diff --git a/.chronus/changes/create_vendor_folder-2025-3-17-15-28-15.md b/.chronus/changes/create_vendor_folder-2025-3-17-15-28-15.md new file mode 100644 index 00000000000..78496ab9faa --- /dev/null +++ b/.chronus/changes/create_vendor_folder-2025-3-17-15-28-15.md @@ -0,0 +1,8 @@ +--- +changeKind: fix +packages: + - "@autorest/python" + - "@azure-tools/typespec-python" +--- + +Move all utils code into a `_utils` folder diff --git a/packages/autorest.python/autorest/multiapi/serializers/__init__.py b/packages/autorest.python/autorest/multiapi/serializers/__init__.py index 9f197a7e2e0..414021ea94c 100644 --- a/packages/autorest.python/autorest/multiapi/serializers/__init__.py +++ b/packages/autorest.python/autorest/multiapi/serializers/__init__.py @@ -133,7 +133,11 @@ def serialize(self, code_model: CodeModel, no_async: Optional[bool]) -> None: lstrip_blocks=True, ) self.write_file( - Path("_serialization.py"), + Path("_utils/__init__.py"), + self.env.get_template("multiapi_utils_init.py.jinja2").render(), + ) + self.write_file( + Path("_utils/serialization.py"), codegen_env.get_template("serialization.py.jinja2").render( code_model=code_model, ), diff --git a/packages/autorest.python/autorest/multiapi/templates/multiapi_operations_mixin.py.jinja2 b/packages/autorest.python/autorest/multiapi/templates/multiapi_operations_mixin.py.jinja2 index 9e0db96c539..203082eb2f7 100644 --- a/packages/autorest.python/autorest/multiapi/templates/multiapi_operations_mixin.py.jinja2 +++ b/packages/autorest.python/autorest/multiapi/templates/multiapi_operations_mixin.py.jinja2 @@ -8,7 +8,7 @@ # Changes may cause incorrect behavior and will be lost if the code is # regenerated. # -------------------------------------------------------------------------- -from {{ ".." if async_mode else "." }}_serialization import Serializer, Deserializer +from {{ ".." if async_mode else "." }}_utils.serialization import Serializer, Deserializer {% if imports %} {{ imports }} {% endif %} diff --git a/packages/autorest.python/autorest/multiapi/templates/multiapi_utils_init.py.jinja2 b/packages/autorest.python/autorest/multiapi/templates/multiapi_utils_init.py.jinja2 new file mode 100644 index 00000000000..59333308532 --- /dev/null +++ b/packages/autorest.python/autorest/multiapi/templates/multiapi_utils_init.py.jinja2 @@ -0,0 +1,10 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is +# regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/autorest.python/package.json b/packages/autorest.python/package.json index f9bc82f4fc4..31c78515da3 100644 --- a/packages/autorest.python/package.json +++ b/packages/autorest.python/package.json @@ -29,7 +29,7 @@ }, "homepage": "https://github.com/Azure/autorest.python/blob/main/README.md", "dependencies": { - "@typespec/http-client-python": "~0.11.0", + "@typespec/http-client-python": "~0.11.1", "@autorest/system-requirements": "~1.0.2", "fs-extra": "~11.2.0", "tsx": "~4.19.1" diff --git a/packages/autorest.python/samples/specification/azure-mgmt-test/test/azure-mgmt-test/azure/mgmt/test/_auto_rest_swagger_bat_array_service.py b/packages/autorest.python/samples/specification/azure-mgmt-test/test/azure-mgmt-test/azure/mgmt/test/_auto_rest_swagger_bat_array_service.py index ed17f5c9a7e..4b73ea89b78 100644 --- a/packages/autorest.python/samples/specification/azure-mgmt-test/test/azure-mgmt-test/azure/mgmt/test/_auto_rest_swagger_bat_array_service.py +++ b/packages/autorest.python/samples/specification/azure-mgmt-test/test/azure-mgmt-test/azure/mgmt/test/_auto_rest_swagger_bat_array_service.py @@ -19,7 +19,7 @@ from . import models as _models from ._configuration import AutoRestSwaggerBATArrayServiceConfiguration -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer from .operations import ArrayOperations if TYPE_CHECKING: diff --git a/packages/autorest.python/samples/specification/azure-mgmt-test/test/azure-mgmt-test/azure/mgmt/test/_utils/__init__.py b/packages/autorest.python/samples/specification/azure-mgmt-test/test/azure-mgmt-test/azure/mgmt/test/_utils/__init__.py new file mode 100644 index 00000000000..0af9b28f660 --- /dev/null +++ b/packages/autorest.python/samples/specification/azure-mgmt-test/test/azure-mgmt-test/azure/mgmt/test/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/autorest.python/samples/specification/azure-mgmt-test/test/azure-mgmt-test/azure/mgmt/test/_serialization.py b/packages/autorest.python/samples/specification/azure-mgmt-test/test/azure-mgmt-test/azure/mgmt/test/_utils/serialization.py similarity index 100% rename from packages/autorest.python/samples/specification/azure-mgmt-test/test/azure-mgmt-test/azure/mgmt/test/_serialization.py rename to packages/autorest.python/samples/specification/azure-mgmt-test/test/azure-mgmt-test/azure/mgmt/test/_utils/serialization.py diff --git a/packages/autorest.python/samples/specification/azure-mgmt-test/test/azure-mgmt-test/azure/mgmt/test/aio/_auto_rest_swagger_bat_array_service.py b/packages/autorest.python/samples/specification/azure-mgmt-test/test/azure-mgmt-test/azure/mgmt/test/aio/_auto_rest_swagger_bat_array_service.py index 318a87ba5d9..a751a969089 100644 --- a/packages/autorest.python/samples/specification/azure-mgmt-test/test/azure-mgmt-test/azure/mgmt/test/aio/_auto_rest_swagger_bat_array_service.py +++ b/packages/autorest.python/samples/specification/azure-mgmt-test/test/azure-mgmt-test/azure/mgmt/test/aio/_auto_rest_swagger_bat_array_service.py @@ -18,7 +18,7 @@ from azure.mgmt.core.tools import get_arm_endpoints from .. import models as _models -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import AutoRestSwaggerBATArrayServiceConfiguration from .operations import ArrayOperations diff --git a/packages/autorest.python/samples/specification/azure-mgmt-test/test/azure-mgmt-test/azure/mgmt/test/aio/operations/_array_operations.py b/packages/autorest.python/samples/specification/azure-mgmt-test/test/azure-mgmt-test/azure/mgmt/test/aio/operations/_array_operations.py index a62c6982274..64e7eae62e6 100644 --- a/packages/autorest.python/samples/specification/azure-mgmt-test/test/azure-mgmt-test/azure/mgmt/test/aio/operations/_array_operations.py +++ b/packages/autorest.python/samples/specification/azure-mgmt-test/test/azure-mgmt-test/azure/mgmt/test/aio/operations/_array_operations.py @@ -27,7 +27,7 @@ from azure.mgmt.core.exceptions import ARMErrorFormat from ... import models as _models -from ..._serialization import Deserializer, Serializer +from ..._utils.serialization import Deserializer, Serializer from ...operations._array_operations import ( build_get_array_empty_request, build_get_array_item_empty_request, diff --git a/packages/autorest.python/samples/specification/azure-mgmt-test/test/azure-mgmt-test/azure/mgmt/test/models/_models_py3.py b/packages/autorest.python/samples/specification/azure-mgmt-test/test/azure-mgmt-test/azure/mgmt/test/models/_models_py3.py index 6aa1810338a..35f5e8e8764 100644 --- a/packages/autorest.python/samples/specification/azure-mgmt-test/test/azure-mgmt-test/azure/mgmt/test/models/_models_py3.py +++ b/packages/autorest.python/samples/specification/azure-mgmt-test/test/azure-mgmt-test/azure/mgmt/test/models/_models_py3.py @@ -8,7 +8,7 @@ from typing import Any, Optional -from .. import _serialization +from .._utils import serialization as _serialization class Error(_serialization.Model): diff --git a/packages/autorest.python/samples/specification/azure-mgmt-test/test/azure-mgmt-test/azure/mgmt/test/operations/_array_operations.py b/packages/autorest.python/samples/specification/azure-mgmt-test/test/azure-mgmt-test/azure/mgmt/test/operations/_array_operations.py index 168e6c44d62..6d688f61dae 100644 --- a/packages/autorest.python/samples/specification/azure-mgmt-test/test/azure-mgmt-test/azure/mgmt/test/operations/_array_operations.py +++ b/packages/autorest.python/samples/specification/azure-mgmt-test/test/azure-mgmt-test/azure/mgmt/test/operations/_array_operations.py @@ -28,7 +28,7 @@ from .. import models as _models from .._configuration import AutoRestSwaggerBATArrayServiceConfiguration -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/autorest.python/samples/specification/azure-test/test/azure-test/azure/test/_generated/_client.py b/packages/autorest.python/samples/specification/azure-test/test/azure-test/azure/test/_generated/_client.py index e1ae0b47664..3e259254259 100644 --- a/packages/autorest.python/samples/specification/azure-test/test/azure-test/azure/test/_generated/_client.py +++ b/packages/autorest.python/samples/specification/azure-test/test/azure-test/azure/test/_generated/_client.py @@ -16,7 +16,7 @@ from . import models as _models from ._configuration import AutoRestSwaggerBATArrayServiceConfiguration -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer from .operations import ArrayOperations diff --git a/packages/autorest.python/samples/specification/azure-test/test/azure-test/azure/test/_generated/_utils/__init__.py b/packages/autorest.python/samples/specification/azure-test/test/azure-test/azure/test/_generated/_utils/__init__.py new file mode 100644 index 00000000000..0af9b28f660 --- /dev/null +++ b/packages/autorest.python/samples/specification/azure-test/test/azure-test/azure/test/_generated/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/autorest.python/samples/specification/azure-test/test/azure-test/azure/test/_generated/_serialization.py b/packages/autorest.python/samples/specification/azure-test/test/azure-test/azure/test/_generated/_utils/serialization.py similarity index 100% rename from packages/autorest.python/samples/specification/azure-test/test/azure-test/azure/test/_generated/_serialization.py rename to packages/autorest.python/samples/specification/azure-test/test/azure-test/azure/test/_generated/_utils/serialization.py diff --git a/packages/autorest.python/samples/specification/azure-test/test/azure-test/azure/test/_generated/aio/_client.py b/packages/autorest.python/samples/specification/azure-test/test/azure-test/azure/test/_generated/aio/_client.py index 7f4a8028f39..804ba362ed1 100644 --- a/packages/autorest.python/samples/specification/azure-test/test/azure-test/azure/test/_generated/aio/_client.py +++ b/packages/autorest.python/samples/specification/azure-test/test/azure-test/azure/test/_generated/aio/_client.py @@ -15,7 +15,7 @@ from azure.core.rest import AsyncHttpResponse, HttpRequest from .. import models as _models -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import AutoRestSwaggerBATArrayServiceConfiguration from .operations import ArrayOperations diff --git a/packages/autorest.python/samples/specification/azure-test/test/azure-test/azure/test/_generated/aio/operations/_operations.py b/packages/autorest.python/samples/specification/azure-test/test/azure-test/azure/test/_generated/aio/operations/_operations.py index f4ed8069ad2..d7e26f197f6 100644 --- a/packages/autorest.python/samples/specification/azure-test/test/azure-test/azure/test/_generated/aio/operations/_operations.py +++ b/packages/autorest.python/samples/specification/azure-test/test/azure-test/azure/test/_generated/aio/operations/_operations.py @@ -26,7 +26,7 @@ from azure.core.utils import case_insensitive_dict from ... import models as _models -from ..._serialization import Deserializer, Serializer +from ..._utils.serialization import Deserializer, Serializer from ...operations._operations import ( build_array_get_array_empty_request, build_array_get_array_item_empty_request, diff --git a/packages/autorest.python/samples/specification/azure-test/test/azure-test/azure/test/_generated/models/_models.py b/packages/autorest.python/samples/specification/azure-test/test/azure-test/azure/test/_generated/models/_models.py index 6aa1810338a..35f5e8e8764 100644 --- a/packages/autorest.python/samples/specification/azure-test/test/azure-test/azure/test/_generated/models/_models.py +++ b/packages/autorest.python/samples/specification/azure-test/test/azure-test/azure/test/_generated/models/_models.py @@ -8,7 +8,7 @@ from typing import Any, Optional -from .. import _serialization +from .._utils import serialization as _serialization class Error(_serialization.Model): diff --git a/packages/autorest.python/samples/specification/azure-test/test/azure-test/azure/test/_generated/operations/_operations.py b/packages/autorest.python/samples/specification/azure-test/test/azure-test/azure/test/_generated/operations/_operations.py index a84ff40a4c8..d1e303793a8 100644 --- a/packages/autorest.python/samples/specification/azure-test/test/azure-test/azure/test/_generated/operations/_operations.py +++ b/packages/autorest.python/samples/specification/azure-test/test/azure-test/azure/test/_generated/operations/_operations.py @@ -27,7 +27,7 @@ from .. import models as _models from .._configuration import AutoRestSwaggerBATArrayServiceConfiguration -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/autorest.python/samples/specification/azure_key_credential/generated/azure/key/credential/sample/_client.py b/packages/autorest.python/samples/specification/azure_key_credential/generated/azure/key/credential/sample/_client.py index b86dd40ec88..7289074a3f7 100644 --- a/packages/autorest.python/samples/specification/azure_key_credential/generated/azure/key/credential/sample/_client.py +++ b/packages/autorest.python/samples/specification/azure_key_credential/generated/azure/key/credential/sample/_client.py @@ -16,7 +16,7 @@ from azure.core.rest import HttpRequest, HttpResponse from ._configuration import AutoRestHeadTestServiceConfiguration -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer from .operations import HttpSuccessOperations diff --git a/packages/autorest.python/samples/specification/azure_key_credential/generated/azure/key/credential/sample/_utils/__init__.py b/packages/autorest.python/samples/specification/azure_key_credential/generated/azure/key/credential/sample/_utils/__init__.py new file mode 100644 index 00000000000..0af9b28f660 --- /dev/null +++ b/packages/autorest.python/samples/specification/azure_key_credential/generated/azure/key/credential/sample/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/autorest.python/samples/specification/azure_key_credential/generated/azure/key/credential/sample/_serialization.py b/packages/autorest.python/samples/specification/azure_key_credential/generated/azure/key/credential/sample/_utils/serialization.py similarity index 100% rename from packages/autorest.python/samples/specification/azure_key_credential/generated/azure/key/credential/sample/_serialization.py rename to packages/autorest.python/samples/specification/azure_key_credential/generated/azure/key/credential/sample/_utils/serialization.py diff --git a/packages/autorest.python/samples/specification/azure_key_credential/generated/azure/key/credential/sample/aio/_client.py b/packages/autorest.python/samples/specification/azure_key_credential/generated/azure/key/credential/sample/aio/_client.py index eeb8a4476b9..4c393c268bf 100644 --- a/packages/autorest.python/samples/specification/azure_key_credential/generated/azure/key/credential/sample/aio/_client.py +++ b/packages/autorest.python/samples/specification/azure_key_credential/generated/azure/key/credential/sample/aio/_client.py @@ -15,7 +15,7 @@ from azure.core.pipeline import policies from azure.core.rest import AsyncHttpResponse, HttpRequest -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import AutoRestHeadTestServiceConfiguration from .operations import HttpSuccessOperations diff --git a/packages/autorest.python/samples/specification/azure_key_credential/generated/azure/key/credential/sample/aio/operations/_operations.py b/packages/autorest.python/samples/specification/azure_key_credential/generated/azure/key/credential/sample/aio/operations/_operations.py index 74e76083804..374598e66ca 100644 --- a/packages/autorest.python/samples/specification/azure_key_credential/generated/azure/key/credential/sample/aio/operations/_operations.py +++ b/packages/autorest.python/samples/specification/azure_key_credential/generated/azure/key/credential/sample/aio/operations/_operations.py @@ -21,7 +21,7 @@ from azure.core.rest import AsyncHttpResponse, HttpRequest from azure.core.tracing.decorator_async import distributed_trace_async -from ..._serialization import Deserializer, Serializer +from ..._utils.serialization import Deserializer, Serializer from ...operations._operations import ( build_http_success_head200_request, build_http_success_head204_request, diff --git a/packages/autorest.python/samples/specification/azure_key_credential/generated/azure/key/credential/sample/operations/_operations.py b/packages/autorest.python/samples/specification/azure_key_credential/generated/azure/key/credential/sample/operations/_operations.py index ddb1d520c0f..85d63e10a6f 100644 --- a/packages/autorest.python/samples/specification/azure_key_credential/generated/azure/key/credential/sample/operations/_operations.py +++ b/packages/autorest.python/samples/specification/azure_key_credential/generated/azure/key/credential/sample/operations/_operations.py @@ -22,7 +22,7 @@ from azure.core.tracing.decorator import distributed_trace from .._configuration import AutoRestHeadTestServiceConfiguration -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/autorest.python/samples/specification/basic/generated/azure/basic/sample/_client.py b/packages/autorest.python/samples/specification/basic/generated/azure/basic/sample/_client.py index 8901722bf0a..e3a605b5b77 100644 --- a/packages/autorest.python/samples/specification/basic/generated/azure/basic/sample/_client.py +++ b/packages/autorest.python/samples/specification/basic/generated/azure/basic/sample/_client.py @@ -15,7 +15,7 @@ from azure.core.rest import HttpRequest, HttpResponse from ._configuration import AutoRestHeadTestServiceConfiguration -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer from .operations import HttpSuccessOperations diff --git a/packages/autorest.python/samples/specification/basic/generated/azure/basic/sample/_utils/__init__.py b/packages/autorest.python/samples/specification/basic/generated/azure/basic/sample/_utils/__init__.py new file mode 100644 index 00000000000..0af9b28f660 --- /dev/null +++ b/packages/autorest.python/samples/specification/basic/generated/azure/basic/sample/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/autorest.python/samples/specification/basic/generated/azure/basic/sample/_serialization.py b/packages/autorest.python/samples/specification/basic/generated/azure/basic/sample/_utils/serialization.py similarity index 100% rename from packages/autorest.python/samples/specification/basic/generated/azure/basic/sample/_serialization.py rename to packages/autorest.python/samples/specification/basic/generated/azure/basic/sample/_utils/serialization.py diff --git a/packages/autorest.python/samples/specification/basic/generated/azure/basic/sample/aio/_client.py b/packages/autorest.python/samples/specification/basic/generated/azure/basic/sample/aio/_client.py index 8a4d37d9a81..35b5e4a9c91 100644 --- a/packages/autorest.python/samples/specification/basic/generated/azure/basic/sample/aio/_client.py +++ b/packages/autorest.python/samples/specification/basic/generated/azure/basic/sample/aio/_client.py @@ -14,7 +14,7 @@ from azure.core.pipeline import policies from azure.core.rest import AsyncHttpResponse, HttpRequest -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import AutoRestHeadTestServiceConfiguration from .operations import HttpSuccessOperations diff --git a/packages/autorest.python/samples/specification/basic/generated/azure/basic/sample/aio/operations/_operations.py b/packages/autorest.python/samples/specification/basic/generated/azure/basic/sample/aio/operations/_operations.py index c32e4c29589..86349d39ef8 100644 --- a/packages/autorest.python/samples/specification/basic/generated/azure/basic/sample/aio/operations/_operations.py +++ b/packages/autorest.python/samples/specification/basic/generated/azure/basic/sample/aio/operations/_operations.py @@ -21,7 +21,7 @@ from azure.core.rest import AsyncHttpResponse, HttpRequest from azure.core.tracing.decorator_async import distributed_trace_async -from ..._serialization import Deserializer, Serializer +from ..._utils.serialization import Deserializer, Serializer from ...operations._operations import ( build_http_success_head200_request, build_http_success_head204_request, diff --git a/packages/autorest.python/samples/specification/basic/generated/azure/basic/sample/operations/_operations.py b/packages/autorest.python/samples/specification/basic/generated/azure/basic/sample/operations/_operations.py index 58a269bb90e..6a91397376f 100644 --- a/packages/autorest.python/samples/specification/basic/generated/azure/basic/sample/operations/_operations.py +++ b/packages/autorest.python/samples/specification/basic/generated/azure/basic/sample/operations/_operations.py @@ -22,7 +22,7 @@ from azure.core.tracing.decorator import distributed_trace from .._configuration import AutoRestHeadTestServiceConfiguration -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/autorest.python/samples/specification/directives/generated/azure/directives/sample/_client.py b/packages/autorest.python/samples/specification/directives/generated/azure/directives/sample/_client.py index 0d8ab0f61b6..e54b610ede2 100644 --- a/packages/autorest.python/samples/specification/directives/generated/azure/directives/sample/_client.py +++ b/packages/autorest.python/samples/specification/directives/generated/azure/directives/sample/_client.py @@ -16,7 +16,7 @@ from ._configuration import PollingPagingExampleConfiguration from ._operations import PollingPagingExampleOperationsMixin -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer class PollingPagingExample(PollingPagingExampleOperationsMixin): # pylint: disable=client-accepts-api-version-keyword diff --git a/packages/autorest.python/samples/specification/directives/generated/azure/directives/sample/_operations/_operations.py b/packages/autorest.python/samples/specification/directives/generated/azure/directives/sample/_operations/_operations.py index 67c3cacd0f6..c72dd895a86 100644 --- a/packages/autorest.python/samples/specification/directives/generated/azure/directives/sample/_operations/_operations.py +++ b/packages/autorest.python/samples/specification/directives/generated/azure/directives/sample/_operations/_operations.py @@ -11,6 +11,7 @@ from my.library import CustomDefaultPollingMethod, CustomPager, CustomPoller +from azure.core import PipelineClient from azure.core.exceptions import ( ClientAuthenticationError, HttpResponseError, @@ -27,8 +28,9 @@ from azure.core.tracing.decorator import distributed_trace from azure.core.utils import case_insensitive_dict -from .._serialization import Serializer -from .._vendor import PollingPagingExampleMixinABC +from .._configuration import PollingPagingExampleConfiguration +from .._utils.serialization import Serializer +from .._utils.utils import ClientMixinABC JSON = MutableMapping[str, Any] T = TypeVar("T") @@ -69,7 +71,7 @@ def build_polling_paging_example_basic_paging_request(**kwargs: Any) -> HttpRequ return HttpRequest(method="GET", url=_url, headers=_headers, **kwargs) -class PollingPagingExampleOperationsMixin(PollingPagingExampleMixinABC): +class PollingPagingExampleOperationsMixin(ClientMixinABC[PipelineClient, PollingPagingExampleConfiguration]): def _basic_polling_initial( self, product: Optional[Union[JSON, IO[bytes]]] = None, **kwargs: Any diff --git a/packages/autorest.python/samples/specification/directives/generated/azure/directives/sample/_utils/__init__.py b/packages/autorest.python/samples/specification/directives/generated/azure/directives/sample/_utils/__init__.py new file mode 100644 index 00000000000..0af9b28f660 --- /dev/null +++ b/packages/autorest.python/samples/specification/directives/generated/azure/directives/sample/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/autorest.python/samples/specification/directives/generated/azure/directives/sample/_serialization.py b/packages/autorest.python/samples/specification/directives/generated/azure/directives/sample/_utils/serialization.py similarity index 100% rename from packages/autorest.python/samples/specification/directives/generated/azure/directives/sample/_serialization.py rename to packages/autorest.python/samples/specification/directives/generated/azure/directives/sample/_utils/serialization.py diff --git a/packages/autorest.python/samples/specification/directives/generated/azure/directives/sample/_utils/utils.py b/packages/autorest.python/samples/specification/directives/generated/azure/directives/sample/_utils/utils.py new file mode 100644 index 00000000000..39b612f39a9 --- /dev/null +++ b/packages/autorest.python/samples/specification/directives/generated/azure/directives/sample/_utils/utils.py @@ -0,0 +1,25 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from abc import ABC +from typing import Generic, TYPE_CHECKING, TypeVar + +if TYPE_CHECKING: + from .serialization import Deserializer, Serializer + + +TClient = TypeVar("TClient") +TConfig = TypeVar("TConfig") + + +class ClientMixinABC(ABC, Generic[TClient, TConfig]): + """DO NOT use this class. It is for internal typing use only.""" + + _client: TClient + _config: TConfig + _serialize: "Serializer" + _deserialize: "Deserializer" diff --git a/packages/autorest.python/samples/specification/directives/generated/azure/directives/sample/_vendor.py b/packages/autorest.python/samples/specification/directives/generated/azure/directives/sample/_vendor.py deleted file mode 100644 index 2df1e2f0178..00000000000 --- a/packages/autorest.python/samples/specification/directives/generated/azure/directives/sample/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) AutoRest Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import PollingPagingExampleConfiguration - -if TYPE_CHECKING: - from azure.core import PipelineClient - - from ._serialization import Deserializer, Serializer - - -class PollingPagingExampleMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "PipelineClient" - _config: PollingPagingExampleConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/autorest.python/samples/specification/directives/generated/azure/directives/sample/aio/_client.py b/packages/autorest.python/samples/specification/directives/generated/azure/directives/sample/aio/_client.py index e90f7bc8160..629ef93de31 100644 --- a/packages/autorest.python/samples/specification/directives/generated/azure/directives/sample/aio/_client.py +++ b/packages/autorest.python/samples/specification/directives/generated/azure/directives/sample/aio/_client.py @@ -14,7 +14,7 @@ from azure.core.pipeline import policies from azure.core.rest import AsyncHttpResponse, HttpRequest -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import PollingPagingExampleConfiguration from ._operations import PollingPagingExampleOperationsMixin diff --git a/packages/autorest.python/samples/specification/directives/generated/azure/directives/sample/aio/_operations/_operations.py b/packages/autorest.python/samples/specification/directives/generated/azure/directives/sample/aio/_operations/_operations.py index 1442437cd2f..e0c50ce22e5 100644 --- a/packages/autorest.python/samples/specification/directives/generated/azure/directives/sample/aio/_operations/_operations.py +++ b/packages/autorest.python/samples/specification/directives/generated/azure/directives/sample/aio/_operations/_operations.py @@ -12,6 +12,7 @@ from my.library.aio import AsyncCustomDefaultPollingMethod, AsyncCustomPager, AsyncCustomPoller +from azure.core import AsyncPipelineClient from azure.core.async_paging import AsyncList from azure.core.exceptions import ( ClientAuthenticationError, @@ -34,14 +35,15 @@ build_polling_paging_example_basic_paging_request, build_polling_paging_example_basic_polling_request, ) -from .._vendor import PollingPagingExampleMixinABC +from ..._utils.utils import ClientMixinABC +from .._configuration import PollingPagingExampleConfiguration JSON = MutableMapping[str, Any] T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, AsyncHttpResponse], T, Dict[str, Any]], Any]] -class PollingPagingExampleOperationsMixin(PollingPagingExampleMixinABC): +class PollingPagingExampleOperationsMixin(ClientMixinABC[AsyncPipelineClient, PollingPagingExampleConfiguration]): async def _basic_polling_initial( self, product: Optional[Union[JSON, IO[bytes]]] = None, **kwargs: Any diff --git a/packages/autorest.python/samples/specification/directives/generated/azure/directives/sample/aio/_vendor.py b/packages/autorest.python/samples/specification/directives/generated/azure/directives/sample/aio/_vendor.py deleted file mode 100644 index dbf332bdeab..00000000000 --- a/packages/autorest.python/samples/specification/directives/generated/azure/directives/sample/aio/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) AutoRest Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import PollingPagingExampleConfiguration - -if TYPE_CHECKING: - from azure.core import AsyncPipelineClient - - from .._serialization import Deserializer, Serializer - - -class PollingPagingExampleMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "AsyncPipelineClient" - _config: PollingPagingExampleConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/autorest.python/samples/specification/management/generated/azure/mgmt/sample/_auto_rest_head_test_service.py b/packages/autorest.python/samples/specification/management/generated/azure/mgmt/sample/_auto_rest_head_test_service.py index 244db3a7381..413af58592a 100644 --- a/packages/autorest.python/samples/specification/management/generated/azure/mgmt/sample/_auto_rest_head_test_service.py +++ b/packages/autorest.python/samples/specification/management/generated/azure/mgmt/sample/_auto_rest_head_test_service.py @@ -18,7 +18,7 @@ from azure.mgmt.core.tools import get_arm_endpoints from ._configuration import AutoRestHeadTestServiceConfiguration -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer from .operations import HttpSuccessOperations if TYPE_CHECKING: diff --git a/packages/autorest.python/samples/specification/management/generated/azure/mgmt/sample/_utils/__init__.py b/packages/autorest.python/samples/specification/management/generated/azure/mgmt/sample/_utils/__init__.py new file mode 100644 index 00000000000..0af9b28f660 --- /dev/null +++ b/packages/autorest.python/samples/specification/management/generated/azure/mgmt/sample/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/autorest.python/samples/specification/management/generated/azure/mgmt/sample/_serialization.py b/packages/autorest.python/samples/specification/management/generated/azure/mgmt/sample/_utils/serialization.py similarity index 100% rename from packages/autorest.python/samples/specification/management/generated/azure/mgmt/sample/_serialization.py rename to packages/autorest.python/samples/specification/management/generated/azure/mgmt/sample/_utils/serialization.py diff --git a/packages/autorest.python/samples/specification/management/generated/azure/mgmt/sample/aio/_auto_rest_head_test_service.py b/packages/autorest.python/samples/specification/management/generated/azure/mgmt/sample/aio/_auto_rest_head_test_service.py index 305692103ec..a95c0062e08 100644 --- a/packages/autorest.python/samples/specification/management/generated/azure/mgmt/sample/aio/_auto_rest_head_test_service.py +++ b/packages/autorest.python/samples/specification/management/generated/azure/mgmt/sample/aio/_auto_rest_head_test_service.py @@ -17,7 +17,7 @@ from azure.mgmt.core.policies import AsyncARMAutoResourceProviderRegistrationPolicy from azure.mgmt.core.tools import get_arm_endpoints -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import AutoRestHeadTestServiceConfiguration from .operations import HttpSuccessOperations diff --git a/packages/autorest.python/samples/specification/management/generated/azure/mgmt/sample/aio/operations/_http_success_operations.py b/packages/autorest.python/samples/specification/management/generated/azure/mgmt/sample/aio/operations/_http_success_operations.py index bd4ca8684d0..05073e8186b 100644 --- a/packages/autorest.python/samples/specification/management/generated/azure/mgmt/sample/aio/operations/_http_success_operations.py +++ b/packages/autorest.python/samples/specification/management/generated/azure/mgmt/sample/aio/operations/_http_success_operations.py @@ -22,7 +22,7 @@ from azure.core.tracing.decorator_async import distributed_trace_async from azure.mgmt.core.exceptions import ARMErrorFormat -from ..._serialization import Deserializer, Serializer +from ..._utils.serialization import Deserializer, Serializer from ...operations._http_success_operations import build_head200_request, build_head204_request, build_head404_request from .._configuration import AutoRestHeadTestServiceConfiguration diff --git a/packages/autorest.python/samples/specification/management/generated/azure/mgmt/sample/operations/_http_success_operations.py b/packages/autorest.python/samples/specification/management/generated/azure/mgmt/sample/operations/_http_success_operations.py index 9621221895f..1798f4595f7 100644 --- a/packages/autorest.python/samples/specification/management/generated/azure/mgmt/sample/operations/_http_success_operations.py +++ b/packages/autorest.python/samples/specification/management/generated/azure/mgmt/sample/operations/_http_success_operations.py @@ -23,7 +23,7 @@ from azure.mgmt.core.exceptions import ARMErrorFormat from .._configuration import AutoRestHeadTestServiceConfiguration -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/autorest.python/samples/specification/multiapi/generated/azure/multiapi/sample/_multiapi_service_client.py b/packages/autorest.python/samples/specification/multiapi/generated/azure/multiapi/sample/_multiapi_service_client.py index 30d1c238948..adaaef946eb 100644 --- a/packages/autorest.python/samples/specification/multiapi/generated/azure/multiapi/sample/_multiapi_service_client.py +++ b/packages/autorest.python/samples/specification/multiapi/generated/azure/multiapi/sample/_multiapi_service_client.py @@ -22,7 +22,7 @@ from ._configuration import MultiapiServiceClientConfiguration from ._operations_mixin import MultiapiServiceClientOperationsMixin -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer if TYPE_CHECKING: # pylint: disable=unused-import,ungrouped-imports diff --git a/packages/autorest.python/samples/specification/multiapi/generated/azure/multiapi/sample/_operations_mixin.py b/packages/autorest.python/samples/specification/multiapi/generated/azure/multiapi/sample/_operations_mixin.py index d55b41d3a3b..07f62adea1d 100644 --- a/packages/autorest.python/samples/specification/multiapi/generated/azure/multiapi/sample/_operations_mixin.py +++ b/packages/autorest.python/samples/specification/multiapi/generated/azure/multiapi/sample/_operations_mixin.py @@ -8,7 +8,7 @@ # Changes may cause incorrect behavior and will be lost if the code is # regenerated. # -------------------------------------------------------------------------- -from ._serialization import Serializer, Deserializer +from ._utils.serialization import Serializer, Deserializer from io import IOBase from typing import Any, IO, Iterable, Iterator, Optional, Union diff --git a/packages/autorest.python/samples/specification/multiapi/generated/azure/multiapi/sample/_utils/__init__.py b/packages/autorest.python/samples/specification/multiapi/generated/azure/multiapi/sample/_utils/__init__.py new file mode 100644 index 00000000000..59333308532 --- /dev/null +++ b/packages/autorest.python/samples/specification/multiapi/generated/azure/multiapi/sample/_utils/__init__.py @@ -0,0 +1,10 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is +# regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiSecurity/multiapisecurity/_serialization.py b/packages/autorest.python/samples/specification/multiapi/generated/azure/multiapi/sample/_utils/serialization.py similarity index 100% rename from packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiSecurity/multiapisecurity/_serialization.py rename to packages/autorest.python/samples/specification/multiapi/generated/azure/multiapi/sample/_utils/serialization.py diff --git a/packages/autorest.python/samples/specification/multiapi/generated/azure/multiapi/sample/aio/_multiapi_service_client.py b/packages/autorest.python/samples/specification/multiapi/generated/azure/multiapi/sample/aio/_multiapi_service_client.py index 4a310c442e8..c2e13770dc5 100644 --- a/packages/autorest.python/samples/specification/multiapi/generated/azure/multiapi/sample/aio/_multiapi_service_client.py +++ b/packages/autorest.python/samples/specification/multiapi/generated/azure/multiapi/sample/aio/_multiapi_service_client.py @@ -20,7 +20,7 @@ from azure.profiles import KnownProfiles, ProfileDefinition from azure.profiles.multiapiclient import MultiApiClientMixin -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import MultiapiServiceClientConfiguration from ._operations_mixin import MultiapiServiceClientOperationsMixin diff --git a/packages/autorest.python/samples/specification/multiapi/generated/azure/multiapi/sample/aio/_operations_mixin.py b/packages/autorest.python/samples/specification/multiapi/generated/azure/multiapi/sample/aio/_operations_mixin.py index 6c75275be96..9423ef48cad 100644 --- a/packages/autorest.python/samples/specification/multiapi/generated/azure/multiapi/sample/aio/_operations_mixin.py +++ b/packages/autorest.python/samples/specification/multiapi/generated/azure/multiapi/sample/aio/_operations_mixin.py @@ -8,7 +8,7 @@ # Changes may cause incorrect behavior and will be lost if the code is # regenerated. # -------------------------------------------------------------------------- -from .._serialization import Serializer, Deserializer +from .._utils.serialization import Serializer, Deserializer from io import IOBase from typing import Any, AsyncIterable, AsyncIterator, IO, Optional, Union diff --git a/packages/autorest.python/samples/specification/multiapi/generated/azure/multiapi/sample/v1/_metadata.json b/packages/autorest.python/samples/specification/multiapi/generated/azure/multiapi/sample/v1/_metadata.json index 34e0dbdf81f..0d02a936b15 100644 --- a/packages/autorest.python/samples/specification/multiapi/generated/azure/multiapi/sample/v1/_metadata.json +++ b/packages/autorest.python/samples/specification/multiapi/generated/azure/multiapi/sample/v1/_metadata.json @@ -10,8 +10,8 @@ "azure_arm": true, "has_public_lro_operations": true, "client_side_validation": false, - "sync_imports": "{\"conditional\": {\"stdlib\": {\"typing\": [\"Any\", \"Optional\"]}}, \"regular\": {\"sdkcore\": {\"azure.mgmt.core\": [\"ARMPipelineClient\"], \"azure.core.pipeline\": [\"policies\"], \"azure.mgmt.core.policies\": [\"ARMAutoResourceProviderRegistrationPolicy\"], \"azure.core.settings\": [\"settings\"], \"azure.mgmt.core.tools\": [\"get_arm_endpoints\"], \"azure.profiles\": [\"KnownProfiles\", \"ProfileDefinition\"], \"azure.profiles.multiapiclient\": [\"MultiApiClientMixin\"]}, \"stdlib\": {\"typing\": [\"Optional\", \"cast\"], \"typing_extensions\": [\"Self\"]}, \"local\": {\"._configuration\": [\"MultiapiServiceClientConfiguration\"], \".._serialization\": [\"Deserializer\", \"Serializer\"], \"._operations_mixin\": [\"MultiapiServiceClientOperationsMixin\"]}}, \"typing\": {\"sdkcore\": {\"azure.core.credentials\": [\"TokenCredential\"]}}}", - "async_imports": "{\"conditional\": {\"stdlib\": {\"typing\": [\"Any\", \"Optional\"]}}, \"regular\": {\"sdkcore\": {\"azure.mgmt.core\": [\"AsyncARMPipelineClient\"], \"azure.core.pipeline\": [\"policies\"], \"azure.mgmt.core.policies\": [\"AsyncARMAutoResourceProviderRegistrationPolicy\"], \"azure.core.settings\": [\"settings\"], \"azure.mgmt.core.tools\": [\"get_arm_endpoints\"], \"azure.profiles\": [\"KnownProfiles\", \"ProfileDefinition\"], \"azure.profiles.multiapiclient\": [\"MultiApiClientMixin\"]}, \"stdlib\": {\"typing\": [\"Optional\", \"cast\"], \"typing_extensions\": [\"Self\"]}, \"local\": {\"._configuration\": [\"MultiapiServiceClientConfiguration\"], \"..._serialization\": [\"Deserializer\", \"Serializer\"], \"._operations_mixin\": [\"MultiapiServiceClientOperationsMixin\"]}}, \"typing\": {\"sdkcore\": {\"azure.core.credentials_async\": [\"AsyncTokenCredential\"]}}}" + "sync_imports": "{\"conditional\": {\"stdlib\": {\"typing\": [\"Any\", \"Optional\"]}}, \"regular\": {\"sdkcore\": {\"azure.mgmt.core\": [\"ARMPipelineClient\"], \"azure.core.pipeline\": [\"policies\"], \"azure.mgmt.core.policies\": [\"ARMAutoResourceProviderRegistrationPolicy\"], \"azure.core.settings\": [\"settings\"], \"azure.mgmt.core.tools\": [\"get_arm_endpoints\"], \"azure.profiles\": [\"KnownProfiles\", \"ProfileDefinition\"], \"azure.profiles.multiapiclient\": [\"MultiApiClientMixin\"]}, \"stdlib\": {\"typing\": [\"Optional\", \"cast\"], \"typing_extensions\": [\"Self\"]}, \"local\": {\"._configuration\": [\"MultiapiServiceClientConfiguration\"], \"._utils.serialization\": [\"Deserializer\", \"Serializer\"], \"._operations_mixin\": [\"MultiapiServiceClientOperationsMixin\"]}}, \"typing\": {\"sdkcore\": {\"azure.core.credentials\": [\"TokenCredential\"]}}}", + "async_imports": "{\"conditional\": {\"stdlib\": {\"typing\": [\"Any\", \"Optional\"]}}, \"regular\": {\"sdkcore\": {\"azure.mgmt.core\": [\"AsyncARMPipelineClient\"], \"azure.core.pipeline\": [\"policies\"], \"azure.mgmt.core.policies\": [\"AsyncARMAutoResourceProviderRegistrationPolicy\"], \"azure.core.settings\": [\"settings\"], \"azure.mgmt.core.tools\": [\"get_arm_endpoints\"], \"azure.profiles\": [\"KnownProfiles\", \"ProfileDefinition\"], \"azure.profiles.multiapiclient\": [\"MultiApiClientMixin\"]}, \"stdlib\": {\"typing\": [\"Optional\", \"cast\"], \"typing_extensions\": [\"Self\"]}, \"local\": {\"._configuration\": [\"MultiapiServiceClientConfiguration\"], \".._utils.serialization\": [\"Deserializer\", \"Serializer\"], \"._operations_mixin\": [\"MultiapiServiceClientOperationsMixin\"]}}, \"typing\": {\"sdkcore\": {\"azure.core.credentials_async\": [\"AsyncTokenCredential\"]}}}" }, "global_parameters": { "sync": { diff --git a/packages/autorest.python/samples/specification/multiapi/generated/azure/multiapi/sample/v1/_multiapi_service_client.py b/packages/autorest.python/samples/specification/multiapi/generated/azure/multiapi/sample/v1/_multiapi_service_client.py index 2ad9004da3b..4f4f2bb2cd6 100644 --- a/packages/autorest.python/samples/specification/multiapi/generated/azure/multiapi/sample/v1/_multiapi_service_client.py +++ b/packages/autorest.python/samples/specification/multiapi/generated/azure/multiapi/sample/v1/_multiapi_service_client.py @@ -18,8 +18,8 @@ from azure.mgmt.core.tools import get_arm_endpoints from . import models as _models -from .._serialization import Deserializer, Serializer from ._configuration import MultiapiServiceClientConfiguration +from ._utils.serialization import Deserializer, Serializer from .operations import MultiapiServiceClientOperationsMixin, OperationGroupOneOperations if TYPE_CHECKING: diff --git a/packages/autorest.python/samples/specification/multiapi/generated/azure/multiapi/sample/v1/_utils/__init__.py b/packages/autorest.python/samples/specification/multiapi/generated/azure/multiapi/sample/v1/_utils/__init__.py new file mode 100644 index 00000000000..0af9b28f660 --- /dev/null +++ b/packages/autorest.python/samples/specification/multiapi/generated/azure/multiapi/sample/v1/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/AzureBodyDuration/bodyduration/_serialization.py b/packages/autorest.python/samples/specification/multiapi/generated/azure/multiapi/sample/v1/_utils/serialization.py similarity index 100% rename from packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/AzureBodyDuration/bodyduration/_serialization.py rename to packages/autorest.python/samples/specification/multiapi/generated/azure/multiapi/sample/v1/_utils/serialization.py diff --git a/packages/autorest.python/samples/specification/multiapi/generated/azure/multiapi/sample/v1/_utils/utils.py b/packages/autorest.python/samples/specification/multiapi/generated/azure/multiapi/sample/v1/_utils/utils.py new file mode 100644 index 00000000000..39b612f39a9 --- /dev/null +++ b/packages/autorest.python/samples/specification/multiapi/generated/azure/multiapi/sample/v1/_utils/utils.py @@ -0,0 +1,25 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from abc import ABC +from typing import Generic, TYPE_CHECKING, TypeVar + +if TYPE_CHECKING: + from .serialization import Deserializer, Serializer + + +TClient = TypeVar("TClient") +TConfig = TypeVar("TConfig") + + +class ClientMixinABC(ABC, Generic[TClient, TConfig]): + """DO NOT use this class. It is for internal typing use only.""" + + _client: TClient + _config: TConfig + _serialize: "Serializer" + _deserialize: "Deserializer" diff --git a/packages/autorest.python/samples/specification/multiapi/generated/azure/multiapi/sample/v1/_vendor.py b/packages/autorest.python/samples/specification/multiapi/generated/azure/multiapi/sample/v1/_vendor.py deleted file mode 100644 index 70517e0b7af..00000000000 --- a/packages/autorest.python/samples/specification/multiapi/generated/azure/multiapi/sample/v1/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) AutoRest Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import MultiapiServiceClientConfiguration - -if TYPE_CHECKING: - from azure.core import PipelineClient - - from .._serialization import Deserializer, Serializer - - -class MultiapiServiceClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "PipelineClient" - _config: MultiapiServiceClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/autorest.python/samples/specification/multiapi/generated/azure/multiapi/sample/v1/aio/_multiapi_service_client.py b/packages/autorest.python/samples/specification/multiapi/generated/azure/multiapi/sample/v1/aio/_multiapi_service_client.py index fccf81fcb14..328bdfadc8e 100644 --- a/packages/autorest.python/samples/specification/multiapi/generated/azure/multiapi/sample/v1/aio/_multiapi_service_client.py +++ b/packages/autorest.python/samples/specification/multiapi/generated/azure/multiapi/sample/v1/aio/_multiapi_service_client.py @@ -18,7 +18,7 @@ from azure.mgmt.core.tools import get_arm_endpoints from .. import models as _models -from ..._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import MultiapiServiceClientConfiguration from .operations import MultiapiServiceClientOperationsMixin, OperationGroupOneOperations diff --git a/packages/autorest.python/samples/specification/multiapi/generated/azure/multiapi/sample/v1/aio/_vendor.py b/packages/autorest.python/samples/specification/multiapi/generated/azure/multiapi/sample/v1/aio/_vendor.py deleted file mode 100644 index 9c6fd05bb21..00000000000 --- a/packages/autorest.python/samples/specification/multiapi/generated/azure/multiapi/sample/v1/aio/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) AutoRest Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import MultiapiServiceClientConfiguration - -if TYPE_CHECKING: - from azure.core import AsyncPipelineClient - - from ..._serialization import Deserializer, Serializer - - -class MultiapiServiceClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "AsyncPipelineClient" - _config: MultiapiServiceClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/autorest.python/samples/specification/multiapi/generated/azure/multiapi/sample/v1/aio/operations/_multiapi_service_client_operations.py b/packages/autorest.python/samples/specification/multiapi/generated/azure/multiapi/sample/v1/aio/operations/_multiapi_service_client_operations.py index 3089e804ec3..c113644549c 100644 --- a/packages/autorest.python/samples/specification/multiapi/generated/azure/multiapi/sample/v1/aio/operations/_multiapi_service_client_operations.py +++ b/packages/autorest.python/samples/specification/multiapi/generated/azure/multiapi/sample/v1/aio/operations/_multiapi_service_client_operations.py @@ -11,6 +11,7 @@ from typing import Any, AsyncIterable, AsyncIterator, Callable, Dict, IO, Optional, TypeVar, Union, cast, overload import urllib.parse +from azure.core import AsyncPipelineClient from azure.core.async_paging import AsyncItemPaged, AsyncList from azure.core.exceptions import ( ClientAuthenticationError, @@ -32,19 +33,20 @@ from azure.mgmt.core.polling.async_arm_polling import AsyncARMPolling from ... import models as _models +from ..._utils.utils import ClientMixinABC from ...operations._multiapi_service_client_operations import ( build_test_different_calls_request, build_test_lro_and_paging_request, build_test_lro_request, build_test_one_request, ) -from .._vendor import MultiapiServiceClientMixinABC +from .._configuration import MultiapiServiceClientConfiguration T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, AsyncHttpResponse], T, Dict[str, Any]], Any]] -class MultiapiServiceClientOperationsMixin(MultiapiServiceClientMixinABC): +class MultiapiServiceClientOperationsMixin(ClientMixinABC[AsyncPipelineClient, MultiapiServiceClientConfiguration]): def _api_version(self, op_name: str) -> str: # pylint: disable=unused-argument try: return self._config.api_version diff --git a/packages/autorest.python/samples/specification/multiapi/generated/azure/multiapi/sample/v1/aio/operations/_operation_group_one_operations.py b/packages/autorest.python/samples/specification/multiapi/generated/azure/multiapi/sample/v1/aio/operations/_operation_group_one_operations.py index c65cbb16ed9..d38c6342121 100644 --- a/packages/autorest.python/samples/specification/multiapi/generated/azure/multiapi/sample/v1/aio/operations/_operation_group_one_operations.py +++ b/packages/autorest.python/samples/specification/multiapi/generated/azure/multiapi/sample/v1/aio/operations/_operation_group_one_operations.py @@ -24,7 +24,7 @@ from azure.mgmt.core.exceptions import ARMErrorFormat from ... import models as _models -from ...._serialization import Deserializer, Serializer +from ..._utils.serialization import Deserializer, Serializer from ...operations._operation_group_one_operations import build_test_two_request from .._configuration import MultiapiServiceClientConfiguration diff --git a/packages/autorest.python/samples/specification/multiapi/generated/azure/multiapi/sample/v1/models/_models_py3.py b/packages/autorest.python/samples/specification/multiapi/generated/azure/multiapi/sample/v1/models/_models_py3.py index 3748e0032bc..b5877d520e4 100644 --- a/packages/autorest.python/samples/specification/multiapi/generated/azure/multiapi/sample/v1/models/_models_py3.py +++ b/packages/autorest.python/samples/specification/multiapi/generated/azure/multiapi/sample/v1/models/_models_py3.py @@ -8,7 +8,7 @@ from typing import Any, List, Optional, TYPE_CHECKING -from ... import _serialization +from .._utils import serialization as _serialization if TYPE_CHECKING: from .. import models as _models diff --git a/packages/autorest.python/samples/specification/multiapi/generated/azure/multiapi/sample/v1/operations/_multiapi_service_client_operations.py b/packages/autorest.python/samples/specification/multiapi/generated/azure/multiapi/sample/v1/operations/_multiapi_service_client_operations.py index 4dce5c0c8e6..e80e0ec6a22 100644 --- a/packages/autorest.python/samples/specification/multiapi/generated/azure/multiapi/sample/v1/operations/_multiapi_service_client_operations.py +++ b/packages/autorest.python/samples/specification/multiapi/generated/azure/multiapi/sample/v1/operations/_multiapi_service_client_operations.py @@ -10,6 +10,7 @@ from typing import Any, Callable, Dict, IO, Iterable, Iterator, Optional, TypeVar, Union, cast, overload import urllib.parse +from azure.core import PipelineClient from azure.core.exceptions import ( ClientAuthenticationError, HttpResponseError, @@ -30,8 +31,9 @@ from azure.mgmt.core.polling.arm_polling import ARMPolling from .. import models as _models -from ..._serialization import Serializer -from .._vendor import MultiapiServiceClientMixinABC +from .._configuration import MultiapiServiceClientConfiguration +from .._utils.serialization import Serializer +from .._utils.utils import ClientMixinABC T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] @@ -121,7 +123,7 @@ def build_test_different_calls_request(*, greeting_in_english: str, **kwargs: An return HttpRequest(method="GET", url=_url, params=_params, headers=_headers, **kwargs) -class MultiapiServiceClientOperationsMixin(MultiapiServiceClientMixinABC): +class MultiapiServiceClientOperationsMixin(ClientMixinABC[PipelineClient, MultiapiServiceClientConfiguration]): def _api_version(self, op_name: str) -> str: # pylint: disable=unused-argument try: return self._config.api_version diff --git a/packages/autorest.python/samples/specification/multiapi/generated/azure/multiapi/sample/v1/operations/_operation_group_one_operations.py b/packages/autorest.python/samples/specification/multiapi/generated/azure/multiapi/sample/v1/operations/_operation_group_one_operations.py index 09e311d6e36..bfb256eeede 100644 --- a/packages/autorest.python/samples/specification/multiapi/generated/azure/multiapi/sample/v1/operations/_operation_group_one_operations.py +++ b/packages/autorest.python/samples/specification/multiapi/generated/azure/multiapi/sample/v1/operations/_operation_group_one_operations.py @@ -24,8 +24,8 @@ from azure.mgmt.core.exceptions import ARMErrorFormat from .. import models as _models -from ..._serialization import Deserializer, Serializer from .._configuration import MultiapiServiceClientConfiguration +from .._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/autorest.python/samples/specification/multiapi/generated/azure/multiapi/sample/v2/_metadata.json b/packages/autorest.python/samples/specification/multiapi/generated/azure/multiapi/sample/v2/_metadata.json index 6b6258d2047..8c17464870f 100644 --- a/packages/autorest.python/samples/specification/multiapi/generated/azure/multiapi/sample/v2/_metadata.json +++ b/packages/autorest.python/samples/specification/multiapi/generated/azure/multiapi/sample/v2/_metadata.json @@ -10,8 +10,8 @@ "azure_arm": true, "has_public_lro_operations": false, "client_side_validation": false, - "sync_imports": "{\"conditional\": {\"stdlib\": {\"typing\": [\"Any\", \"Optional\"]}}, \"regular\": {\"sdkcore\": {\"azure.mgmt.core\": [\"ARMPipelineClient\"], \"azure.core.pipeline\": [\"policies\"], \"azure.mgmt.core.policies\": [\"ARMAutoResourceProviderRegistrationPolicy\"], \"azure.core.settings\": [\"settings\"], \"azure.mgmt.core.tools\": [\"get_arm_endpoints\"], \"azure.profiles\": [\"KnownProfiles\", \"ProfileDefinition\"], \"azure.profiles.multiapiclient\": [\"MultiApiClientMixin\"]}, \"stdlib\": {\"typing\": [\"Optional\", \"cast\"], \"typing_extensions\": [\"Self\"]}, \"local\": {\"._configuration\": [\"MultiapiServiceClientConfiguration\"], \".._serialization\": [\"Deserializer\", \"Serializer\"], \"._operations_mixin\": [\"MultiapiServiceClientOperationsMixin\"]}}, \"typing\": {\"sdkcore\": {\"azure.core.credentials\": [\"TokenCredential\"]}}}", - "async_imports": "{\"conditional\": {\"stdlib\": {\"typing\": [\"Any\", \"Optional\"]}}, \"regular\": {\"sdkcore\": {\"azure.mgmt.core\": [\"AsyncARMPipelineClient\"], \"azure.core.pipeline\": [\"policies\"], \"azure.mgmt.core.policies\": [\"AsyncARMAutoResourceProviderRegistrationPolicy\"], \"azure.core.settings\": [\"settings\"], \"azure.mgmt.core.tools\": [\"get_arm_endpoints\"], \"azure.profiles\": [\"KnownProfiles\", \"ProfileDefinition\"], \"azure.profiles.multiapiclient\": [\"MultiApiClientMixin\"]}, \"stdlib\": {\"typing\": [\"Optional\", \"cast\"], \"typing_extensions\": [\"Self\"]}, \"local\": {\"._configuration\": [\"MultiapiServiceClientConfiguration\"], \"..._serialization\": [\"Deserializer\", \"Serializer\"], \"._operations_mixin\": [\"MultiapiServiceClientOperationsMixin\"]}}, \"typing\": {\"sdkcore\": {\"azure.core.credentials_async\": [\"AsyncTokenCredential\"]}}}" + "sync_imports": "{\"conditional\": {\"stdlib\": {\"typing\": [\"Any\", \"Optional\"]}}, \"regular\": {\"sdkcore\": {\"azure.mgmt.core\": [\"ARMPipelineClient\"], \"azure.core.pipeline\": [\"policies\"], \"azure.mgmt.core.policies\": [\"ARMAutoResourceProviderRegistrationPolicy\"], \"azure.core.settings\": [\"settings\"], \"azure.mgmt.core.tools\": [\"get_arm_endpoints\"], \"azure.profiles\": [\"KnownProfiles\", \"ProfileDefinition\"], \"azure.profiles.multiapiclient\": [\"MultiApiClientMixin\"]}, \"stdlib\": {\"typing\": [\"Optional\", \"cast\"], \"typing_extensions\": [\"Self\"]}, \"local\": {\"._configuration\": [\"MultiapiServiceClientConfiguration\"], \"._utils.serialization\": [\"Deserializer\", \"Serializer\"], \"._operations_mixin\": [\"MultiapiServiceClientOperationsMixin\"]}}, \"typing\": {\"sdkcore\": {\"azure.core.credentials\": [\"TokenCredential\"]}}}", + "async_imports": "{\"conditional\": {\"stdlib\": {\"typing\": [\"Any\", \"Optional\"]}}, \"regular\": {\"sdkcore\": {\"azure.mgmt.core\": [\"AsyncARMPipelineClient\"], \"azure.core.pipeline\": [\"policies\"], \"azure.mgmt.core.policies\": [\"AsyncARMAutoResourceProviderRegistrationPolicy\"], \"azure.core.settings\": [\"settings\"], \"azure.mgmt.core.tools\": [\"get_arm_endpoints\"], \"azure.profiles\": [\"KnownProfiles\", \"ProfileDefinition\"], \"azure.profiles.multiapiclient\": [\"MultiApiClientMixin\"]}, \"stdlib\": {\"typing\": [\"Optional\", \"cast\"], \"typing_extensions\": [\"Self\"]}, \"local\": {\"._configuration\": [\"MultiapiServiceClientConfiguration\"], \".._utils.serialization\": [\"Deserializer\", \"Serializer\"], \"._operations_mixin\": [\"MultiapiServiceClientOperationsMixin\"]}}, \"typing\": {\"sdkcore\": {\"azure.core.credentials_async\": [\"AsyncTokenCredential\"]}}}" }, "global_parameters": { "sync": { diff --git a/packages/autorest.python/samples/specification/multiapi/generated/azure/multiapi/sample/v2/_multiapi_service_client.py b/packages/autorest.python/samples/specification/multiapi/generated/azure/multiapi/sample/v2/_multiapi_service_client.py index 54154abfc72..991fb0f6964 100644 --- a/packages/autorest.python/samples/specification/multiapi/generated/azure/multiapi/sample/v2/_multiapi_service_client.py +++ b/packages/autorest.python/samples/specification/multiapi/generated/azure/multiapi/sample/v2/_multiapi_service_client.py @@ -18,8 +18,8 @@ from azure.mgmt.core.tools import get_arm_endpoints from . import models as _models -from .._serialization import Deserializer, Serializer from ._configuration import MultiapiServiceClientConfiguration +from ._utils.serialization import Deserializer, Serializer from .operations import MultiapiServiceClientOperationsMixin, OperationGroupOneOperations, OperationGroupTwoOperations if TYPE_CHECKING: diff --git a/packages/autorest.python/samples/specification/multiapi/generated/azure/multiapi/sample/v2/_utils/__init__.py b/packages/autorest.python/samples/specification/multiapi/generated/azure/multiapi/sample/v2/_utils/__init__.py new file mode 100644 index 00000000000..0af9b28f660 --- /dev/null +++ b/packages/autorest.python/samples/specification/multiapi/generated/azure/multiapi/sample/v2/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/AzureReport/azurereport/_serialization.py b/packages/autorest.python/samples/specification/multiapi/generated/azure/multiapi/sample/v2/_utils/serialization.py similarity index 100% rename from packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/AzureReport/azurereport/_serialization.py rename to packages/autorest.python/samples/specification/multiapi/generated/azure/multiapi/sample/v2/_utils/serialization.py diff --git a/packages/autorest.python/samples/specification/multiapi/generated/azure/multiapi/sample/v2/_utils/utils.py b/packages/autorest.python/samples/specification/multiapi/generated/azure/multiapi/sample/v2/_utils/utils.py new file mode 100644 index 00000000000..39b612f39a9 --- /dev/null +++ b/packages/autorest.python/samples/specification/multiapi/generated/azure/multiapi/sample/v2/_utils/utils.py @@ -0,0 +1,25 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from abc import ABC +from typing import Generic, TYPE_CHECKING, TypeVar + +if TYPE_CHECKING: + from .serialization import Deserializer, Serializer + + +TClient = TypeVar("TClient") +TConfig = TypeVar("TConfig") + + +class ClientMixinABC(ABC, Generic[TClient, TConfig]): + """DO NOT use this class. It is for internal typing use only.""" + + _client: TClient + _config: TConfig + _serialize: "Serializer" + _deserialize: "Deserializer" diff --git a/packages/autorest.python/samples/specification/multiapi/generated/azure/multiapi/sample/v2/_vendor.py b/packages/autorest.python/samples/specification/multiapi/generated/azure/multiapi/sample/v2/_vendor.py deleted file mode 100644 index 70517e0b7af..00000000000 --- a/packages/autorest.python/samples/specification/multiapi/generated/azure/multiapi/sample/v2/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) AutoRest Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import MultiapiServiceClientConfiguration - -if TYPE_CHECKING: - from azure.core import PipelineClient - - from .._serialization import Deserializer, Serializer - - -class MultiapiServiceClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "PipelineClient" - _config: MultiapiServiceClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/autorest.python/samples/specification/multiapi/generated/azure/multiapi/sample/v2/aio/_multiapi_service_client.py b/packages/autorest.python/samples/specification/multiapi/generated/azure/multiapi/sample/v2/aio/_multiapi_service_client.py index 1ed555c423a..d90355010b5 100644 --- a/packages/autorest.python/samples/specification/multiapi/generated/azure/multiapi/sample/v2/aio/_multiapi_service_client.py +++ b/packages/autorest.python/samples/specification/multiapi/generated/azure/multiapi/sample/v2/aio/_multiapi_service_client.py @@ -18,7 +18,7 @@ from azure.mgmt.core.tools import get_arm_endpoints from .. import models as _models -from ..._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import MultiapiServiceClientConfiguration from .operations import MultiapiServiceClientOperationsMixin, OperationGroupOneOperations, OperationGroupTwoOperations diff --git a/packages/autorest.python/samples/specification/multiapi/generated/azure/multiapi/sample/v2/aio/_vendor.py b/packages/autorest.python/samples/specification/multiapi/generated/azure/multiapi/sample/v2/aio/_vendor.py deleted file mode 100644 index 9c6fd05bb21..00000000000 --- a/packages/autorest.python/samples/specification/multiapi/generated/azure/multiapi/sample/v2/aio/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) AutoRest Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import MultiapiServiceClientConfiguration - -if TYPE_CHECKING: - from azure.core import AsyncPipelineClient - - from ..._serialization import Deserializer, Serializer - - -class MultiapiServiceClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "AsyncPipelineClient" - _config: MultiapiServiceClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/autorest.python/samples/specification/multiapi/generated/azure/multiapi/sample/v2/aio/operations/_multiapi_service_client_operations.py b/packages/autorest.python/samples/specification/multiapi/generated/azure/multiapi/sample/v2/aio/operations/_multiapi_service_client_operations.py index a17aa785371..c5926cb7c45 100644 --- a/packages/autorest.python/samples/specification/multiapi/generated/azure/multiapi/sample/v2/aio/operations/_multiapi_service_client_operations.py +++ b/packages/autorest.python/samples/specification/multiapi/generated/azure/multiapi/sample/v2/aio/operations/_multiapi_service_client_operations.py @@ -9,6 +9,7 @@ from collections.abc import MutableMapping from typing import Any, Callable, Dict, Optional, TypeVar +from azure.core import AsyncPipelineClient from azure.core.exceptions import ( ClientAuthenticationError, HttpResponseError, @@ -24,14 +25,15 @@ from azure.mgmt.core.exceptions import ARMErrorFormat from ... import models as _models +from ..._utils.utils import ClientMixinABC from ...operations._multiapi_service_client_operations import build_test_different_calls_request, build_test_one_request -from .._vendor import MultiapiServiceClientMixinABC +from .._configuration import MultiapiServiceClientConfiguration T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, AsyncHttpResponse], T, Dict[str, Any]], Any]] -class MultiapiServiceClientOperationsMixin(MultiapiServiceClientMixinABC): +class MultiapiServiceClientOperationsMixin(ClientMixinABC[AsyncPipelineClient, MultiapiServiceClientConfiguration]): def _api_version(self, op_name: str) -> str: # pylint: disable=unused-argument try: return self._config.api_version diff --git a/packages/autorest.python/samples/specification/multiapi/generated/azure/multiapi/sample/v2/aio/operations/_operation_group_one_operations.py b/packages/autorest.python/samples/specification/multiapi/generated/azure/multiapi/sample/v2/aio/operations/_operation_group_one_operations.py index ef50b42c8c8..98dfc0ce7e7 100644 --- a/packages/autorest.python/samples/specification/multiapi/generated/azure/multiapi/sample/v2/aio/operations/_operation_group_one_operations.py +++ b/packages/autorest.python/samples/specification/multiapi/generated/azure/multiapi/sample/v2/aio/operations/_operation_group_one_operations.py @@ -25,7 +25,7 @@ from azure.mgmt.core.exceptions import ARMErrorFormat from ... import models as _models -from ...._serialization import Deserializer, Serializer +from ..._utils.serialization import Deserializer, Serializer from ...operations._operation_group_one_operations import build_test_three_request, build_test_two_request from .._configuration import MultiapiServiceClientConfiguration diff --git a/packages/autorest.python/samples/specification/multiapi/generated/azure/multiapi/sample/v2/aio/operations/_operation_group_two_operations.py b/packages/autorest.python/samples/specification/multiapi/generated/azure/multiapi/sample/v2/aio/operations/_operation_group_two_operations.py index 2837828018c..4ccfd325cd9 100644 --- a/packages/autorest.python/samples/specification/multiapi/generated/azure/multiapi/sample/v2/aio/operations/_operation_group_two_operations.py +++ b/packages/autorest.python/samples/specification/multiapi/generated/azure/multiapi/sample/v2/aio/operations/_operation_group_two_operations.py @@ -24,7 +24,7 @@ from azure.mgmt.core.exceptions import ARMErrorFormat from ... import models as _models -from ...._serialization import Deserializer, Serializer +from ..._utils.serialization import Deserializer, Serializer from ...operations._operation_group_two_operations import build_test_four_request from .._configuration import MultiapiServiceClientConfiguration diff --git a/packages/autorest.python/samples/specification/multiapi/generated/azure/multiapi/sample/v2/models/_models_py3.py b/packages/autorest.python/samples/specification/multiapi/generated/azure/multiapi/sample/v2/models/_models_py3.py index 46990252065..a00726a3da2 100644 --- a/packages/autorest.python/samples/specification/multiapi/generated/azure/multiapi/sample/v2/models/_models_py3.py +++ b/packages/autorest.python/samples/specification/multiapi/generated/azure/multiapi/sample/v2/models/_models_py3.py @@ -8,7 +8,7 @@ from typing import Any, Optional -from ... import _serialization +from .._utils import serialization as _serialization class Error(_serialization.Model): diff --git a/packages/autorest.python/samples/specification/multiapi/generated/azure/multiapi/sample/v2/operations/_multiapi_service_client_operations.py b/packages/autorest.python/samples/specification/multiapi/generated/azure/multiapi/sample/v2/operations/_multiapi_service_client_operations.py index 4fa2b8c6fd6..1ccdacc247c 100644 --- a/packages/autorest.python/samples/specification/multiapi/generated/azure/multiapi/sample/v2/operations/_multiapi_service_client_operations.py +++ b/packages/autorest.python/samples/specification/multiapi/generated/azure/multiapi/sample/v2/operations/_multiapi_service_client_operations.py @@ -8,6 +8,7 @@ from collections.abc import MutableMapping from typing import Any, Callable, Dict, Optional, TypeVar +from azure.core import PipelineClient from azure.core.exceptions import ( ClientAuthenticationError, HttpResponseError, @@ -23,8 +24,9 @@ from azure.mgmt.core.exceptions import ARMErrorFormat from .. import models as _models -from ..._serialization import Serializer -from .._vendor import MultiapiServiceClientMixinABC +from .._configuration import MultiapiServiceClientConfiguration +from .._utils.serialization import Serializer +from .._utils.utils import ClientMixinABC T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] @@ -79,7 +81,7 @@ def build_test_different_calls_request( return HttpRequest(method="GET", url=_url, params=_params, headers=_headers, **kwargs) -class MultiapiServiceClientOperationsMixin(MultiapiServiceClientMixinABC): +class MultiapiServiceClientOperationsMixin(ClientMixinABC[PipelineClient, MultiapiServiceClientConfiguration]): def _api_version(self, op_name: str) -> str: # pylint: disable=unused-argument try: return self._config.api_version diff --git a/packages/autorest.python/samples/specification/multiapi/generated/azure/multiapi/sample/v2/operations/_operation_group_one_operations.py b/packages/autorest.python/samples/specification/multiapi/generated/azure/multiapi/sample/v2/operations/_operation_group_one_operations.py index 2a6f2f11e18..ad1d9ef1cf6 100644 --- a/packages/autorest.python/samples/specification/multiapi/generated/azure/multiapi/sample/v2/operations/_operation_group_one_operations.py +++ b/packages/autorest.python/samples/specification/multiapi/generated/azure/multiapi/sample/v2/operations/_operation_group_one_operations.py @@ -25,8 +25,8 @@ from azure.mgmt.core.exceptions import ARMErrorFormat from .. import models as _models -from ..._serialization import Deserializer, Serializer from .._configuration import MultiapiServiceClientConfiguration +from .._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/autorest.python/samples/specification/multiapi/generated/azure/multiapi/sample/v2/operations/_operation_group_two_operations.py b/packages/autorest.python/samples/specification/multiapi/generated/azure/multiapi/sample/v2/operations/_operation_group_two_operations.py index 6692b600239..82f9f20bd76 100644 --- a/packages/autorest.python/samples/specification/multiapi/generated/azure/multiapi/sample/v2/operations/_operation_group_two_operations.py +++ b/packages/autorest.python/samples/specification/multiapi/generated/azure/multiapi/sample/v2/operations/_operation_group_two_operations.py @@ -24,8 +24,8 @@ from azure.mgmt.core.exceptions import ARMErrorFormat from .. import models as _models -from ..._serialization import Deserializer, Serializer from .._configuration import MultiapiServiceClientConfiguration +from .._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/autorest.python/samples/specification/multiapi/generated/azure/multiapi/sample/v3/_metadata.json b/packages/autorest.python/samples/specification/multiapi/generated/azure/multiapi/sample/v3/_metadata.json index a4b55c6c9a0..98596886372 100644 --- a/packages/autorest.python/samples/specification/multiapi/generated/azure/multiapi/sample/v3/_metadata.json +++ b/packages/autorest.python/samples/specification/multiapi/generated/azure/multiapi/sample/v3/_metadata.json @@ -10,8 +10,8 @@ "azure_arm": true, "has_public_lro_operations": false, "client_side_validation": false, - "sync_imports": "{\"conditional\": {\"stdlib\": {\"typing\": [\"Any\", \"Optional\"]}}, \"regular\": {\"sdkcore\": {\"azure.mgmt.core\": [\"ARMPipelineClient\"], \"azure.core.pipeline\": [\"policies\"], \"azure.mgmt.core.policies\": [\"ARMAutoResourceProviderRegistrationPolicy\"], \"azure.core.settings\": [\"settings\"], \"azure.mgmt.core.tools\": [\"get_arm_endpoints\"], \"azure.profiles\": [\"KnownProfiles\", \"ProfileDefinition\"], \"azure.profiles.multiapiclient\": [\"MultiApiClientMixin\"]}, \"stdlib\": {\"typing\": [\"Optional\", \"cast\"], \"typing_extensions\": [\"Self\"]}, \"local\": {\"._configuration\": [\"MultiapiServiceClientConfiguration\"], \".._serialization\": [\"Deserializer\", \"Serializer\"], \"._operations_mixin\": [\"MultiapiServiceClientOperationsMixin\"]}}, \"typing\": {\"sdkcore\": {\"azure.core.credentials\": [\"TokenCredential\"]}}}", - "async_imports": "{\"conditional\": {\"stdlib\": {\"typing\": [\"Any\", \"Optional\"]}}, \"regular\": {\"sdkcore\": {\"azure.mgmt.core\": [\"AsyncARMPipelineClient\"], \"azure.core.pipeline\": [\"policies\"], \"azure.mgmt.core.policies\": [\"AsyncARMAutoResourceProviderRegistrationPolicy\"], \"azure.core.settings\": [\"settings\"], \"azure.mgmt.core.tools\": [\"get_arm_endpoints\"], \"azure.profiles\": [\"KnownProfiles\", \"ProfileDefinition\"], \"azure.profiles.multiapiclient\": [\"MultiApiClientMixin\"]}, \"stdlib\": {\"typing\": [\"Optional\", \"cast\"], \"typing_extensions\": [\"Self\"]}, \"local\": {\"._configuration\": [\"MultiapiServiceClientConfiguration\"], \"..._serialization\": [\"Deserializer\", \"Serializer\"], \"._operations_mixin\": [\"MultiapiServiceClientOperationsMixin\"]}}, \"typing\": {\"sdkcore\": {\"azure.core.credentials_async\": [\"AsyncTokenCredential\"]}}}" + "sync_imports": "{\"conditional\": {\"stdlib\": {\"typing\": [\"Any\", \"Optional\"]}}, \"regular\": {\"sdkcore\": {\"azure.mgmt.core\": [\"ARMPipelineClient\"], \"azure.core.pipeline\": [\"policies\"], \"azure.mgmt.core.policies\": [\"ARMAutoResourceProviderRegistrationPolicy\"], \"azure.core.settings\": [\"settings\"], \"azure.mgmt.core.tools\": [\"get_arm_endpoints\"], \"azure.profiles\": [\"KnownProfiles\", \"ProfileDefinition\"], \"azure.profiles.multiapiclient\": [\"MultiApiClientMixin\"]}, \"stdlib\": {\"typing\": [\"Optional\", \"cast\"], \"typing_extensions\": [\"Self\"]}, \"local\": {\"._configuration\": [\"MultiapiServiceClientConfiguration\"], \"._utils.serialization\": [\"Deserializer\", \"Serializer\"], \"._operations_mixin\": [\"MultiapiServiceClientOperationsMixin\"]}}, \"typing\": {\"sdkcore\": {\"azure.core.credentials\": [\"TokenCredential\"]}}}", + "async_imports": "{\"conditional\": {\"stdlib\": {\"typing\": [\"Any\", \"Optional\"]}}, \"regular\": {\"sdkcore\": {\"azure.mgmt.core\": [\"AsyncARMPipelineClient\"], \"azure.core.pipeline\": [\"policies\"], \"azure.mgmt.core.policies\": [\"AsyncARMAutoResourceProviderRegistrationPolicy\"], \"azure.core.settings\": [\"settings\"], \"azure.mgmt.core.tools\": [\"get_arm_endpoints\"], \"azure.profiles\": [\"KnownProfiles\", \"ProfileDefinition\"], \"azure.profiles.multiapiclient\": [\"MultiApiClientMixin\"]}, \"stdlib\": {\"typing\": [\"Optional\", \"cast\"], \"typing_extensions\": [\"Self\"]}, \"local\": {\"._configuration\": [\"MultiapiServiceClientConfiguration\"], \".._utils.serialization\": [\"Deserializer\", \"Serializer\"], \"._operations_mixin\": [\"MultiapiServiceClientOperationsMixin\"]}}, \"typing\": {\"sdkcore\": {\"azure.core.credentials_async\": [\"AsyncTokenCredential\"]}}}" }, "global_parameters": { "sync": { diff --git a/packages/autorest.python/samples/specification/multiapi/generated/azure/multiapi/sample/v3/_multiapi_service_client.py b/packages/autorest.python/samples/specification/multiapi/generated/azure/multiapi/sample/v3/_multiapi_service_client.py index a2ecd98c08f..16b83fbe3d3 100644 --- a/packages/autorest.python/samples/specification/multiapi/generated/azure/multiapi/sample/v3/_multiapi_service_client.py +++ b/packages/autorest.python/samples/specification/multiapi/generated/azure/multiapi/sample/v3/_multiapi_service_client.py @@ -18,8 +18,8 @@ from azure.mgmt.core.tools import get_arm_endpoints from . import models as _models -from .._serialization import Deserializer, Serializer from ._configuration import MultiapiServiceClientConfiguration +from ._utils.serialization import Deserializer, Serializer from .operations import MultiapiServiceClientOperationsMixin, OperationGroupOneOperations, OperationGroupTwoOperations if TYPE_CHECKING: diff --git a/packages/autorest.python/samples/specification/multiapi/generated/azure/multiapi/sample/v3/_utils/__init__.py b/packages/autorest.python/samples/specification/multiapi/generated/azure/multiapi/sample/v3/_utils/__init__.py new file mode 100644 index 00000000000..0af9b28f660 --- /dev/null +++ b/packages/autorest.python/samples/specification/multiapi/generated/azure/multiapi/sample/v3/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/CustomPollerPager/custompollerpager/_serialization.py b/packages/autorest.python/samples/specification/multiapi/generated/azure/multiapi/sample/v3/_utils/serialization.py similarity index 100% rename from packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/CustomPollerPager/custompollerpager/_serialization.py rename to packages/autorest.python/samples/specification/multiapi/generated/azure/multiapi/sample/v3/_utils/serialization.py diff --git a/packages/autorest.python/samples/specification/multiapi/generated/azure/multiapi/sample/v3/_utils/utils.py b/packages/autorest.python/samples/specification/multiapi/generated/azure/multiapi/sample/v3/_utils/utils.py new file mode 100644 index 00000000000..39b612f39a9 --- /dev/null +++ b/packages/autorest.python/samples/specification/multiapi/generated/azure/multiapi/sample/v3/_utils/utils.py @@ -0,0 +1,25 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from abc import ABC +from typing import Generic, TYPE_CHECKING, TypeVar + +if TYPE_CHECKING: + from .serialization import Deserializer, Serializer + + +TClient = TypeVar("TClient") +TConfig = TypeVar("TConfig") + + +class ClientMixinABC(ABC, Generic[TClient, TConfig]): + """DO NOT use this class. It is for internal typing use only.""" + + _client: TClient + _config: TConfig + _serialize: "Serializer" + _deserialize: "Deserializer" diff --git a/packages/autorest.python/samples/specification/multiapi/generated/azure/multiapi/sample/v3/_vendor.py b/packages/autorest.python/samples/specification/multiapi/generated/azure/multiapi/sample/v3/_vendor.py deleted file mode 100644 index 70517e0b7af..00000000000 --- a/packages/autorest.python/samples/specification/multiapi/generated/azure/multiapi/sample/v3/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) AutoRest Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import MultiapiServiceClientConfiguration - -if TYPE_CHECKING: - from azure.core import PipelineClient - - from .._serialization import Deserializer, Serializer - - -class MultiapiServiceClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "PipelineClient" - _config: MultiapiServiceClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/autorest.python/samples/specification/multiapi/generated/azure/multiapi/sample/v3/aio/_multiapi_service_client.py b/packages/autorest.python/samples/specification/multiapi/generated/azure/multiapi/sample/v3/aio/_multiapi_service_client.py index 4fc6c74c485..cad974bc4fd 100644 --- a/packages/autorest.python/samples/specification/multiapi/generated/azure/multiapi/sample/v3/aio/_multiapi_service_client.py +++ b/packages/autorest.python/samples/specification/multiapi/generated/azure/multiapi/sample/v3/aio/_multiapi_service_client.py @@ -18,7 +18,7 @@ from azure.mgmt.core.tools import get_arm_endpoints from .. import models as _models -from ..._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import MultiapiServiceClientConfiguration from .operations import MultiapiServiceClientOperationsMixin, OperationGroupOneOperations, OperationGroupTwoOperations diff --git a/packages/autorest.python/samples/specification/multiapi/generated/azure/multiapi/sample/v3/aio/_vendor.py b/packages/autorest.python/samples/specification/multiapi/generated/azure/multiapi/sample/v3/aio/_vendor.py deleted file mode 100644 index 9c6fd05bb21..00000000000 --- a/packages/autorest.python/samples/specification/multiapi/generated/azure/multiapi/sample/v3/aio/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) AutoRest Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import MultiapiServiceClientConfiguration - -if TYPE_CHECKING: - from azure.core import AsyncPipelineClient - - from ..._serialization import Deserializer, Serializer - - -class MultiapiServiceClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "AsyncPipelineClient" - _config: MultiapiServiceClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/autorest.python/samples/specification/multiapi/generated/azure/multiapi/sample/v3/aio/operations/_multiapi_service_client_operations.py b/packages/autorest.python/samples/specification/multiapi/generated/azure/multiapi/sample/v3/aio/operations/_multiapi_service_client_operations.py index bc69659a05f..751494c06eb 100644 --- a/packages/autorest.python/samples/specification/multiapi/generated/azure/multiapi/sample/v3/aio/operations/_multiapi_service_client_operations.py +++ b/packages/autorest.python/samples/specification/multiapi/generated/azure/multiapi/sample/v3/aio/operations/_multiapi_service_client_operations.py @@ -10,6 +10,7 @@ from typing import Any, AsyncIterable, Callable, Dict, Optional, TypeVar import urllib.parse +from azure.core import AsyncPipelineClient from azure.core.async_paging import AsyncItemPaged, AsyncList from azure.core.exceptions import ( ClientAuthenticationError, @@ -27,17 +28,18 @@ from azure.mgmt.core.exceptions import ARMErrorFormat from ... import models as _models +from ..._utils.utils import ClientMixinABC from ...operations._multiapi_service_client_operations import ( build_test_different_calls_request, build_test_paging_request, ) -from .._vendor import MultiapiServiceClientMixinABC +from .._configuration import MultiapiServiceClientConfiguration T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, AsyncHttpResponse], T, Dict[str, Any]], Any]] -class MultiapiServiceClientOperationsMixin(MultiapiServiceClientMixinABC): +class MultiapiServiceClientOperationsMixin(ClientMixinABC[AsyncPipelineClient, MultiapiServiceClientConfiguration]): def _api_version(self, op_name: str) -> str: # pylint: disable=unused-argument try: return self._config.api_version diff --git a/packages/autorest.python/samples/specification/multiapi/generated/azure/multiapi/sample/v3/aio/operations/_operation_group_one_operations.py b/packages/autorest.python/samples/specification/multiapi/generated/azure/multiapi/sample/v3/aio/operations/_operation_group_one_operations.py index ef79a1ed8cc..4213a70cf66 100644 --- a/packages/autorest.python/samples/specification/multiapi/generated/azure/multiapi/sample/v3/aio/operations/_operation_group_one_operations.py +++ b/packages/autorest.python/samples/specification/multiapi/generated/azure/multiapi/sample/v3/aio/operations/_operation_group_one_operations.py @@ -28,7 +28,7 @@ from azure.mgmt.core.exceptions import ARMErrorFormat from ... import models as _models -from ...._serialization import Deserializer, Serializer +from ..._utils.serialization import Deserializer, Serializer from ...operations._operation_group_one_operations import ( build_test_operation_group_paging_request, build_test_two_request, diff --git a/packages/autorest.python/samples/specification/multiapi/generated/azure/multiapi/sample/v3/aio/operations/_operation_group_two_operations.py b/packages/autorest.python/samples/specification/multiapi/generated/azure/multiapi/sample/v3/aio/operations/_operation_group_two_operations.py index fe8bc201f63..bfc87390709 100644 --- a/packages/autorest.python/samples/specification/multiapi/generated/azure/multiapi/sample/v3/aio/operations/_operation_group_two_operations.py +++ b/packages/autorest.python/samples/specification/multiapi/generated/azure/multiapi/sample/v3/aio/operations/_operation_group_two_operations.py @@ -25,7 +25,7 @@ from azure.mgmt.core.exceptions import ARMErrorFormat from ... import models as _models -from ...._serialization import Deserializer, Serializer +from ..._utils.serialization import Deserializer, Serializer from ...operations._operation_group_two_operations import build_test_five_request, build_test_four_request from .._configuration import MultiapiServiceClientConfiguration diff --git a/packages/autorest.python/samples/specification/multiapi/generated/azure/multiapi/sample/v3/models/_models_py3.py b/packages/autorest.python/samples/specification/multiapi/generated/azure/multiapi/sample/v3/models/_models_py3.py index 0f284e05cf1..7d0d8f6b862 100644 --- a/packages/autorest.python/samples/specification/multiapi/generated/azure/multiapi/sample/v3/models/_models_py3.py +++ b/packages/autorest.python/samples/specification/multiapi/generated/azure/multiapi/sample/v3/models/_models_py3.py @@ -8,7 +8,7 @@ from typing import Any, List, Optional, TYPE_CHECKING -from ... import _serialization +from .._utils import serialization as _serialization if TYPE_CHECKING: from .. import models as _models diff --git a/packages/autorest.python/samples/specification/multiapi/generated/azure/multiapi/sample/v3/operations/_multiapi_service_client_operations.py b/packages/autorest.python/samples/specification/multiapi/generated/azure/multiapi/sample/v3/operations/_multiapi_service_client_operations.py index 767f753749d..f7ef8e6cd39 100644 --- a/packages/autorest.python/samples/specification/multiapi/generated/azure/multiapi/sample/v3/operations/_multiapi_service_client_operations.py +++ b/packages/autorest.python/samples/specification/multiapi/generated/azure/multiapi/sample/v3/operations/_multiapi_service_client_operations.py @@ -9,6 +9,7 @@ from typing import Any, Callable, Dict, Iterable, Optional, TypeVar import urllib.parse +from azure.core import PipelineClient from azure.core.exceptions import ( ClientAuthenticationError, HttpResponseError, @@ -25,8 +26,9 @@ from azure.mgmt.core.exceptions import ARMErrorFormat from .. import models as _models -from ..._serialization import Serializer -from .._vendor import MultiapiServiceClientMixinABC +from .._configuration import MultiapiServiceClientConfiguration +from .._utils.serialization import Serializer +from .._utils.utils import ClientMixinABC T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] @@ -79,7 +81,7 @@ def build_test_different_calls_request( return HttpRequest(method="GET", url=_url, params=_params, headers=_headers, **kwargs) -class MultiapiServiceClientOperationsMixin(MultiapiServiceClientMixinABC): +class MultiapiServiceClientOperationsMixin(ClientMixinABC[PipelineClient, MultiapiServiceClientConfiguration]): def _api_version(self, op_name: str) -> str: # pylint: disable=unused-argument try: return self._config.api_version diff --git a/packages/autorest.python/samples/specification/multiapi/generated/azure/multiapi/sample/v3/operations/_operation_group_one_operations.py b/packages/autorest.python/samples/specification/multiapi/generated/azure/multiapi/sample/v3/operations/_operation_group_one_operations.py index 300e9752ee2..df458abd4be 100644 --- a/packages/autorest.python/samples/specification/multiapi/generated/azure/multiapi/sample/v3/operations/_operation_group_one_operations.py +++ b/packages/autorest.python/samples/specification/multiapi/generated/azure/multiapi/sample/v3/operations/_operation_group_one_operations.py @@ -27,8 +27,8 @@ from azure.mgmt.core.exceptions import ARMErrorFormat from .. import models as _models -from ..._serialization import Deserializer, Serializer from .._configuration import MultiapiServiceClientConfiguration +from .._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/autorest.python/samples/specification/multiapi/generated/azure/multiapi/sample/v3/operations/_operation_group_two_operations.py b/packages/autorest.python/samples/specification/multiapi/generated/azure/multiapi/sample/v3/operations/_operation_group_two_operations.py index ef3505b2b47..7f1e8ab888c 100644 --- a/packages/autorest.python/samples/specification/multiapi/generated/azure/multiapi/sample/v3/operations/_operation_group_two_operations.py +++ b/packages/autorest.python/samples/specification/multiapi/generated/azure/multiapi/sample/v3/operations/_operation_group_two_operations.py @@ -25,8 +25,8 @@ from azure.mgmt.core.exceptions import ARMErrorFormat from .. import models as _models -from ..._serialization import Deserializer, Serializer from .._configuration import MultiapiServiceClientConfiguration +from .._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/autorest.python/tasks.py b/packages/autorest.python/tasks.py index 75520536bbd..25896843166 100644 --- a/packages/autorest.python/tasks.py +++ b/packages/autorest.python/tasks.py @@ -467,7 +467,7 @@ def regenerate( @task def regenerate_unittests(c): shutil.copyfile( - "test/azure/legacy/Expected/AcceptanceTests/AzureBodyDuration/bodyduration/_serialization.py", + "test/azure/legacy/Expected/AcceptanceTests/AzureBodyDuration/bodyduration/_utils/serialization.py", "test/unittests/storage_models/serialization.py", ) diff --git a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/AzureBodyDuration/bodyduration/_auto_rest_duration_test_service.py b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/AzureBodyDuration/bodyduration/_auto_rest_duration_test_service.py index 7643379f050..99afed42522 100644 --- a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/AzureBodyDuration/bodyduration/_auto_rest_duration_test_service.py +++ b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/AzureBodyDuration/bodyduration/_auto_rest_duration_test_service.py @@ -16,7 +16,7 @@ from . import models as _models from ._configuration import AutoRestDurationTestServiceConfiguration -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer from .operations import DurationOperations diff --git a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/AzureBodyDuration/bodyduration/_utils/__init__.py b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/AzureBodyDuration/bodyduration/_utils/__init__.py new file mode 100644 index 00000000000..0af9b28f660 --- /dev/null +++ b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/AzureBodyDuration/bodyduration/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/CustomUrlPaging/custombaseurlpaging/_serialization.py b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/AzureBodyDuration/bodyduration/_utils/serialization.py similarity index 100% rename from packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/CustomUrlPaging/custombaseurlpaging/_serialization.py rename to packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/AzureBodyDuration/bodyduration/_utils/serialization.py diff --git a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/AzureBodyDuration/bodyduration/aio/_auto_rest_duration_test_service.py b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/AzureBodyDuration/bodyduration/aio/_auto_rest_duration_test_service.py index 99edfaf2a7f..b6145cdcadd 100644 --- a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/AzureBodyDuration/bodyduration/aio/_auto_rest_duration_test_service.py +++ b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/AzureBodyDuration/bodyduration/aio/_auto_rest_duration_test_service.py @@ -15,7 +15,7 @@ from azure.core.rest import AsyncHttpResponse, HttpRequest from .. import models as _models -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import AutoRestDurationTestServiceConfiguration from .operations import DurationOperations diff --git a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/AzureBodyDuration/bodyduration/aio/operations/_duration_operations.py b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/AzureBodyDuration/bodyduration/aio/operations/_duration_operations.py index 4b66edf6816..cf92c57b6cc 100644 --- a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/AzureBodyDuration/bodyduration/aio/operations/_duration_operations.py +++ b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/AzureBodyDuration/bodyduration/aio/operations/_duration_operations.py @@ -24,7 +24,7 @@ from azure.core.utils import case_insensitive_dict from ... import models as _models -from ..._serialization import Deserializer, Serializer +from ..._utils.serialization import Deserializer, Serializer from ...operations._duration_operations import ( build_get_invalid_request, build_get_null_request, diff --git a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/AzureBodyDuration/bodyduration/models/_models_py3.py b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/AzureBodyDuration/bodyduration/models/_models_py3.py index 1d1b7707def..109cf147510 100644 --- a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/AzureBodyDuration/bodyduration/models/_models_py3.py +++ b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/AzureBodyDuration/bodyduration/models/_models_py3.py @@ -8,7 +8,7 @@ from typing import Any, Optional -from .. import _serialization +from .._utils import serialization as _serialization class Error(_serialization.Model): diff --git a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/AzureBodyDuration/bodyduration/operations/_duration_operations.py b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/AzureBodyDuration/bodyduration/operations/_duration_operations.py index e504a2de33c..187bbb920cb 100644 --- a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/AzureBodyDuration/bodyduration/operations/_duration_operations.py +++ b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/AzureBodyDuration/bodyduration/operations/_duration_operations.py @@ -25,7 +25,7 @@ from .. import models as _models from .._configuration import AutoRestDurationTestServiceConfiguration -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/AzureReport/azurereport/_auto_rest_report_service_for_azure.py b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/AzureReport/azurereport/_auto_rest_report_service_for_azure.py index fe557451ca5..ec9a3f10751 100644 --- a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/AzureReport/azurereport/_auto_rest_report_service_for_azure.py +++ b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/AzureReport/azurereport/_auto_rest_report_service_for_azure.py @@ -16,7 +16,7 @@ from . import models as _models from ._configuration import AutoRestReportServiceForAzureConfiguration -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer from .operations import AutoRestReportServiceForAzureOperationsMixin diff --git a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/AzureReport/azurereport/_utils/__init__.py b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/AzureReport/azurereport/_utils/__init__.py new file mode 100644 index 00000000000..0af9b28f660 --- /dev/null +++ b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/AzureReport/azurereport/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/Head/head/_serialization.py b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/AzureReport/azurereport/_utils/serialization.py similarity index 100% rename from packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/Head/head/_serialization.py rename to packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/AzureReport/azurereport/_utils/serialization.py diff --git a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/AzureReport/azurereport/_utils/utils.py b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/AzureReport/azurereport/_utils/utils.py new file mode 100644 index 00000000000..39b612f39a9 --- /dev/null +++ b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/AzureReport/azurereport/_utils/utils.py @@ -0,0 +1,25 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from abc import ABC +from typing import Generic, TYPE_CHECKING, TypeVar + +if TYPE_CHECKING: + from .serialization import Deserializer, Serializer + + +TClient = TypeVar("TClient") +TConfig = TypeVar("TConfig") + + +class ClientMixinABC(ABC, Generic[TClient, TConfig]): + """DO NOT use this class. It is for internal typing use only.""" + + _client: TClient + _config: TConfig + _serialize: "Serializer" + _deserialize: "Deserializer" diff --git a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/AzureReport/azurereport/_vendor.py b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/AzureReport/azurereport/_vendor.py deleted file mode 100644 index 3af6dbaa6be..00000000000 --- a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/AzureReport/azurereport/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) AutoRest Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import AutoRestReportServiceForAzureConfiguration - -if TYPE_CHECKING: - from azure.core import PipelineClient - - from ._serialization import Deserializer, Serializer - - -class AutoRestReportServiceForAzureMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "PipelineClient" - _config: AutoRestReportServiceForAzureConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/AzureReport/azurereport/aio/_auto_rest_report_service_for_azure.py b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/AzureReport/azurereport/aio/_auto_rest_report_service_for_azure.py index 6bd77ad055f..30a746b7a18 100644 --- a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/AzureReport/azurereport/aio/_auto_rest_report_service_for_azure.py +++ b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/AzureReport/azurereport/aio/_auto_rest_report_service_for_azure.py @@ -15,7 +15,7 @@ from azure.core.rest import AsyncHttpResponse, HttpRequest from .. import models as _models -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import AutoRestReportServiceForAzureConfiguration from .operations import AutoRestReportServiceForAzureOperationsMixin diff --git a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/AzureReport/azurereport/aio/_vendor.py b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/AzureReport/azurereport/aio/_vendor.py deleted file mode 100644 index 769b210a071..00000000000 --- a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/AzureReport/azurereport/aio/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) AutoRest Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import AutoRestReportServiceForAzureConfiguration - -if TYPE_CHECKING: - from azure.core import AsyncPipelineClient - - from .._serialization import Deserializer, Serializer - - -class AutoRestReportServiceForAzureMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "AsyncPipelineClient" - _config: AutoRestReportServiceForAzureConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/AzureReport/azurereport/aio/operations/_auto_rest_report_service_for_azure_operations.py b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/AzureReport/azurereport/aio/operations/_auto_rest_report_service_for_azure_operations.py index d4da7f98667..97c8c2e73e3 100644 --- a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/AzureReport/azurereport/aio/operations/_auto_rest_report_service_for_azure_operations.py +++ b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/AzureReport/azurereport/aio/operations/_auto_rest_report_service_for_azure_operations.py @@ -9,6 +9,7 @@ from collections.abc import MutableMapping from typing import Any, Callable, Dict, Optional, TypeVar +from azure.core import AsyncPipelineClient from azure.core.exceptions import ( ClientAuthenticationError, HttpResponseError, @@ -22,15 +23,16 @@ from azure.core.tracing.decorator_async import distributed_trace_async from ... import models as _models +from ..._utils.utils import ClientMixinABC from ...operations._auto_rest_report_service_for_azure_operations import build_get_report_request -from .._vendor import AutoRestReportServiceForAzureMixinABC +from .._configuration import AutoRestReportServiceForAzureConfiguration T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, AsyncHttpResponse], T, Dict[str, Any]], Any]] class AutoRestReportServiceForAzureOperationsMixin( # pylint: disable=name-too-long - AutoRestReportServiceForAzureMixinABC + ClientMixinABC[AsyncPipelineClient, AutoRestReportServiceForAzureConfiguration] ): @distributed_trace_async diff --git a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/AzureReport/azurereport/models/_models_py3.py b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/AzureReport/azurereport/models/_models_py3.py index 1d1b7707def..109cf147510 100644 --- a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/AzureReport/azurereport/models/_models_py3.py +++ b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/AzureReport/azurereport/models/_models_py3.py @@ -8,7 +8,7 @@ from typing import Any, Optional -from .. import _serialization +from .._utils import serialization as _serialization class Error(_serialization.Model): diff --git a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/AzureReport/azurereport/operations/_auto_rest_report_service_for_azure_operations.py b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/AzureReport/azurereport/operations/_auto_rest_report_service_for_azure_operations.py index a9fa7b094f3..79260b059c2 100644 --- a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/AzureReport/azurereport/operations/_auto_rest_report_service_for_azure_operations.py +++ b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/AzureReport/azurereport/operations/_auto_rest_report_service_for_azure_operations.py @@ -8,6 +8,7 @@ from collections.abc import MutableMapping from typing import Any, Callable, Dict, Optional, TypeVar +from azure.core import PipelineClient from azure.core.exceptions import ( ClientAuthenticationError, HttpResponseError, @@ -22,8 +23,9 @@ from azure.core.utils import case_insensitive_dict from .. import models as _models -from .._serialization import Serializer -from .._vendor import AutoRestReportServiceForAzureMixinABC +from .._configuration import AutoRestReportServiceForAzureConfiguration +from .._utils.serialization import Serializer +from .._utils.utils import ClientMixinABC T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] @@ -52,7 +54,7 @@ def build_get_report_request(*, qualifier: Optional[str] = None, **kwargs: Any) class AutoRestReportServiceForAzureOperationsMixin( # pylint: disable=name-too-long - AutoRestReportServiceForAzureMixinABC + ClientMixinABC[PipelineClient, AutoRestReportServiceForAzureConfiguration] ): @distributed_trace diff --git a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/CustomPollerPager/custompollerpager/_auto_rest_paging_test_service.py b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/CustomPollerPager/custompollerpager/_auto_rest_paging_test_service.py index fb420ff7591..d1235311485 100644 --- a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/CustomPollerPager/custompollerpager/_auto_rest_paging_test_service.py +++ b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/CustomPollerPager/custompollerpager/_auto_rest_paging_test_service.py @@ -19,7 +19,7 @@ from . import models as _models from ._configuration import AutoRestPagingTestServiceConfiguration -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer from .operations import PagingOperations if TYPE_CHECKING: diff --git a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/CustomPollerPager/custompollerpager/_utils/__init__.py b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/CustomPollerPager/custompollerpager/_utils/__init__.py new file mode 100644 index 00000000000..0af9b28f660 --- /dev/null +++ b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/CustomPollerPager/custompollerpager/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/HeadExceptions/headexceptions/_serialization.py b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/CustomPollerPager/custompollerpager/_utils/serialization.py similarity index 100% rename from packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/HeadExceptions/headexceptions/_serialization.py rename to packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/CustomPollerPager/custompollerpager/_utils/serialization.py diff --git a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/CustomPollerPager/custompollerpager/aio/_auto_rest_paging_test_service.py b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/CustomPollerPager/custompollerpager/aio/_auto_rest_paging_test_service.py index 3674da2d379..31d7199c1a7 100644 --- a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/CustomPollerPager/custompollerpager/aio/_auto_rest_paging_test_service.py +++ b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/CustomPollerPager/custompollerpager/aio/_auto_rest_paging_test_service.py @@ -18,7 +18,7 @@ from azure.mgmt.core.tools import get_arm_endpoints from .. import models as _models -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import AutoRestPagingTestServiceConfiguration from .operations import PagingOperations diff --git a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/CustomPollerPager/custompollerpager/aio/operations/_paging_operations.py b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/CustomPollerPager/custompollerpager/aio/operations/_paging_operations.py index ea28c2568cf..7610af2f0c9 100644 --- a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/CustomPollerPager/custompollerpager/aio/operations/_paging_operations.py +++ b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/CustomPollerPager/custompollerpager/aio/operations/_paging_operations.py @@ -34,7 +34,7 @@ from azure.mgmt.core.polling.async_arm_polling import AsyncARMPolling from ... import models as _models -from ..._serialization import Deserializer, Serializer +from ..._utils.serialization import Deserializer, Serializer from ...operations._paging_operations import ( build_append_api_version_request, build_duplicate_params_request, diff --git a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/CustomPollerPager/custompollerpager/models/_models_py3.py b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/CustomPollerPager/custompollerpager/models/_models_py3.py index e661461d066..4b93c33b5c9 100644 --- a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/CustomPollerPager/custompollerpager/models/_models_py3.py +++ b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/CustomPollerPager/custompollerpager/models/_models_py3.py @@ -8,7 +8,7 @@ from typing import Any, List, Optional, TYPE_CHECKING, Union -from .. import _serialization +from .._utils import serialization as _serialization if TYPE_CHECKING: from .. import models as _models diff --git a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/CustomPollerPager/custompollerpager/operations/_paging_operations.py b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/CustomPollerPager/custompollerpager/operations/_paging_operations.py index 01bbdc1e781..281d4999cd2 100644 --- a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/CustomPollerPager/custompollerpager/operations/_paging_operations.py +++ b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/CustomPollerPager/custompollerpager/operations/_paging_operations.py @@ -34,7 +34,7 @@ from .. import models as _models from .._configuration import AutoRestPagingTestServiceConfiguration -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/CustomUrlPaging/custombaseurlpaging/_auto_rest_parameterized_host_test_paging_client.py b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/CustomUrlPaging/custombaseurlpaging/_auto_rest_parameterized_host_test_paging_client.py index d00b918e6d1..09d8154a67a 100644 --- a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/CustomUrlPaging/custombaseurlpaging/_auto_rest_parameterized_host_test_paging_client.py +++ b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/CustomUrlPaging/custombaseurlpaging/_auto_rest_parameterized_host_test_paging_client.py @@ -16,7 +16,7 @@ from . import models as _models from ._configuration import AutoRestParameterizedHostTestPagingClientConfiguration -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer from .operations import PagingOperations diff --git a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/CustomUrlPaging/custombaseurlpaging/_utils/__init__.py b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/CustomUrlPaging/custombaseurlpaging/_utils/__init__.py new file mode 100644 index 00000000000..0af9b28f660 --- /dev/null +++ b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/CustomUrlPaging/custombaseurlpaging/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/HeadWithAzureKeyCredentialPolicy/headwithazurekeycredentialpolicy/_serialization.py b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/CustomUrlPaging/custombaseurlpaging/_utils/serialization.py similarity index 100% rename from packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/HeadWithAzureKeyCredentialPolicy/headwithazurekeycredentialpolicy/_serialization.py rename to packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/CustomUrlPaging/custombaseurlpaging/_utils/serialization.py diff --git a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/CustomUrlPaging/custombaseurlpaging/aio/_auto_rest_parameterized_host_test_paging_client.py b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/CustomUrlPaging/custombaseurlpaging/aio/_auto_rest_parameterized_host_test_paging_client.py index c5ab02b0a5d..f1f554c5a80 100644 --- a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/CustomUrlPaging/custombaseurlpaging/aio/_auto_rest_parameterized_host_test_paging_client.py +++ b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/CustomUrlPaging/custombaseurlpaging/aio/_auto_rest_parameterized_host_test_paging_client.py @@ -15,7 +15,7 @@ from azure.core.rest import AsyncHttpResponse, HttpRequest from .. import models as _models -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import AutoRestParameterizedHostTestPagingClientConfiguration from .operations import PagingOperations diff --git a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/CustomUrlPaging/custombaseurlpaging/aio/operations/_paging_operations.py b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/CustomUrlPaging/custombaseurlpaging/aio/operations/_paging_operations.py index f610f88f962..cbfd9df60b0 100644 --- a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/CustomUrlPaging/custombaseurlpaging/aio/operations/_paging_operations.py +++ b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/CustomUrlPaging/custombaseurlpaging/aio/operations/_paging_operations.py @@ -23,7 +23,7 @@ from azure.core.tracing.decorator import distributed_trace from ... import models as _models -from ..._serialization import Deserializer, Serializer +from ..._utils.serialization import Deserializer, Serializer from ...operations._paging_operations import ( build_get_pages_partial_url_operation_next_request, build_get_pages_partial_url_operation_request, diff --git a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/CustomUrlPaging/custombaseurlpaging/models/_models_py3.py b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/CustomUrlPaging/custombaseurlpaging/models/_models_py3.py index fc88a8d66ac..9202f8a1c3a 100644 --- a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/CustomUrlPaging/custombaseurlpaging/models/_models_py3.py +++ b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/CustomUrlPaging/custombaseurlpaging/models/_models_py3.py @@ -8,7 +8,7 @@ from typing import Any, List, Optional, TYPE_CHECKING -from .. import _serialization +from .._utils import serialization as _serialization if TYPE_CHECKING: from .. import models as _models diff --git a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/CustomUrlPaging/custombaseurlpaging/operations/_paging_operations.py b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/CustomUrlPaging/custombaseurlpaging/operations/_paging_operations.py index c3666ceda30..158fcaeaaa8 100644 --- a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/CustomUrlPaging/custombaseurlpaging/operations/_paging_operations.py +++ b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/CustomUrlPaging/custombaseurlpaging/operations/_paging_operations.py @@ -25,7 +25,7 @@ from .. import models as _models from .._configuration import AutoRestParameterizedHostTestPagingClientConfiguration -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/Head/head/_auto_rest_head_test_service.py b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/Head/head/_auto_rest_head_test_service.py index 2f9f1bb11a7..9bf0f648fd8 100644 --- a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/Head/head/_auto_rest_head_test_service.py +++ b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/Head/head/_auto_rest_head_test_service.py @@ -18,7 +18,7 @@ from azure.mgmt.core.tools import get_arm_endpoints from ._configuration import AutoRestHeadTestServiceConfiguration -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer from .operations import HttpSuccessOperations if TYPE_CHECKING: diff --git a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/Head/head/_utils/__init__.py b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/Head/head/_utils/__init__.py new file mode 100644 index 00000000000..0af9b28f660 --- /dev/null +++ b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/Head/head/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/Lro/lro/_serialization.py b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/Head/head/_utils/serialization.py similarity index 100% rename from packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/Lro/lro/_serialization.py rename to packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/Head/head/_utils/serialization.py diff --git a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/Head/head/aio/_auto_rest_head_test_service.py b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/Head/head/aio/_auto_rest_head_test_service.py index 01fb623f1fc..0c23a5f2968 100644 --- a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/Head/head/aio/_auto_rest_head_test_service.py +++ b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/Head/head/aio/_auto_rest_head_test_service.py @@ -17,7 +17,7 @@ from azure.mgmt.core.policies import AsyncARMAutoResourceProviderRegistrationPolicy from azure.mgmt.core.tools import get_arm_endpoints -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import AutoRestHeadTestServiceConfiguration from .operations import HttpSuccessOperations diff --git a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/Head/head/aio/operations/_http_success_operations.py b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/Head/head/aio/operations/_http_success_operations.py index 683fccc3845..8a8ac7ca978 100644 --- a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/Head/head/aio/operations/_http_success_operations.py +++ b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/Head/head/aio/operations/_http_success_operations.py @@ -22,7 +22,7 @@ from azure.core.tracing.decorator_async import distributed_trace_async from azure.mgmt.core.exceptions import ARMErrorFormat -from ..._serialization import Deserializer, Serializer +from ..._utils.serialization import Deserializer, Serializer from ...operations._http_success_operations import build_head200_request, build_head204_request, build_head404_request from .._configuration import AutoRestHeadTestServiceConfiguration diff --git a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/Head/head/operations/_http_success_operations.py b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/Head/head/operations/_http_success_operations.py index dbeee656da3..d9c3113111f 100644 --- a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/Head/head/operations/_http_success_operations.py +++ b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/Head/head/operations/_http_success_operations.py @@ -23,7 +23,7 @@ from azure.mgmt.core.exceptions import ARMErrorFormat from .._configuration import AutoRestHeadTestServiceConfiguration -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/HeadExceptions/headexceptions/_auto_rest_head_exception_test_service.py b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/HeadExceptions/headexceptions/_auto_rest_head_exception_test_service.py index 4ed2c11c4d0..e55e2322b2d 100644 --- a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/HeadExceptions/headexceptions/_auto_rest_head_exception_test_service.py +++ b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/HeadExceptions/headexceptions/_auto_rest_head_exception_test_service.py @@ -18,7 +18,7 @@ from azure.mgmt.core.tools import get_arm_endpoints from ._configuration import AutoRestHeadExceptionTestServiceConfiguration -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer from .operations import HeadExceptionOperations if TYPE_CHECKING: diff --git a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/HeadExceptions/headexceptions/_utils/__init__.py b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/HeadExceptions/headexceptions/_utils/__init__.py new file mode 100644 index 00000000000..0af9b28f660 --- /dev/null +++ b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/HeadExceptions/headexceptions/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/LroWithParameterizedEndpoints/lrowithparameterizedendpoints/_serialization.py b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/HeadExceptions/headexceptions/_utils/serialization.py similarity index 100% rename from packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/LroWithParameterizedEndpoints/lrowithparameterizedendpoints/_serialization.py rename to packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/HeadExceptions/headexceptions/_utils/serialization.py diff --git a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/HeadExceptions/headexceptions/aio/_auto_rest_head_exception_test_service.py b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/HeadExceptions/headexceptions/aio/_auto_rest_head_exception_test_service.py index 6bade8d83b2..959410afb6d 100644 --- a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/HeadExceptions/headexceptions/aio/_auto_rest_head_exception_test_service.py +++ b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/HeadExceptions/headexceptions/aio/_auto_rest_head_exception_test_service.py @@ -17,7 +17,7 @@ from azure.mgmt.core.policies import AsyncARMAutoResourceProviderRegistrationPolicy from azure.mgmt.core.tools import get_arm_endpoints -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import AutoRestHeadExceptionTestServiceConfiguration from .operations import HeadExceptionOperations diff --git a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/HeadExceptions/headexceptions/aio/operations/_head_exception_operations.py b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/HeadExceptions/headexceptions/aio/operations/_head_exception_operations.py index 20ccaf5cbc2..64c06dcada9 100644 --- a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/HeadExceptions/headexceptions/aio/operations/_head_exception_operations.py +++ b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/HeadExceptions/headexceptions/aio/operations/_head_exception_operations.py @@ -22,7 +22,7 @@ from azure.core.tracing.decorator_async import distributed_trace_async from azure.mgmt.core.exceptions import ARMErrorFormat -from ..._serialization import Deserializer, Serializer +from ..._utils.serialization import Deserializer, Serializer from ...operations._head_exception_operations import build_head200_request, build_head204_request, build_head404_request from .._configuration import AutoRestHeadExceptionTestServiceConfiguration diff --git a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/HeadExceptions/headexceptions/operations/_head_exception_operations.py b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/HeadExceptions/headexceptions/operations/_head_exception_operations.py index 0908aa418f3..6728043e94e 100644 --- a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/HeadExceptions/headexceptions/operations/_head_exception_operations.py +++ b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/HeadExceptions/headexceptions/operations/_head_exception_operations.py @@ -23,7 +23,7 @@ from azure.mgmt.core.exceptions import ARMErrorFormat from .._configuration import AutoRestHeadExceptionTestServiceConfiguration -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/HeadWithAzureKeyCredentialPolicy/headwithazurekeycredentialpolicy/_auto_rest_head_test_service.py b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/HeadWithAzureKeyCredentialPolicy/headwithazurekeycredentialpolicy/_auto_rest_head_test_service.py index b3adf5c2cde..ea1911e90c1 100644 --- a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/HeadWithAzureKeyCredentialPolicy/headwithazurekeycredentialpolicy/_auto_rest_head_test_service.py +++ b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/HeadWithAzureKeyCredentialPolicy/headwithazurekeycredentialpolicy/_auto_rest_head_test_service.py @@ -17,7 +17,7 @@ from azure.mgmt.core.policies import ARMAutoResourceProviderRegistrationPolicy from ._configuration import AutoRestHeadTestServiceConfiguration -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer from .operations import HttpSuccessOperations diff --git a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/HeadWithAzureKeyCredentialPolicy/headwithazurekeycredentialpolicy/_utils/__init__.py b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/HeadWithAzureKeyCredentialPolicy/headwithazurekeycredentialpolicy/_utils/__init__.py new file mode 100644 index 00000000000..0af9b28f660 --- /dev/null +++ b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/HeadWithAzureKeyCredentialPolicy/headwithazurekeycredentialpolicy/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/MixedApiVersion/mixedapiversion/_serialization.py b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/HeadWithAzureKeyCredentialPolicy/headwithazurekeycredentialpolicy/_utils/serialization.py similarity index 100% rename from packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/MixedApiVersion/mixedapiversion/_serialization.py rename to packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/HeadWithAzureKeyCredentialPolicy/headwithazurekeycredentialpolicy/_utils/serialization.py diff --git a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/HeadWithAzureKeyCredentialPolicy/headwithazurekeycredentialpolicy/aio/_auto_rest_head_test_service.py b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/HeadWithAzureKeyCredentialPolicy/headwithazurekeycredentialpolicy/aio/_auto_rest_head_test_service.py index 2d4a857aa37..e93bb15e676 100644 --- a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/HeadWithAzureKeyCredentialPolicy/headwithazurekeycredentialpolicy/aio/_auto_rest_head_test_service.py +++ b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/HeadWithAzureKeyCredentialPolicy/headwithazurekeycredentialpolicy/aio/_auto_rest_head_test_service.py @@ -16,7 +16,7 @@ from azure.mgmt.core import AsyncARMPipelineClient from azure.mgmt.core.policies import AsyncARMAutoResourceProviderRegistrationPolicy -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import AutoRestHeadTestServiceConfiguration from .operations import HttpSuccessOperations diff --git a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/HeadWithAzureKeyCredentialPolicy/headwithazurekeycredentialpolicy/aio/operations/_http_success_operations.py b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/HeadWithAzureKeyCredentialPolicy/headwithazurekeycredentialpolicy/aio/operations/_http_success_operations.py index e8566562bb9..64150e9413a 100644 --- a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/HeadWithAzureKeyCredentialPolicy/headwithazurekeycredentialpolicy/aio/operations/_http_success_operations.py +++ b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/HeadWithAzureKeyCredentialPolicy/headwithazurekeycredentialpolicy/aio/operations/_http_success_operations.py @@ -22,7 +22,7 @@ from azure.core.tracing.decorator_async import distributed_trace_async from azure.mgmt.core.exceptions import ARMErrorFormat -from ..._serialization import Deserializer, Serializer +from ..._utils.serialization import Deserializer, Serializer from ...operations._http_success_operations import build_head200_request, build_head204_request, build_head404_request from .._configuration import AutoRestHeadTestServiceConfiguration diff --git a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/HeadWithAzureKeyCredentialPolicy/headwithazurekeycredentialpolicy/operations/_http_success_operations.py b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/HeadWithAzureKeyCredentialPolicy/headwithazurekeycredentialpolicy/operations/_http_success_operations.py index da1fc1af1e8..ab23e949bda 100644 --- a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/HeadWithAzureKeyCredentialPolicy/headwithazurekeycredentialpolicy/operations/_http_success_operations.py +++ b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/HeadWithAzureKeyCredentialPolicy/headwithazurekeycredentialpolicy/operations/_http_success_operations.py @@ -23,7 +23,7 @@ from azure.mgmt.core.exceptions import ARMErrorFormat from .._configuration import AutoRestHeadTestServiceConfiguration -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/Lro/lro/_auto_rest_long_running_operation_test_service.py b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/Lro/lro/_auto_rest_long_running_operation_test_service.py index 63b94d91f3e..20d4e28ddd8 100644 --- a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/Lro/lro/_auto_rest_long_running_operation_test_service.py +++ b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/Lro/lro/_auto_rest_long_running_operation_test_service.py @@ -19,7 +19,7 @@ from . import models as _models from ._configuration import AutoRestLongRunningOperationTestServiceConfiguration -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer from .operations import LRORetrysOperations, LROSADsOperations, LROsCustomHeaderOperations, LROsOperations if TYPE_CHECKING: diff --git a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/Lro/lro/_utils/__init__.py b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/Lro/lro/_utils/__init__.py new file mode 100644 index 00000000000..0af9b28f660 --- /dev/null +++ b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/Lro/lro/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/Paging/paging/_serialization.py b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/Lro/lro/_utils/serialization.py similarity index 100% rename from packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/Paging/paging/_serialization.py rename to packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/Lro/lro/_utils/serialization.py diff --git a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/Lro/lro/aio/_auto_rest_long_running_operation_test_service.py b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/Lro/lro/aio/_auto_rest_long_running_operation_test_service.py index bc315631e70..f255bc9ed3f 100644 --- a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/Lro/lro/aio/_auto_rest_long_running_operation_test_service.py +++ b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/Lro/lro/aio/_auto_rest_long_running_operation_test_service.py @@ -18,7 +18,7 @@ from azure.mgmt.core.tools import get_arm_endpoints from .. import models as _models -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import AutoRestLongRunningOperationTestServiceConfiguration from .operations import LRORetrysOperations, LROSADsOperations, LROsCustomHeaderOperations, LROsOperations diff --git a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/Lro/lro/aio/operations/_lr_os_custom_header_operations.py b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/Lro/lro/aio/operations/_lr_os_custom_header_operations.py index a5f7ea07137..292a1db6fd1 100644 --- a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/Lro/lro/aio/operations/_lr_os_custom_header_operations.py +++ b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/Lro/lro/aio/operations/_lr_os_custom_header_operations.py @@ -29,7 +29,7 @@ from azure.mgmt.core.polling.async_arm_polling import AsyncARMPolling from ... import models as _models -from ..._serialization import Deserializer, Serializer +from ..._utils.serialization import Deserializer, Serializer from ...operations._lr_os_custom_header_operations import ( build_post202_retry200_request, build_post_async_retry_succeeded_request, diff --git a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/Lro/lro/aio/operations/_lro_retrys_operations.py b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/Lro/lro/aio/operations/_lro_retrys_operations.py index 85dc9ef4079..cad56f5b27f 100644 --- a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/Lro/lro/aio/operations/_lro_retrys_operations.py +++ b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/Lro/lro/aio/operations/_lro_retrys_operations.py @@ -29,7 +29,7 @@ from azure.mgmt.core.polling.async_arm_polling import AsyncARMPolling from ... import models as _models -from ..._serialization import Deserializer, Serializer +from ..._utils.serialization import Deserializer, Serializer from ...operations._lro_retrys_operations import ( build_delete202_retry200_request, build_delete_async_relative_retry_succeeded_request, diff --git a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/Lro/lro/aio/operations/_lros_operations.py b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/Lro/lro/aio/operations/_lros_operations.py index 9d78fbf6112..9368bd50e24 100644 --- a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/Lro/lro/aio/operations/_lros_operations.py +++ b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/Lro/lro/aio/operations/_lros_operations.py @@ -30,7 +30,7 @@ from azure.mgmt.core.polling.async_arm_polling import AsyncARMPolling from ... import models as _models -from ..._serialization import Deserializer, Serializer +from ..._utils.serialization import Deserializer, Serializer from ...operations._lros_operations import ( build_delete202_no_retry204_request, build_delete202_retry200_request, diff --git a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/Lro/lro/aio/operations/_lrosads_operations.py b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/Lro/lro/aio/operations/_lrosads_operations.py index f83f5d35508..3c2d4bd04a4 100644 --- a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/Lro/lro/aio/operations/_lrosads_operations.py +++ b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/Lro/lro/aio/operations/_lrosads_operations.py @@ -30,7 +30,7 @@ from azure.mgmt.core.polling.async_arm_polling import AsyncARMPolling from ... import models as _models -from ..._serialization import Deserializer, Serializer +from ..._utils.serialization import Deserializer, Serializer from ...operations._lrosads_operations import ( build_delete202_non_retry400_request, build_delete202_retry_invalid_header_request, diff --git a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/Lro/lro/models/_models_py3.py b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/Lro/lro/models/_models_py3.py index 2c47307e8be..3b2e9443b08 100644 --- a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/Lro/lro/models/_models_py3.py +++ b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/Lro/lro/models/_models_py3.py @@ -8,7 +8,7 @@ from typing import Any, Dict, Optional, TYPE_CHECKING, Union -from .. import _serialization +from .._utils import serialization as _serialization if TYPE_CHECKING: from .. import models as _models diff --git a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/Lro/lro/operations/_lr_os_custom_header_operations.py b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/Lro/lro/operations/_lr_os_custom_header_operations.py index cfdd919c8e3..43235cc0e76 100644 --- a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/Lro/lro/operations/_lr_os_custom_header_operations.py +++ b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/Lro/lro/operations/_lr_os_custom_header_operations.py @@ -30,7 +30,7 @@ from .. import models as _models from .._configuration import AutoRestLongRunningOperationTestServiceConfiguration -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/Lro/lro/operations/_lro_retrys_operations.py b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/Lro/lro/operations/_lro_retrys_operations.py index 1de5747d190..faf642c85c6 100644 --- a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/Lro/lro/operations/_lro_retrys_operations.py +++ b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/Lro/lro/operations/_lro_retrys_operations.py @@ -31,7 +31,7 @@ from .. import models as _models from .._configuration import AutoRestLongRunningOperationTestServiceConfiguration -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/Lro/lro/operations/_lros_operations.py b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/Lro/lro/operations/_lros_operations.py index 8853a2fa182..29ca0584c83 100644 --- a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/Lro/lro/operations/_lros_operations.py +++ b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/Lro/lro/operations/_lros_operations.py @@ -31,7 +31,7 @@ from .. import models as _models from .._configuration import AutoRestLongRunningOperationTestServiceConfiguration -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/Lro/lro/operations/_lrosads_operations.py b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/Lro/lro/operations/_lrosads_operations.py index 67152a0ba14..24938e2baa9 100644 --- a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/Lro/lro/operations/_lrosads_operations.py +++ b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/Lro/lro/operations/_lrosads_operations.py @@ -31,7 +31,7 @@ from .. import models as _models from .._configuration import AutoRestLongRunningOperationTestServiceConfiguration -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/LroWithParameterizedEndpoints/lrowithparameterizedendpoints/_lro_with_paramaterized_endpoints.py b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/LroWithParameterizedEndpoints/lrowithparameterizedendpoints/_lro_with_paramaterized_endpoints.py index fef384ecb49..f2585f5b1c0 100644 --- a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/LroWithParameterizedEndpoints/lrowithparameterizedendpoints/_lro_with_paramaterized_endpoints.py +++ b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/LroWithParameterizedEndpoints/lrowithparameterizedendpoints/_lro_with_paramaterized_endpoints.py @@ -16,7 +16,7 @@ from . import models as _models from ._configuration import LROWithParamaterizedEndpointsConfiguration -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer from .operations import LROWithParamaterizedEndpointsOperationsMixin diff --git a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/LroWithParameterizedEndpoints/lrowithparameterizedendpoints/_utils/__init__.py b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/LroWithParameterizedEndpoints/lrowithparameterizedendpoints/_utils/__init__.py new file mode 100644 index 00000000000..0af9b28f660 --- /dev/null +++ b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/LroWithParameterizedEndpoints/lrowithparameterizedendpoints/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/SecurityAadSwagger/securityaadswagger/_serialization.py b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/LroWithParameterizedEndpoints/lrowithparameterizedendpoints/_utils/serialization.py similarity index 100% rename from packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/SecurityAadSwagger/securityaadswagger/_serialization.py rename to packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/LroWithParameterizedEndpoints/lrowithparameterizedendpoints/_utils/serialization.py diff --git a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/LroWithParameterizedEndpoints/lrowithparameterizedendpoints/_utils/utils.py b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/LroWithParameterizedEndpoints/lrowithparameterizedendpoints/_utils/utils.py new file mode 100644 index 00000000000..39b612f39a9 --- /dev/null +++ b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/LroWithParameterizedEndpoints/lrowithparameterizedendpoints/_utils/utils.py @@ -0,0 +1,25 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from abc import ABC +from typing import Generic, TYPE_CHECKING, TypeVar + +if TYPE_CHECKING: + from .serialization import Deserializer, Serializer + + +TClient = TypeVar("TClient") +TConfig = TypeVar("TConfig") + + +class ClientMixinABC(ABC, Generic[TClient, TConfig]): + """DO NOT use this class. It is for internal typing use only.""" + + _client: TClient + _config: TConfig + _serialize: "Serializer" + _deserialize: "Deserializer" diff --git a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/LroWithParameterizedEndpoints/lrowithparameterizedendpoints/_vendor.py b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/LroWithParameterizedEndpoints/lrowithparameterizedendpoints/_vendor.py deleted file mode 100644 index fcf80212404..00000000000 --- a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/LroWithParameterizedEndpoints/lrowithparameterizedendpoints/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) AutoRest Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import LROWithParamaterizedEndpointsConfiguration - -if TYPE_CHECKING: - from azure.core import PipelineClient - - from ._serialization import Deserializer, Serializer - - -class LROWithParamaterizedEndpointsMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "PipelineClient" - _config: LROWithParamaterizedEndpointsConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/LroWithParameterizedEndpoints/lrowithparameterizedendpoints/aio/_lro_with_paramaterized_endpoints.py b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/LroWithParameterizedEndpoints/lrowithparameterizedendpoints/aio/_lro_with_paramaterized_endpoints.py index bc6f394cfa5..e080274a996 100644 --- a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/LroWithParameterizedEndpoints/lrowithparameterizedendpoints/aio/_lro_with_paramaterized_endpoints.py +++ b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/LroWithParameterizedEndpoints/lrowithparameterizedendpoints/aio/_lro_with_paramaterized_endpoints.py @@ -15,7 +15,7 @@ from azure.core.rest import AsyncHttpResponse, HttpRequest from .. import models as _models -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import LROWithParamaterizedEndpointsConfiguration from .operations import LROWithParamaterizedEndpointsOperationsMixin diff --git a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/LroWithParameterizedEndpoints/lrowithparameterizedendpoints/aio/_vendor.py b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/LroWithParameterizedEndpoints/lrowithparameterizedendpoints/aio/_vendor.py deleted file mode 100644 index 65404a7e264..00000000000 --- a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/LroWithParameterizedEndpoints/lrowithparameterizedendpoints/aio/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) AutoRest Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import LROWithParamaterizedEndpointsConfiguration - -if TYPE_CHECKING: - from azure.core import AsyncPipelineClient - - from .._serialization import Deserializer, Serializer - - -class LROWithParamaterizedEndpointsMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "AsyncPipelineClient" - _config: LROWithParamaterizedEndpointsConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/LroWithParameterizedEndpoints/lrowithparameterizedendpoints/aio/operations/_lro_with_paramaterized_endpoints_operations.py b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/LroWithParameterizedEndpoints/lrowithparameterizedendpoints/aio/operations/_lro_with_paramaterized_endpoints_operations.py index 694d6f9b233..0693baa39f3 100644 --- a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/LroWithParameterizedEndpoints/lrowithparameterizedendpoints/aio/operations/_lro_with_paramaterized_endpoints_operations.py +++ b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/LroWithParameterizedEndpoints/lrowithparameterizedendpoints/aio/operations/_lro_with_paramaterized_endpoints_operations.py @@ -9,6 +9,7 @@ from collections.abc import MutableMapping from typing import Any, AsyncIterator, Callable, Dict, Literal, Optional, TypeVar, Union, cast +from azure.core import AsyncPipelineClient from azure.core.exceptions import ( ClientAuthenticationError, HttpResponseError, @@ -26,18 +27,19 @@ from azure.core.tracing.decorator_async import distributed_trace_async from ... import models as _models +from ..._utils.utils import ClientMixinABC from ...operations._lro_with_paramaterized_endpoints_operations import ( build_poll_with_constant_parameterized_endpoints_request, build_poll_with_parameterized_endpoints_request, ) -from .._vendor import LROWithParamaterizedEndpointsMixinABC +from .._configuration import LROWithParamaterizedEndpointsConfiguration T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, AsyncHttpResponse], T, Dict[str, Any]], Any]] class LROWithParamaterizedEndpointsOperationsMixin( # pylint: disable=name-too-long - LROWithParamaterizedEndpointsMixinABC + ClientMixinABC[AsyncPipelineClient, LROWithParamaterizedEndpointsConfiguration] ): async def _poll_with_parameterized_endpoints_initial( # pylint: disable=name-too-long diff --git a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/LroWithParameterizedEndpoints/lrowithparameterizedendpoints/models/_models_py3.py b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/LroWithParameterizedEndpoints/lrowithparameterizedendpoints/models/_models_py3.py index 1d1b7707def..109cf147510 100644 --- a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/LroWithParameterizedEndpoints/lrowithparameterizedendpoints/models/_models_py3.py +++ b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/LroWithParameterizedEndpoints/lrowithparameterizedendpoints/models/_models_py3.py @@ -8,7 +8,7 @@ from typing import Any, Optional -from .. import _serialization +from .._utils import serialization as _serialization class Error(_serialization.Model): diff --git a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/LroWithParameterizedEndpoints/lrowithparameterizedendpoints/operations/_lro_with_paramaterized_endpoints_operations.py b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/LroWithParameterizedEndpoints/lrowithparameterizedendpoints/operations/_lro_with_paramaterized_endpoints_operations.py index 927cd193a01..ded37832c7b 100644 --- a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/LroWithParameterizedEndpoints/lrowithparameterizedendpoints/operations/_lro_with_paramaterized_endpoints_operations.py +++ b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/LroWithParameterizedEndpoints/lrowithparameterizedendpoints/operations/_lro_with_paramaterized_endpoints_operations.py @@ -8,6 +8,7 @@ from collections.abc import MutableMapping from typing import Any, Callable, Dict, Iterator, Literal, Optional, TypeVar, Union, cast +from azure.core import PipelineClient from azure.core.exceptions import ( ClientAuthenticationError, HttpResponseError, @@ -26,8 +27,9 @@ from azure.core.utils import case_insensitive_dict from .. import models as _models -from .._serialization import Serializer -from .._vendor import LROWithParamaterizedEndpointsMixinABC +from .._configuration import LROWithParamaterizedEndpointsConfiguration +from .._utils.serialization import Serializer +from .._utils.utils import ClientMixinABC T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] @@ -73,7 +75,7 @@ def build_poll_with_constant_parameterized_endpoints_request( # pylint: disable class LROWithParamaterizedEndpointsOperationsMixin( # pylint: disable=name-too-long - LROWithParamaterizedEndpointsMixinABC + ClientMixinABC[PipelineClient, LROWithParamaterizedEndpointsConfiguration] ): def _poll_with_parameterized_endpoints_initial( # pylint: disable=name-too-long diff --git a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/MixedApiVersion/mixedapiversion/_mixed_api_version_client.py b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/MixedApiVersion/mixedapiversion/_mixed_api_version_client.py index 6146344883d..3cd26ec240d 100644 --- a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/MixedApiVersion/mixedapiversion/_mixed_api_version_client.py +++ b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/MixedApiVersion/mixedapiversion/_mixed_api_version_client.py @@ -16,7 +16,7 @@ from . import models as _models from ._configuration import MixedApiVersionClientConfiguration -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer from .operations import ( ApiVersionDefaultOperations, ApiVersionLocalOperations, diff --git a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/MixedApiVersion/mixedapiversion/_utils/__init__.py b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/MixedApiVersion/mixedapiversion/_utils/__init__.py new file mode 100644 index 00000000000..0af9b28f660 --- /dev/null +++ b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/MixedApiVersion/mixedapiversion/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/SecurityKeySwagger/securitykeyswagger/_serialization.py b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/MixedApiVersion/mixedapiversion/_utils/serialization.py similarity index 100% rename from packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/SecurityKeySwagger/securitykeyswagger/_serialization.py rename to packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/MixedApiVersion/mixedapiversion/_utils/serialization.py diff --git a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/MixedApiVersion/mixedapiversion/aio/_mixed_api_version_client.py b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/MixedApiVersion/mixedapiversion/aio/_mixed_api_version_client.py index d70a052ad6d..9607a275dd6 100644 --- a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/MixedApiVersion/mixedapiversion/aio/_mixed_api_version_client.py +++ b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/MixedApiVersion/mixedapiversion/aio/_mixed_api_version_client.py @@ -15,7 +15,7 @@ from azure.core.rest import AsyncHttpResponse, HttpRequest from .. import models as _models -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import MixedApiVersionClientConfiguration from .operations import ( ApiVersionDefaultOperations, diff --git a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/MixedApiVersion/mixedapiversion/aio/operations/_api_version_default_operations.py b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/MixedApiVersion/mixedapiversion/aio/operations/_api_version_default_operations.py index c98cb589314..4b6ddacce93 100644 --- a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/MixedApiVersion/mixedapiversion/aio/operations/_api_version_default_operations.py +++ b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/MixedApiVersion/mixedapiversion/aio/operations/_api_version_default_operations.py @@ -23,7 +23,7 @@ from azure.core.utils import case_insensitive_dict from ... import models as _models -from ..._serialization import Deserializer, Serializer +from ..._utils.serialization import Deserializer, Serializer from ...operations._api_version_default_operations import ( build_get_method_global_not_provided_valid_request, build_get_method_global_valid_request, diff --git a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/MixedApiVersion/mixedapiversion/aio/operations/_api_version_local_operations.py b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/MixedApiVersion/mixedapiversion/aio/operations/_api_version_local_operations.py index e7fb47c4f9a..e55e44c4c98 100644 --- a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/MixedApiVersion/mixedapiversion/aio/operations/_api_version_local_operations.py +++ b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/MixedApiVersion/mixedapiversion/aio/operations/_api_version_local_operations.py @@ -23,7 +23,7 @@ from azure.core.utils import case_insensitive_dict from ... import models as _models -from ..._serialization import Deserializer, Serializer +from ..._utils.serialization import Deserializer, Serializer from ...operations._api_version_local_operations import ( build_get_method_local_null_request, build_get_method_local_valid_request, diff --git a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/MixedApiVersion/mixedapiversion/aio/operations/_header_operations.py b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/MixedApiVersion/mixedapiversion/aio/operations/_header_operations.py index 80de605c3f5..1bbafc405c1 100644 --- a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/MixedApiVersion/mixedapiversion/aio/operations/_header_operations.py +++ b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/MixedApiVersion/mixedapiversion/aio/operations/_header_operations.py @@ -23,7 +23,7 @@ from azure.core.tracing.decorator_async import distributed_trace_async from ... import models as _models -from ..._serialization import Deserializer, Serializer +from ..._utils.serialization import Deserializer, Serializer from ...operations._header_operations import ( build_custom_named_request_id_head_request, build_custom_named_request_id_param_grouping_request, diff --git a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/MixedApiVersion/mixedapiversion/aio/operations/_http_success_operations.py b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/MixedApiVersion/mixedapiversion/aio/operations/_http_success_operations.py index e2e0e8fd356..1d3b2c3fffd 100644 --- a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/MixedApiVersion/mixedapiversion/aio/operations/_http_success_operations.py +++ b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/MixedApiVersion/mixedapiversion/aio/operations/_http_success_operations.py @@ -22,7 +22,7 @@ from azure.core.tracing.decorator_async import distributed_trace_async from ... import models as _models -from ..._serialization import Deserializer, Serializer +from ..._utils.serialization import Deserializer, Serializer from ...operations._http_success_operations import build_head200_request, build_head204_request, build_head404_request from .._configuration import MixedApiVersionClientConfiguration diff --git a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/MixedApiVersion/mixedapiversion/aio/operations/_odata_operations.py b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/MixedApiVersion/mixedapiversion/aio/operations/_odata_operations.py index 1cf29418daa..c3db3cc5ed0 100644 --- a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/MixedApiVersion/mixedapiversion/aio/operations/_odata_operations.py +++ b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/MixedApiVersion/mixedapiversion/aio/operations/_odata_operations.py @@ -22,7 +22,7 @@ from azure.core.tracing.decorator_async import distributed_trace_async from ... import models as _models -from ..._serialization import Deserializer, Serializer +from ..._utils.serialization import Deserializer, Serializer from ...operations._odata_operations import build_get_with_filter_request from .._configuration import MixedApiVersionClientConfiguration diff --git a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/MixedApiVersion/mixedapiversion/aio/operations/_skip_url_encoding_operations.py b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/MixedApiVersion/mixedapiversion/aio/operations/_skip_url_encoding_operations.py index 9e157e48bce..e02888a1970 100644 --- a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/MixedApiVersion/mixedapiversion/aio/operations/_skip_url_encoding_operations.py +++ b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/MixedApiVersion/mixedapiversion/aio/operations/_skip_url_encoding_operations.py @@ -23,7 +23,7 @@ from azure.core.utils import case_insensitive_dict from ... import models as _models -from ..._serialization import Deserializer, Serializer +from ..._utils.serialization import Deserializer, Serializer from ...operations._skip_url_encoding_operations import ( build_get_method_path_valid_request, build_get_method_query_null_request, diff --git a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/MixedApiVersion/mixedapiversion/aio/operations/_subscription_in_credentials_operations.py b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/MixedApiVersion/mixedapiversion/aio/operations/_subscription_in_credentials_operations.py index 268dac4f9d8..abe5af69988 100644 --- a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/MixedApiVersion/mixedapiversion/aio/operations/_subscription_in_credentials_operations.py +++ b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/MixedApiVersion/mixedapiversion/aio/operations/_subscription_in_credentials_operations.py @@ -23,7 +23,7 @@ from azure.core.utils import case_insensitive_dict from ... import models as _models -from ..._serialization import Deserializer, Serializer +from ..._utils.serialization import Deserializer, Serializer from ...operations._subscription_in_credentials_operations import ( build_post_method_global_not_provided_valid_request, build_post_method_global_null_request, diff --git a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/MixedApiVersion/mixedapiversion/aio/operations/_subscription_in_method_operations.py b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/MixedApiVersion/mixedapiversion/aio/operations/_subscription_in_method_operations.py index 99f108f0f11..242bc65e81a 100644 --- a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/MixedApiVersion/mixedapiversion/aio/operations/_subscription_in_method_operations.py +++ b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/MixedApiVersion/mixedapiversion/aio/operations/_subscription_in_method_operations.py @@ -22,7 +22,7 @@ from azure.core.tracing.decorator_async import distributed_trace_async from ... import models as _models -from ..._serialization import Deserializer, Serializer +from ..._utils.serialization import Deserializer, Serializer from ...operations._subscription_in_method_operations import ( build_post_method_local_null_request, build_post_method_local_valid_request, diff --git a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/MixedApiVersion/mixedapiversion/aio/operations/_xms_client_request_id_operations.py b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/MixedApiVersion/mixedapiversion/aio/operations/_xms_client_request_id_operations.py index 250dd59a106..48c0c4adba4 100644 --- a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/MixedApiVersion/mixedapiversion/aio/operations/_xms_client_request_id_operations.py +++ b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/MixedApiVersion/mixedapiversion/aio/operations/_xms_client_request_id_operations.py @@ -22,7 +22,7 @@ from azure.core.tracing.decorator_async import distributed_trace_async from ... import models as _models -from ..._serialization import Deserializer, Serializer +from ..._utils.serialization import Deserializer, Serializer from ...operations._xms_client_request_id_operations import build_get_request, build_param_get_request from .._configuration import MixedApiVersionClientConfiguration diff --git a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/MixedApiVersion/mixedapiversion/models/_models_py3.py b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/MixedApiVersion/mixedapiversion/models/_models_py3.py index ec9deec55aa..321e7bee115 100644 --- a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/MixedApiVersion/mixedapiversion/models/_models_py3.py +++ b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/MixedApiVersion/mixedapiversion/models/_models_py3.py @@ -8,7 +8,7 @@ from typing import Any, Optional -from .. import _serialization +from .._utils import serialization as _serialization class Error(_serialization.Model): diff --git a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/MixedApiVersion/mixedapiversion/operations/_api_version_default_operations.py b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/MixedApiVersion/mixedapiversion/operations/_api_version_default_operations.py index e01a0b4bccc..ec11e20bde0 100644 --- a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/MixedApiVersion/mixedapiversion/operations/_api_version_default_operations.py +++ b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/MixedApiVersion/mixedapiversion/operations/_api_version_default_operations.py @@ -24,7 +24,7 @@ from .. import models as _models from .._configuration import MixedApiVersionClientConfiguration -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/MixedApiVersion/mixedapiversion/operations/_api_version_local_operations.py b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/MixedApiVersion/mixedapiversion/operations/_api_version_local_operations.py index 3e3c6fbe12a..2a6386802f1 100644 --- a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/MixedApiVersion/mixedapiversion/operations/_api_version_local_operations.py +++ b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/MixedApiVersion/mixedapiversion/operations/_api_version_local_operations.py @@ -24,7 +24,7 @@ from .. import models as _models from .._configuration import MixedApiVersionClientConfiguration -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/MixedApiVersion/mixedapiversion/operations/_header_operations.py b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/MixedApiVersion/mixedapiversion/operations/_header_operations.py index 49ff15c0aff..1d051285b06 100644 --- a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/MixedApiVersion/mixedapiversion/operations/_header_operations.py +++ b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/MixedApiVersion/mixedapiversion/operations/_header_operations.py @@ -25,7 +25,7 @@ from .. import models as _models from .._configuration import MixedApiVersionClientConfiguration -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/MixedApiVersion/mixedapiversion/operations/_http_success_operations.py b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/MixedApiVersion/mixedapiversion/operations/_http_success_operations.py index 9a737ea6884..3f44d1b360c 100644 --- a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/MixedApiVersion/mixedapiversion/operations/_http_success_operations.py +++ b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/MixedApiVersion/mixedapiversion/operations/_http_success_operations.py @@ -23,7 +23,7 @@ from .. import models as _models from .._configuration import MixedApiVersionClientConfiguration -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/MixedApiVersion/mixedapiversion/operations/_odata_operations.py b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/MixedApiVersion/mixedapiversion/operations/_odata_operations.py index 2544debc817..9a22dbcb620 100644 --- a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/MixedApiVersion/mixedapiversion/operations/_odata_operations.py +++ b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/MixedApiVersion/mixedapiversion/operations/_odata_operations.py @@ -24,7 +24,7 @@ from .. import models as _models from .._configuration import MixedApiVersionClientConfiguration -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/MixedApiVersion/mixedapiversion/operations/_skip_url_encoding_operations.py b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/MixedApiVersion/mixedapiversion/operations/_skip_url_encoding_operations.py index 2d6b0e9717b..f9799ad8443 100644 --- a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/MixedApiVersion/mixedapiversion/operations/_skip_url_encoding_operations.py +++ b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/MixedApiVersion/mixedapiversion/operations/_skip_url_encoding_operations.py @@ -24,7 +24,7 @@ from .. import models as _models from .._configuration import MixedApiVersionClientConfiguration -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/MixedApiVersion/mixedapiversion/operations/_subscription_in_credentials_operations.py b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/MixedApiVersion/mixedapiversion/operations/_subscription_in_credentials_operations.py index aad12194069..44d07d043a2 100644 --- a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/MixedApiVersion/mixedapiversion/operations/_subscription_in_credentials_operations.py +++ b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/MixedApiVersion/mixedapiversion/operations/_subscription_in_credentials_operations.py @@ -24,7 +24,7 @@ from .. import models as _models from .._configuration import MixedApiVersionClientConfiguration -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/MixedApiVersion/mixedapiversion/operations/_subscription_in_method_operations.py b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/MixedApiVersion/mixedapiversion/operations/_subscription_in_method_operations.py index 81f5934acd8..d56856cbf24 100644 --- a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/MixedApiVersion/mixedapiversion/operations/_subscription_in_method_operations.py +++ b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/MixedApiVersion/mixedapiversion/operations/_subscription_in_method_operations.py @@ -24,7 +24,7 @@ from .. import models as _models from .._configuration import MixedApiVersionClientConfiguration -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/MixedApiVersion/mixedapiversion/operations/_xms_client_request_id_operations.py b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/MixedApiVersion/mixedapiversion/operations/_xms_client_request_id_operations.py index de7097ac3be..0fcf156e9d4 100644 --- a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/MixedApiVersion/mixedapiversion/operations/_xms_client_request_id_operations.py +++ b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/MixedApiVersion/mixedapiversion/operations/_xms_client_request_id_operations.py @@ -24,7 +24,7 @@ from .. import models as _models from .._configuration import MixedApiVersionClientConfiguration -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/PackageModeBatch/azure/packagemode/batch/head/_head_client.py b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/PackageModeBatch/azure/packagemode/batch/head/_head_client.py index 16f04758741..1e2c2ac4474 100644 --- a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/PackageModeBatch/azure/packagemode/batch/head/_head_client.py +++ b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/PackageModeBatch/azure/packagemode/batch/head/_head_client.py @@ -18,7 +18,7 @@ from azure.mgmt.core.tools import get_arm_endpoints from ._configuration import HeadClientConfiguration -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer from .operations import HttpSuccessOperations if TYPE_CHECKING: diff --git a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/PackageModeBatch/azure/packagemode/batch/head/_utils/__init__.py b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/PackageModeBatch/azure/packagemode/batch/head/_utils/__init__.py new file mode 100644 index 00000000000..0af9b28f660 --- /dev/null +++ b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/PackageModeBatch/azure/packagemode/batch/head/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/StorageManagementClient/storage/_serialization.py b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/PackageModeBatch/azure/packagemode/batch/head/_utils/serialization.py similarity index 100% rename from packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/StorageManagementClient/storage/_serialization.py rename to packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/PackageModeBatch/azure/packagemode/batch/head/_utils/serialization.py diff --git a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/PackageModeBatch/azure/packagemode/batch/head/_vendor/__init__.py b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/PackageModeBatch/azure/packagemode/batch/head/_vendor/__init__.py new file mode 100644 index 00000000000..0af9b28f660 --- /dev/null +++ b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/PackageModeBatch/azure/packagemode/batch/head/_vendor/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/SubscriptionIdApiVersion/subscriptionidapiversion/_serialization.py b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/PackageModeBatch/azure/packagemode/batch/head/_vendor/serialization.py similarity index 100% rename from packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/SubscriptionIdApiVersion/subscriptionidapiversion/_serialization.py rename to packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/PackageModeBatch/azure/packagemode/batch/head/_vendor/serialization.py diff --git a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/PackageModeBatch/azure/packagemode/batch/head/aio/_head_client.py b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/PackageModeBatch/azure/packagemode/batch/head/aio/_head_client.py index 1af6b9cbce8..35dfe53fc53 100644 --- a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/PackageModeBatch/azure/packagemode/batch/head/aio/_head_client.py +++ b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/PackageModeBatch/azure/packagemode/batch/head/aio/_head_client.py @@ -17,7 +17,7 @@ from azure.mgmt.core.policies import AsyncARMAutoResourceProviderRegistrationPolicy from azure.mgmt.core.tools import get_arm_endpoints -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import HeadClientConfiguration from .operations import HttpSuccessOperations diff --git a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/PackageModeBatch/azure/packagemode/batch/head/aio/operations/_http_success_operations.py b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/PackageModeBatch/azure/packagemode/batch/head/aio/operations/_http_success_operations.py index 8c9922a3882..ee19e5ad77a 100644 --- a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/PackageModeBatch/azure/packagemode/batch/head/aio/operations/_http_success_operations.py +++ b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/PackageModeBatch/azure/packagemode/batch/head/aio/operations/_http_success_operations.py @@ -22,7 +22,7 @@ from azure.core.tracing.decorator_async import distributed_trace_async from azure.mgmt.core.exceptions import ARMErrorFormat -from ..._serialization import Deserializer, Serializer +from ..._utils.serialization import Deserializer, Serializer from ...operations._http_success_operations import build_head200_request, build_head204_request, build_head404_request from .._configuration import HeadClientConfiguration diff --git a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/PackageModeBatch/azure/packagemode/batch/head/operations/_http_success_operations.py b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/PackageModeBatch/azure/packagemode/batch/head/operations/_http_success_operations.py index 86048d3ebbe..24ebb7feac9 100644 --- a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/PackageModeBatch/azure/packagemode/batch/head/operations/_http_success_operations.py +++ b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/PackageModeBatch/azure/packagemode/batch/head/operations/_http_success_operations.py @@ -23,7 +23,7 @@ from azure.mgmt.core.exceptions import ARMErrorFormat from .._configuration import HeadClientConfiguration -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/PackageModeBatch/azure/packagemode/batch/paging/_paging_client.py b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/PackageModeBatch/azure/packagemode/batch/paging/_paging_client.py index 1145f8afd23..e182eb97f27 100644 --- a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/PackageModeBatch/azure/packagemode/batch/paging/_paging_client.py +++ b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/PackageModeBatch/azure/packagemode/batch/paging/_paging_client.py @@ -19,7 +19,7 @@ from . import models as _models from ._configuration import PagingClientConfiguration -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer from .operations import PagingOperations if TYPE_CHECKING: diff --git a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/PackageModeBatch/azure/packagemode/batch/paging/_utils/__init__.py b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/PackageModeBatch/azure/packagemode/batch/paging/_utils/__init__.py new file mode 100644 index 00000000000..0af9b28f660 --- /dev/null +++ b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/PackageModeBatch/azure/packagemode/batch/paging/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/AzureBodyDurationVersionTolerant/bodydurationversiontolerant/_serialization.py b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/PackageModeBatch/azure/packagemode/batch/paging/_utils/serialization.py similarity index 100% rename from packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/AzureBodyDurationVersionTolerant/bodydurationversiontolerant/_serialization.py rename to packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/PackageModeBatch/azure/packagemode/batch/paging/_utils/serialization.py diff --git a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/PackageModeBatch/azure/packagemode/batch/paging/_vendor/__init__.py b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/PackageModeBatch/azure/packagemode/batch/paging/_vendor/__init__.py new file mode 100644 index 00000000000..0af9b28f660 --- /dev/null +++ b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/PackageModeBatch/azure/packagemode/batch/paging/_vendor/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/AzureParameterGroupingVersionTolerant/azureparametergroupingversiontolerant/_serialization.py b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/PackageModeBatch/azure/packagemode/batch/paging/_vendor/serialization.py similarity index 100% rename from packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/AzureParameterGroupingVersionTolerant/azureparametergroupingversiontolerant/_serialization.py rename to packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/PackageModeBatch/azure/packagemode/batch/paging/_vendor/serialization.py diff --git a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/PackageModeBatch/azure/packagemode/batch/paging/aio/_paging_client.py b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/PackageModeBatch/azure/packagemode/batch/paging/aio/_paging_client.py index 82fd8623950..c7566c2118e 100644 --- a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/PackageModeBatch/azure/packagemode/batch/paging/aio/_paging_client.py +++ b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/PackageModeBatch/azure/packagemode/batch/paging/aio/_paging_client.py @@ -18,7 +18,7 @@ from azure.mgmt.core.tools import get_arm_endpoints from .. import models as _models -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import PagingClientConfiguration from .operations import PagingOperations diff --git a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/PackageModeBatch/azure/packagemode/batch/paging/aio/operations/_paging_operations.py b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/PackageModeBatch/azure/packagemode/batch/paging/aio/operations/_paging_operations.py index 8e2305c716b..29d1be28134 100644 --- a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/PackageModeBatch/azure/packagemode/batch/paging/aio/operations/_paging_operations.py +++ b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/PackageModeBatch/azure/packagemode/batch/paging/aio/operations/_paging_operations.py @@ -32,7 +32,7 @@ from azure.mgmt.core.polling.async_arm_polling import AsyncARMPolling from ... import models as _models -from ..._serialization import Deserializer, Serializer +from ..._utils.serialization import Deserializer, Serializer from ...operations._paging_operations import ( build_append_api_version_request, build_duplicate_params_request, diff --git a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/PackageModeBatch/azure/packagemode/batch/paging/models/_models_py3.py b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/PackageModeBatch/azure/packagemode/batch/paging/models/_models_py3.py index e59e87a4ac9..36303b8f9d0 100644 --- a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/PackageModeBatch/azure/packagemode/batch/paging/models/_models_py3.py +++ b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/PackageModeBatch/azure/packagemode/batch/paging/models/_models_py3.py @@ -8,7 +8,7 @@ from typing import Any, List, Optional, TYPE_CHECKING, Union -from .. import _serialization +from .._utils import serialization as _serialization if TYPE_CHECKING: from .. import models as _models diff --git a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/PackageModeBatch/azure/packagemode/batch/paging/operations/_paging_operations.py b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/PackageModeBatch/azure/packagemode/batch/paging/operations/_paging_operations.py index bb59b7dc380..1b16b298057 100644 --- a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/PackageModeBatch/azure/packagemode/batch/paging/operations/_paging_operations.py +++ b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/PackageModeBatch/azure/packagemode/batch/paging/operations/_paging_operations.py @@ -32,7 +32,7 @@ from .. import models as _models from .._configuration import PagingClientConfiguration -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/PackageModeCustomize/azure/packagemode/customize/_auto_rest_head_test_service.py b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/PackageModeCustomize/azure/packagemode/customize/_auto_rest_head_test_service.py index 04d600d1e3a..1c9da1c8548 100644 --- a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/PackageModeCustomize/azure/packagemode/customize/_auto_rest_head_test_service.py +++ b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/PackageModeCustomize/azure/packagemode/customize/_auto_rest_head_test_service.py @@ -18,7 +18,7 @@ from azure.mgmt.core.tools import get_arm_endpoints from ._configuration import AutoRestHeadTestServiceConfiguration -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer from .operations import HttpSuccessOperations if TYPE_CHECKING: diff --git a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/PackageModeCustomize/azure/packagemode/customize/_utils/__init__.py b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/PackageModeCustomize/azure/packagemode/customize/_utils/__init__.py new file mode 100644 index 00000000000..0af9b28f660 --- /dev/null +++ b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/PackageModeCustomize/azure/packagemode/customize/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/AzureReportVersionTolerant/azurereportversiontolerant/_serialization.py b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/PackageModeCustomize/azure/packagemode/customize/_utils/serialization.py similarity index 100% rename from packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/AzureReportVersionTolerant/azurereportversiontolerant/_serialization.py rename to packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/PackageModeCustomize/azure/packagemode/customize/_utils/serialization.py diff --git a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/PackageModeCustomize/azure/packagemode/customize/_vendor/__init__.py b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/PackageModeCustomize/azure/packagemode/customize/_vendor/__init__.py new file mode 100644 index 00000000000..0af9b28f660 --- /dev/null +++ b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/PackageModeCustomize/azure/packagemode/customize/_vendor/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/AzureSpecialsVersionTolerant/azurespecialpropertiesversiontolerant/_serialization.py b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/PackageModeCustomize/azure/packagemode/customize/_vendor/serialization.py similarity index 100% rename from packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/AzureSpecialsVersionTolerant/azurespecialpropertiesversiontolerant/_serialization.py rename to packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/PackageModeCustomize/azure/packagemode/customize/_vendor/serialization.py diff --git a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/PackageModeCustomize/azure/packagemode/customize/aio/_auto_rest_head_test_service.py b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/PackageModeCustomize/azure/packagemode/customize/aio/_auto_rest_head_test_service.py index 7864ddf65f2..730e2872a4f 100644 --- a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/PackageModeCustomize/azure/packagemode/customize/aio/_auto_rest_head_test_service.py +++ b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/PackageModeCustomize/azure/packagemode/customize/aio/_auto_rest_head_test_service.py @@ -17,7 +17,7 @@ from azure.mgmt.core.policies import AsyncARMAutoResourceProviderRegistrationPolicy from azure.mgmt.core.tools import get_arm_endpoints -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import AutoRestHeadTestServiceConfiguration from .operations import HttpSuccessOperations diff --git a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/PackageModeCustomize/azure/packagemode/customize/aio/operations/_http_success_operations.py b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/PackageModeCustomize/azure/packagemode/customize/aio/operations/_http_success_operations.py index fe5b7ed6737..b32ec341aeb 100644 --- a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/PackageModeCustomize/azure/packagemode/customize/aio/operations/_http_success_operations.py +++ b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/PackageModeCustomize/azure/packagemode/customize/aio/operations/_http_success_operations.py @@ -22,7 +22,7 @@ from azure.core.tracing.decorator_async import distributed_trace_async from azure.mgmt.core.exceptions import ARMErrorFormat -from ..._serialization import Deserializer, Serializer +from ..._utils.serialization import Deserializer, Serializer from ...operations._http_success_operations import build_head200_request, build_head204_request, build_head404_request from .._configuration import AutoRestHeadTestServiceConfiguration diff --git a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/PackageModeCustomize/azure/packagemode/customize/operations/_http_success_operations.py b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/PackageModeCustomize/azure/packagemode/customize/operations/_http_success_operations.py index 0cb7d04a784..cb9d3718d30 100644 --- a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/PackageModeCustomize/azure/packagemode/customize/operations/_http_success_operations.py +++ b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/PackageModeCustomize/azure/packagemode/customize/operations/_http_success_operations.py @@ -23,7 +23,7 @@ from azure.mgmt.core.exceptions import ARMErrorFormat from .._configuration import AutoRestHeadTestServiceConfiguration -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/PackageModeDataPlane/azure/packagemode/dataplane/_auto_rest_head_test_service.py b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/PackageModeDataPlane/azure/packagemode/dataplane/_auto_rest_head_test_service.py index fc3f2852b37..3439c20175e 100644 --- a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/PackageModeDataPlane/azure/packagemode/dataplane/_auto_rest_head_test_service.py +++ b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/PackageModeDataPlane/azure/packagemode/dataplane/_auto_rest_head_test_service.py @@ -18,7 +18,7 @@ from azure.mgmt.core.tools import get_arm_endpoints from ._configuration import AutoRestHeadTestServiceConfiguration -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer from .operations import HttpSuccessOperations if TYPE_CHECKING: diff --git a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/PackageModeDataPlane/azure/packagemode/dataplane/_utils/__init__.py b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/PackageModeDataPlane/azure/packagemode/dataplane/_utils/__init__.py new file mode 100644 index 00000000000..0af9b28f660 --- /dev/null +++ b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/PackageModeDataPlane/azure/packagemode/dataplane/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/CustomBaseUriVersionTolerant/custombaseurlversiontolerant/_serialization.py b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/PackageModeDataPlane/azure/packagemode/dataplane/_utils/serialization.py similarity index 100% rename from packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/CustomBaseUriVersionTolerant/custombaseurlversiontolerant/_serialization.py rename to packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/PackageModeDataPlane/azure/packagemode/dataplane/_utils/serialization.py diff --git a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/PackageModeDataPlane/azure/packagemode/dataplane/_vendor/__init__.py b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/PackageModeDataPlane/azure/packagemode/dataplane/_vendor/__init__.py new file mode 100644 index 00000000000..0af9b28f660 --- /dev/null +++ b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/PackageModeDataPlane/azure/packagemode/dataplane/_vendor/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/CustomPollerPagerVersionTolerant/custompollerpagerversiontolerant/_serialization.py b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/PackageModeDataPlane/azure/packagemode/dataplane/_vendor/serialization.py similarity index 100% rename from packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/CustomPollerPagerVersionTolerant/custompollerpagerversiontolerant/_serialization.py rename to packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/PackageModeDataPlane/azure/packagemode/dataplane/_vendor/serialization.py diff --git a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/PackageModeDataPlane/azure/packagemode/dataplane/aio/_auto_rest_head_test_service.py b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/PackageModeDataPlane/azure/packagemode/dataplane/aio/_auto_rest_head_test_service.py index 984c57c86b3..f5773529232 100644 --- a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/PackageModeDataPlane/azure/packagemode/dataplane/aio/_auto_rest_head_test_service.py +++ b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/PackageModeDataPlane/azure/packagemode/dataplane/aio/_auto_rest_head_test_service.py @@ -17,7 +17,7 @@ from azure.mgmt.core.policies import AsyncARMAutoResourceProviderRegistrationPolicy from azure.mgmt.core.tools import get_arm_endpoints -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import AutoRestHeadTestServiceConfiguration from .operations import HttpSuccessOperations diff --git a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/PackageModeDataPlane/azure/packagemode/dataplane/aio/operations/_http_success_operations.py b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/PackageModeDataPlane/azure/packagemode/dataplane/aio/operations/_http_success_operations.py index 6a37a30b1bc..654c8761749 100644 --- a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/PackageModeDataPlane/azure/packagemode/dataplane/aio/operations/_http_success_operations.py +++ b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/PackageModeDataPlane/azure/packagemode/dataplane/aio/operations/_http_success_operations.py @@ -22,7 +22,7 @@ from azure.core.tracing.decorator_async import distributed_trace_async from azure.mgmt.core.exceptions import ARMErrorFormat -from ..._serialization import Deserializer, Serializer +from ..._utils.serialization import Deserializer, Serializer from ...operations._http_success_operations import build_head200_request, build_head204_request, build_head404_request from .._configuration import AutoRestHeadTestServiceConfiguration diff --git a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/PackageModeDataPlane/azure/packagemode/dataplane/operations/_http_success_operations.py b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/PackageModeDataPlane/azure/packagemode/dataplane/operations/_http_success_operations.py index 76ffba9967e..b6ff8be5eb8 100644 --- a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/PackageModeDataPlane/azure/packagemode/dataplane/operations/_http_success_operations.py +++ b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/PackageModeDataPlane/azure/packagemode/dataplane/operations/_http_success_operations.py @@ -23,7 +23,7 @@ from azure.mgmt.core.exceptions import ARMErrorFormat from .._configuration import AutoRestHeadTestServiceConfiguration -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/PackageModeMgmtPlane/azure/package/mode/_auto_rest_head_test_service.py b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/PackageModeMgmtPlane/azure/package/mode/_auto_rest_head_test_service.py index 919c9c6405b..e640f9bc44f 100644 --- a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/PackageModeMgmtPlane/azure/package/mode/_auto_rest_head_test_service.py +++ b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/PackageModeMgmtPlane/azure/package/mode/_auto_rest_head_test_service.py @@ -18,7 +18,7 @@ from azure.mgmt.core.tools import get_arm_endpoints from ._configuration import AutoRestHeadTestServiceConfiguration -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer from .operations import HttpSuccessOperations if TYPE_CHECKING: diff --git a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/PackageModeMgmtPlane/azure/package/mode/_utils/__init__.py b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/PackageModeMgmtPlane/azure/package/mode/_utils/__init__.py new file mode 100644 index 00000000000..0af9b28f660 --- /dev/null +++ b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/PackageModeMgmtPlane/azure/package/mode/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/CustomUrlPagingVersionTolerant/custombaseurlpagingversiontolerant/_serialization.py b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/PackageModeMgmtPlane/azure/package/mode/_utils/serialization.py similarity index 100% rename from packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/CustomUrlPagingVersionTolerant/custombaseurlpagingversiontolerant/_serialization.py rename to packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/PackageModeMgmtPlane/azure/package/mode/_utils/serialization.py diff --git a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/PackageModeMgmtPlane/azure/package/mode/_vendor/__init__.py b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/PackageModeMgmtPlane/azure/package/mode/_vendor/__init__.py new file mode 100644 index 00000000000..0af9b28f660 --- /dev/null +++ b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/PackageModeMgmtPlane/azure/package/mode/_vendor/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/HeadExceptionsVersionTolerant/headexceptionsversiontolerant/_serialization.py b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/PackageModeMgmtPlane/azure/package/mode/_vendor/serialization.py similarity index 100% rename from packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/HeadExceptionsVersionTolerant/headexceptionsversiontolerant/_serialization.py rename to packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/PackageModeMgmtPlane/azure/package/mode/_vendor/serialization.py diff --git a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/PackageModeMgmtPlane/azure/package/mode/aio/_auto_rest_head_test_service.py b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/PackageModeMgmtPlane/azure/package/mode/aio/_auto_rest_head_test_service.py index 883d2746952..3d8ad03d0df 100644 --- a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/PackageModeMgmtPlane/azure/package/mode/aio/_auto_rest_head_test_service.py +++ b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/PackageModeMgmtPlane/azure/package/mode/aio/_auto_rest_head_test_service.py @@ -17,7 +17,7 @@ from azure.mgmt.core.policies import AsyncARMAutoResourceProviderRegistrationPolicy from azure.mgmt.core.tools import get_arm_endpoints -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import AutoRestHeadTestServiceConfiguration from .operations import HttpSuccessOperations diff --git a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/PackageModeMgmtPlane/azure/package/mode/aio/operations/_http_success_operations.py b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/PackageModeMgmtPlane/azure/package/mode/aio/operations/_http_success_operations.py index e028b532e4c..46dd74dd5c8 100644 --- a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/PackageModeMgmtPlane/azure/package/mode/aio/operations/_http_success_operations.py +++ b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/PackageModeMgmtPlane/azure/package/mode/aio/operations/_http_success_operations.py @@ -22,7 +22,7 @@ from azure.core.tracing.decorator_async import distributed_trace_async from azure.mgmt.core.exceptions import ARMErrorFormat -from ..._serialization import Deserializer, Serializer +from ..._utils.serialization import Deserializer, Serializer from ...operations._http_success_operations import build_head200_request, build_head204_request, build_head404_request from .._configuration import AutoRestHeadTestServiceConfiguration diff --git a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/PackageModeMgmtPlane/azure/package/mode/operations/_http_success_operations.py b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/PackageModeMgmtPlane/azure/package/mode/operations/_http_success_operations.py index 030f071859c..0df7ba8ede6 100644 --- a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/PackageModeMgmtPlane/azure/package/mode/operations/_http_success_operations.py +++ b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/PackageModeMgmtPlane/azure/package/mode/operations/_http_success_operations.py @@ -23,7 +23,7 @@ from azure.mgmt.core.exceptions import ARMErrorFormat from .._configuration import AutoRestHeadTestServiceConfiguration -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/Paging/paging/_auto_rest_paging_test_service.py b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/Paging/paging/_auto_rest_paging_test_service.py index da5413ef05c..1e0ae3ec7bb 100644 --- a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/Paging/paging/_auto_rest_paging_test_service.py +++ b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/Paging/paging/_auto_rest_paging_test_service.py @@ -16,7 +16,7 @@ from . import models as _models from ._configuration import AutoRestPagingTestServiceConfiguration -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer from .operations import PagingOperations diff --git a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/Paging/paging/_utils/__init__.py b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/Paging/paging/_utils/__init__.py new file mode 100644 index 00000000000..0af9b28f660 --- /dev/null +++ b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/Paging/paging/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/HeadVersionTolerant/headversiontolerant/_serialization.py b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/Paging/paging/_utils/serialization.py similarity index 100% rename from packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/HeadVersionTolerant/headversiontolerant/_serialization.py rename to packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/Paging/paging/_utils/serialization.py diff --git a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/Paging/paging/aio/_auto_rest_paging_test_service.py b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/Paging/paging/aio/_auto_rest_paging_test_service.py index 7234e05ca51..3f47c456bb3 100644 --- a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/Paging/paging/aio/_auto_rest_paging_test_service.py +++ b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/Paging/paging/aio/_auto_rest_paging_test_service.py @@ -15,7 +15,7 @@ from azure.core.rest import AsyncHttpResponse, HttpRequest from .. import models as _models -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import AutoRestPagingTestServiceConfiguration from .operations import PagingOperations diff --git a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/Paging/paging/aio/operations/_paging_operations.py b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/Paging/paging/aio/operations/_paging_operations.py index 3945741f768..c7ac9fb4844 100644 --- a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/Paging/paging/aio/operations/_paging_operations.py +++ b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/Paging/paging/aio/operations/_paging_operations.py @@ -31,7 +31,7 @@ from azure.core.utils import case_insensitive_dict from ... import models as _models -from ..._serialization import Deserializer, Serializer +from ..._utils.serialization import Deserializer, Serializer from ...operations._paging_operations import ( build_append_api_version_request, build_duplicate_params_request, diff --git a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/Paging/paging/models/_models_py3.py b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/Paging/paging/models/_models_py3.py index 54d8bfc2674..05b66f11e19 100644 --- a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/Paging/paging/models/_models_py3.py +++ b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/Paging/paging/models/_models_py3.py @@ -8,7 +8,7 @@ from typing import Any, List, Optional, TYPE_CHECKING, Union -from .. import _serialization +from .._utils import serialization as _serialization if TYPE_CHECKING: from .. import models as _models diff --git a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/Paging/paging/operations/_paging_operations.py b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/Paging/paging/operations/_paging_operations.py index 3d69bbd4050..4523defc63c 100644 --- a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/Paging/paging/operations/_paging_operations.py +++ b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/Paging/paging/operations/_paging_operations.py @@ -31,7 +31,7 @@ from .. import models as _models from .._configuration import AutoRestPagingTestServiceConfiguration -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/SecurityAadSwagger/securityaadswagger/_autorest_security_aad.py b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/SecurityAadSwagger/securityaadswagger/_autorest_security_aad.py index 98c6f93e63e..6bbf03e8dcb 100644 --- a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/SecurityAadSwagger/securityaadswagger/_autorest_security_aad.py +++ b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/SecurityAadSwagger/securityaadswagger/_autorest_security_aad.py @@ -18,7 +18,7 @@ from azure.mgmt.core.tools import get_arm_endpoints from ._configuration import AutorestSecurityAadConfiguration -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer from .operations import AutorestSecurityAadOperationsMixin if TYPE_CHECKING: diff --git a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/SecurityAadSwagger/securityaadswagger/_utils/__init__.py b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/SecurityAadSwagger/securityaadswagger/_utils/__init__.py new file mode 100644 index 00000000000..0af9b28f660 --- /dev/null +++ b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/SecurityAadSwagger/securityaadswagger/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/LroPagingVersionTolerant/lropagingversiontolerant/_serialization.py b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/SecurityAadSwagger/securityaadswagger/_utils/serialization.py similarity index 100% rename from packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/LroPagingVersionTolerant/lropagingversiontolerant/_serialization.py rename to packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/SecurityAadSwagger/securityaadswagger/_utils/serialization.py diff --git a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/SecurityAadSwagger/securityaadswagger/_utils/utils.py b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/SecurityAadSwagger/securityaadswagger/_utils/utils.py new file mode 100644 index 00000000000..39b612f39a9 --- /dev/null +++ b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/SecurityAadSwagger/securityaadswagger/_utils/utils.py @@ -0,0 +1,25 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from abc import ABC +from typing import Generic, TYPE_CHECKING, TypeVar + +if TYPE_CHECKING: + from .serialization import Deserializer, Serializer + + +TClient = TypeVar("TClient") +TConfig = TypeVar("TConfig") + + +class ClientMixinABC(ABC, Generic[TClient, TConfig]): + """DO NOT use this class. It is for internal typing use only.""" + + _client: TClient + _config: TConfig + _serialize: "Serializer" + _deserialize: "Deserializer" diff --git a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/SecurityAadSwagger/securityaadswagger/_vendor.py b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/SecurityAadSwagger/securityaadswagger/_vendor.py deleted file mode 100644 index 4bac3abea25..00000000000 --- a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/SecurityAadSwagger/securityaadswagger/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) AutoRest Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import AutorestSecurityAadConfiguration - -if TYPE_CHECKING: - from azure.core import PipelineClient - - from ._serialization import Deserializer, Serializer - - -class AutorestSecurityAadMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "PipelineClient" - _config: AutorestSecurityAadConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/SecurityAadSwagger/securityaadswagger/aio/_autorest_security_aad.py b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/SecurityAadSwagger/securityaadswagger/aio/_autorest_security_aad.py index f31e7e8abc0..1480b5fd523 100644 --- a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/SecurityAadSwagger/securityaadswagger/aio/_autorest_security_aad.py +++ b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/SecurityAadSwagger/securityaadswagger/aio/_autorest_security_aad.py @@ -17,7 +17,7 @@ from azure.mgmt.core.policies import AsyncARMAutoResourceProviderRegistrationPolicy from azure.mgmt.core.tools import get_arm_endpoints -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import AutorestSecurityAadConfiguration from .operations import AutorestSecurityAadOperationsMixin diff --git a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/SecurityAadSwagger/securityaadswagger/aio/_vendor.py b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/SecurityAadSwagger/securityaadswagger/aio/_vendor.py deleted file mode 100644 index 3b07efefdc0..00000000000 --- a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/SecurityAadSwagger/securityaadswagger/aio/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) AutoRest Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import AutorestSecurityAadConfiguration - -if TYPE_CHECKING: - from azure.core import AsyncPipelineClient - - from .._serialization import Deserializer, Serializer - - -class AutorestSecurityAadMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "AsyncPipelineClient" - _config: AutorestSecurityAadConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/SecurityAadSwagger/securityaadswagger/aio/operations/_autorest_security_aad_operations.py b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/SecurityAadSwagger/securityaadswagger/aio/operations/_autorest_security_aad_operations.py index 3d1f677e7ae..4c580dc0113 100644 --- a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/SecurityAadSwagger/securityaadswagger/aio/operations/_autorest_security_aad_operations.py +++ b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/SecurityAadSwagger/securityaadswagger/aio/operations/_autorest_security_aad_operations.py @@ -9,6 +9,7 @@ from collections.abc import MutableMapping from typing import Any, Callable, Dict, Optional, TypeVar +from azure.core import AsyncPipelineClient from azure.core.exceptions import ( ClientAuthenticationError, HttpResponseError, @@ -22,14 +23,15 @@ from azure.core.tracing.decorator_async import distributed_trace_async from azure.mgmt.core.exceptions import ARMErrorFormat +from ..._utils.utils import ClientMixinABC from ...operations._autorest_security_aad_operations import build_head_request -from .._vendor import AutorestSecurityAadMixinABC +from .._configuration import AutorestSecurityAadConfiguration T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, AsyncHttpResponse], T, Dict[str, Any]], Any]] -class AutorestSecurityAadOperationsMixin(AutorestSecurityAadMixinABC): +class AutorestSecurityAadOperationsMixin(ClientMixinABC[AsyncPipelineClient, AutorestSecurityAadConfiguration]): @distributed_trace_async async def head(self, **kwargs: Any) -> bool: diff --git a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/SecurityAadSwagger/securityaadswagger/operations/_autorest_security_aad_operations.py b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/SecurityAadSwagger/securityaadswagger/operations/_autorest_security_aad_operations.py index 149b53707e2..f4ad618e9c4 100644 --- a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/SecurityAadSwagger/securityaadswagger/operations/_autorest_security_aad_operations.py +++ b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/SecurityAadSwagger/securityaadswagger/operations/_autorest_security_aad_operations.py @@ -8,6 +8,7 @@ from collections.abc import MutableMapping from typing import Any, Callable, Dict, Optional, TypeVar +from azure.core import PipelineClient from azure.core.exceptions import ( ClientAuthenticationError, HttpResponseError, @@ -21,8 +22,9 @@ from azure.core.tracing.decorator import distributed_trace from azure.mgmt.core.exceptions import ARMErrorFormat -from .._serialization import Serializer -from .._vendor import AutorestSecurityAadMixinABC +from .._configuration import AutorestSecurityAadConfiguration +from .._utils.serialization import Serializer +from .._utils.utils import ClientMixinABC T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] @@ -38,7 +40,7 @@ def build_head_request(**kwargs: Any) -> HttpRequest: return HttpRequest(method="HEAD", url=_url, **kwargs) -class AutorestSecurityAadOperationsMixin(AutorestSecurityAadMixinABC): +class AutorestSecurityAadOperationsMixin(ClientMixinABC[PipelineClient, AutorestSecurityAadConfiguration]): @distributed_trace def head(self, **kwargs: Any) -> bool: diff --git a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/SecurityKeySwagger/securitykeyswagger/_autorest_security_key.py b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/SecurityKeySwagger/securitykeyswagger/_autorest_security_key.py index e0bede0fb00..3f853862643 100644 --- a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/SecurityKeySwagger/securitykeyswagger/_autorest_security_key.py +++ b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/SecurityKeySwagger/securitykeyswagger/_autorest_security_key.py @@ -18,7 +18,7 @@ from azure.mgmt.core.tools import get_arm_endpoints from ._configuration import AutorestSecurityKeyConfiguration -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer from .operations import AutorestSecurityKeyOperationsMixin if TYPE_CHECKING: diff --git a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/SecurityKeySwagger/securitykeyswagger/_utils/__init__.py b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/SecurityKeySwagger/securitykeyswagger/_utils/__init__.py new file mode 100644 index 00000000000..0af9b28f660 --- /dev/null +++ b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/SecurityKeySwagger/securitykeyswagger/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/LroVersionTolerant/lroversiontolerant/_serialization.py b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/SecurityKeySwagger/securitykeyswagger/_utils/serialization.py similarity index 100% rename from packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/LroVersionTolerant/lroversiontolerant/_serialization.py rename to packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/SecurityKeySwagger/securitykeyswagger/_utils/serialization.py diff --git a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/SecurityKeySwagger/securitykeyswagger/_utils/utils.py b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/SecurityKeySwagger/securitykeyswagger/_utils/utils.py new file mode 100644 index 00000000000..39b612f39a9 --- /dev/null +++ b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/SecurityKeySwagger/securitykeyswagger/_utils/utils.py @@ -0,0 +1,25 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from abc import ABC +from typing import Generic, TYPE_CHECKING, TypeVar + +if TYPE_CHECKING: + from .serialization import Deserializer, Serializer + + +TClient = TypeVar("TClient") +TConfig = TypeVar("TConfig") + + +class ClientMixinABC(ABC, Generic[TClient, TConfig]): + """DO NOT use this class. It is for internal typing use only.""" + + _client: TClient + _config: TConfig + _serialize: "Serializer" + _deserialize: "Deserializer" diff --git a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/SecurityKeySwagger/securitykeyswagger/_vendor.py b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/SecurityKeySwagger/securitykeyswagger/_vendor.py deleted file mode 100644 index d615edd04da..00000000000 --- a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/SecurityKeySwagger/securitykeyswagger/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) AutoRest Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import AutorestSecurityKeyConfiguration - -if TYPE_CHECKING: - from azure.core import PipelineClient - - from ._serialization import Deserializer, Serializer - - -class AutorestSecurityKeyMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "PipelineClient" - _config: AutorestSecurityKeyConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/SecurityKeySwagger/securitykeyswagger/aio/_autorest_security_key.py b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/SecurityKeySwagger/securitykeyswagger/aio/_autorest_security_key.py index 96b6e9652c2..ae3fcdf346e 100644 --- a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/SecurityKeySwagger/securitykeyswagger/aio/_autorest_security_key.py +++ b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/SecurityKeySwagger/securitykeyswagger/aio/_autorest_security_key.py @@ -17,7 +17,7 @@ from azure.mgmt.core.policies import AsyncARMAutoResourceProviderRegistrationPolicy from azure.mgmt.core.tools import get_arm_endpoints -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import AutorestSecurityKeyConfiguration from .operations import AutorestSecurityKeyOperationsMixin diff --git a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/SecurityKeySwagger/securitykeyswagger/aio/_vendor.py b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/SecurityKeySwagger/securitykeyswagger/aio/_vendor.py deleted file mode 100644 index cf209892619..00000000000 --- a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/SecurityKeySwagger/securitykeyswagger/aio/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) AutoRest Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import AutorestSecurityKeyConfiguration - -if TYPE_CHECKING: - from azure.core import AsyncPipelineClient - - from .._serialization import Deserializer, Serializer - - -class AutorestSecurityKeyMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "AsyncPipelineClient" - _config: AutorestSecurityKeyConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/SecurityKeySwagger/securitykeyswagger/aio/operations/_autorest_security_key_operations.py b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/SecurityKeySwagger/securitykeyswagger/aio/operations/_autorest_security_key_operations.py index c6b3ae92886..ba76c1c6847 100644 --- a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/SecurityKeySwagger/securitykeyswagger/aio/operations/_autorest_security_key_operations.py +++ b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/SecurityKeySwagger/securitykeyswagger/aio/operations/_autorest_security_key_operations.py @@ -9,6 +9,7 @@ from collections.abc import MutableMapping from typing import Any, Callable, Dict, Optional, TypeVar +from azure.core import AsyncPipelineClient from azure.core.exceptions import ( ClientAuthenticationError, HttpResponseError, @@ -22,14 +23,15 @@ from azure.core.tracing.decorator_async import distributed_trace_async from azure.mgmt.core.exceptions import ARMErrorFormat +from ..._utils.utils import ClientMixinABC from ...operations._autorest_security_key_operations import build_head_request -from .._vendor import AutorestSecurityKeyMixinABC +from .._configuration import AutorestSecurityKeyConfiguration T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, AsyncHttpResponse], T, Dict[str, Any]], Any]] -class AutorestSecurityKeyOperationsMixin(AutorestSecurityKeyMixinABC): +class AutorestSecurityKeyOperationsMixin(ClientMixinABC[AsyncPipelineClient, AutorestSecurityKeyConfiguration]): @distributed_trace_async async def head(self, **kwargs: Any) -> bool: diff --git a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/SecurityKeySwagger/securitykeyswagger/operations/_autorest_security_key_operations.py b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/SecurityKeySwagger/securitykeyswagger/operations/_autorest_security_key_operations.py index 9f7d4452cdf..05b7f0a41f3 100644 --- a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/SecurityKeySwagger/securitykeyswagger/operations/_autorest_security_key_operations.py +++ b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/SecurityKeySwagger/securitykeyswagger/operations/_autorest_security_key_operations.py @@ -8,6 +8,7 @@ from collections.abc import MutableMapping from typing import Any, Callable, Dict, Optional, TypeVar +from azure.core import PipelineClient from azure.core.exceptions import ( ClientAuthenticationError, HttpResponseError, @@ -21,8 +22,9 @@ from azure.core.tracing.decorator import distributed_trace from azure.mgmt.core.exceptions import ARMErrorFormat -from .._serialization import Serializer -from .._vendor import AutorestSecurityKeyMixinABC +from .._configuration import AutorestSecurityKeyConfiguration +from .._utils.serialization import Serializer +from .._utils.utils import ClientMixinABC T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] @@ -38,7 +40,7 @@ def build_head_request(**kwargs: Any) -> HttpRequest: return HttpRequest(method="HEAD", url=_url, **kwargs) -class AutorestSecurityKeyOperationsMixin(AutorestSecurityKeyMixinABC): +class AutorestSecurityKeyOperationsMixin(ClientMixinABC[PipelineClient, AutorestSecurityKeyConfiguration]): @distributed_trace def head(self, **kwargs: Any) -> bool: diff --git a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/StorageManagementClient/storage/_storage_management_client.py b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/StorageManagementClient/storage/_storage_management_client.py index 1f9835abe72..283fa18c302 100644 --- a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/StorageManagementClient/storage/_storage_management_client.py +++ b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/StorageManagementClient/storage/_storage_management_client.py @@ -19,7 +19,7 @@ from . import models as _models from ._configuration import StorageManagementClientConfiguration -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer from .operations import StorageAccountsOperations, UsageOperations if TYPE_CHECKING: diff --git a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/StorageManagementClient/storage/_utils/__init__.py b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/StorageManagementClient/storage/_utils/__init__.py new file mode 100644 index 00000000000..0af9b28f660 --- /dev/null +++ b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/StorageManagementClient/storage/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/LroWithParameterizedEndpointsVersionTolerant/lrowithparameterizedendpointsversiontolerant/_serialization.py b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/StorageManagementClient/storage/_utils/serialization.py similarity index 100% rename from packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/LroWithParameterizedEndpointsVersionTolerant/lrowithparameterizedendpointsversiontolerant/_serialization.py rename to packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/StorageManagementClient/storage/_utils/serialization.py diff --git a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/StorageManagementClient/storage/aio/_storage_management_client.py b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/StorageManagementClient/storage/aio/_storage_management_client.py index 4ea94e40b77..defb5a50f07 100644 --- a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/StorageManagementClient/storage/aio/_storage_management_client.py +++ b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/StorageManagementClient/storage/aio/_storage_management_client.py @@ -18,7 +18,7 @@ from azure.mgmt.core.tools import get_arm_endpoints from .. import models as _models -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import StorageManagementClientConfiguration from .operations import StorageAccountsOperations, UsageOperations diff --git a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/StorageManagementClient/storage/aio/operations/_storage_accounts_operations.py b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/StorageManagementClient/storage/aio/operations/_storage_accounts_operations.py index d11d7587451..ef4d69f0a7f 100644 --- a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/StorageManagementClient/storage/aio/operations/_storage_accounts_operations.py +++ b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/StorageManagementClient/storage/aio/operations/_storage_accounts_operations.py @@ -32,7 +32,7 @@ from azure.mgmt.core.polling.async_arm_polling import AsyncARMPolling from ... import models as _models -from ..._serialization import Deserializer, Serializer +from ..._utils.serialization import Deserializer, Serializer from ...operations._storage_accounts_operations import ( build_check_name_availability_request, build_create_request, diff --git a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/StorageManagementClient/storage/aio/operations/_usage_operations.py b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/StorageManagementClient/storage/aio/operations/_usage_operations.py index 182c820ff1d..d2c937f7996 100644 --- a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/StorageManagementClient/storage/aio/operations/_usage_operations.py +++ b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/StorageManagementClient/storage/aio/operations/_usage_operations.py @@ -24,7 +24,7 @@ from azure.mgmt.core.exceptions import ARMErrorFormat from ... import models as _models -from ..._serialization import Deserializer, Serializer +from ..._utils.serialization import Deserializer, Serializer from ...operations._usage_operations import build_list_request from .._configuration import StorageManagementClientConfiguration diff --git a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/StorageManagementClient/storage/models/_models_py3.py b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/StorageManagementClient/storage/models/_models_py3.py index 7bfd14320e7..61dd9ea825e 100644 --- a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/StorageManagementClient/storage/models/_models_py3.py +++ b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/StorageManagementClient/storage/models/_models_py3.py @@ -9,7 +9,7 @@ import datetime from typing import Any, Dict, List, Optional, TYPE_CHECKING, Union -from .. import _serialization +from .._utils import serialization as _serialization if TYPE_CHECKING: from .. import models as _models diff --git a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/StorageManagementClient/storage/operations/_storage_accounts_operations.py b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/StorageManagementClient/storage/operations/_storage_accounts_operations.py index 1b488e5d6a4..c6dd542f72f 100644 --- a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/StorageManagementClient/storage/operations/_storage_accounts_operations.py +++ b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/StorageManagementClient/storage/operations/_storage_accounts_operations.py @@ -33,7 +33,7 @@ from .. import models as _models from .._configuration import StorageManagementClientConfiguration -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/StorageManagementClient/storage/operations/_usage_operations.py b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/StorageManagementClient/storage/operations/_usage_operations.py index fbced6505cf..c978cd609c8 100644 --- a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/StorageManagementClient/storage/operations/_usage_operations.py +++ b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/StorageManagementClient/storage/operations/_usage_operations.py @@ -25,7 +25,7 @@ from .. import models as _models from .._configuration import StorageManagementClientConfiguration -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/SubscriptionIdApiVersion/subscriptionidapiversion/_microsoft_azure_test_url.py b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/SubscriptionIdApiVersion/subscriptionidapiversion/_microsoft_azure_test_url.py index f9c51ffdd76..f7490b16bdd 100644 --- a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/SubscriptionIdApiVersion/subscriptionidapiversion/_microsoft_azure_test_url.py +++ b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/SubscriptionIdApiVersion/subscriptionidapiversion/_microsoft_azure_test_url.py @@ -19,7 +19,7 @@ from . import models as _models from ._configuration import MicrosoftAzureTestUrlConfiguration -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer from .operations import GroupOperations if TYPE_CHECKING: diff --git a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/SubscriptionIdApiVersion/subscriptionidapiversion/_utils/__init__.py b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/SubscriptionIdApiVersion/subscriptionidapiversion/_utils/__init__.py new file mode 100644 index 00000000000..0af9b28f660 --- /dev/null +++ b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/SubscriptionIdApiVersion/subscriptionidapiversion/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/PagingVersionTolerant/pagingversiontolerant/_serialization.py b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/SubscriptionIdApiVersion/subscriptionidapiversion/_utils/serialization.py similarity index 100% rename from packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/PagingVersionTolerant/pagingversiontolerant/_serialization.py rename to packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/SubscriptionIdApiVersion/subscriptionidapiversion/_utils/serialization.py diff --git a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/SubscriptionIdApiVersion/subscriptionidapiversion/aio/_microsoft_azure_test_url.py b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/SubscriptionIdApiVersion/subscriptionidapiversion/aio/_microsoft_azure_test_url.py index 2d52ba377e7..1c7465e956f 100644 --- a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/SubscriptionIdApiVersion/subscriptionidapiversion/aio/_microsoft_azure_test_url.py +++ b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/SubscriptionIdApiVersion/subscriptionidapiversion/aio/_microsoft_azure_test_url.py @@ -18,7 +18,7 @@ from azure.mgmt.core.tools import get_arm_endpoints from .. import models as _models -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import MicrosoftAzureTestUrlConfiguration from .operations import GroupOperations diff --git a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/SubscriptionIdApiVersion/subscriptionidapiversion/aio/operations/_group_operations.py b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/SubscriptionIdApiVersion/subscriptionidapiversion/aio/operations/_group_operations.py index 245477d5201..cd56e146c9b 100644 --- a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/SubscriptionIdApiVersion/subscriptionidapiversion/aio/operations/_group_operations.py +++ b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/SubscriptionIdApiVersion/subscriptionidapiversion/aio/operations/_group_operations.py @@ -24,7 +24,7 @@ from azure.mgmt.core.exceptions import ARMErrorFormat from ... import models as _models -from ..._serialization import Deserializer, Serializer +from ..._utils.serialization import Deserializer, Serializer from ...operations._group_operations import build_get_sample_resource_group_request from .._configuration import MicrosoftAzureTestUrlConfiguration diff --git a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/SubscriptionIdApiVersion/subscriptionidapiversion/models/_models_py3.py b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/SubscriptionIdApiVersion/subscriptionidapiversion/models/_models_py3.py index 07b665ae8e2..e62f4b020e0 100644 --- a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/SubscriptionIdApiVersion/subscriptionidapiversion/models/_models_py3.py +++ b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/SubscriptionIdApiVersion/subscriptionidapiversion/models/_models_py3.py @@ -8,7 +8,7 @@ from typing import Any, Optional -from .. import _serialization +from .._utils import serialization as _serialization class Error(_serialization.Model): diff --git a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/SubscriptionIdApiVersion/subscriptionidapiversion/operations/_group_operations.py b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/SubscriptionIdApiVersion/subscriptionidapiversion/operations/_group_operations.py index b9a91bb6359..2834e88ac54 100644 --- a/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/SubscriptionIdApiVersion/subscriptionidapiversion/operations/_group_operations.py +++ b/packages/autorest.python/test/azure/legacy/Expected/AcceptanceTests/SubscriptionIdApiVersion/subscriptionidapiversion/operations/_group_operations.py @@ -25,7 +25,7 @@ from .. import models as _models from .._configuration import MicrosoftAzureTestUrlConfiguration -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/autorest.python/test/azure/legacy/tox.ini b/packages/autorest.python/test/azure/legacy/tox.ini index 0a224e22bc8..bb387be9998 100644 --- a/packages/autorest.python/test/azure/legacy/tox.ini +++ b/packages/autorest.python/test/azure/legacy/tox.ini @@ -8,11 +8,11 @@ deps= -r requirements.txt -r ../../../../../eng/dev_requirements.txt commands= - pytest --cov=Expected + pytest [testenv:ci] commands = - pytest --cov=Expected + pytest [testenv:apiview] commands = diff --git a/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/AzureBodyDurationVersionTolerant/bodydurationversiontolerant/_client.py b/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/AzureBodyDurationVersionTolerant/bodydurationversiontolerant/_client.py index 66012287aa9..d9386eec17a 100644 --- a/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/AzureBodyDurationVersionTolerant/bodydurationversiontolerant/_client.py +++ b/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/AzureBodyDurationVersionTolerant/bodydurationversiontolerant/_client.py @@ -15,7 +15,7 @@ from azure.core.rest import HttpRequest, HttpResponse from ._configuration import AutoRestDurationTestServiceConfiguration -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer from .operations import DurationOperations diff --git a/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/AzureBodyDurationVersionTolerant/bodydurationversiontolerant/_utils/__init__.py b/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/AzureBodyDurationVersionTolerant/bodydurationversiontolerant/_utils/__init__.py new file mode 100644 index 00000000000..0af9b28f660 --- /dev/null +++ b/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/AzureBodyDurationVersionTolerant/bodydurationversiontolerant/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/StorageManagementClientVersionTolerant/storageversiontolerant/_serialization.py b/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/AzureBodyDurationVersionTolerant/bodydurationversiontolerant/_utils/serialization.py similarity index 100% rename from packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/StorageManagementClientVersionTolerant/storageversiontolerant/_serialization.py rename to packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/AzureBodyDurationVersionTolerant/bodydurationversiontolerant/_utils/serialization.py diff --git a/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/AzureBodyDurationVersionTolerant/bodydurationversiontolerant/aio/_client.py b/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/AzureBodyDurationVersionTolerant/bodydurationversiontolerant/aio/_client.py index 53753d25a38..449d62630c0 100644 --- a/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/AzureBodyDurationVersionTolerant/bodydurationversiontolerant/aio/_client.py +++ b/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/AzureBodyDurationVersionTolerant/bodydurationversiontolerant/aio/_client.py @@ -14,7 +14,7 @@ from azure.core.pipeline import policies from azure.core.rest import AsyncHttpResponse, HttpRequest -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import AutoRestDurationTestServiceConfiguration from .operations import DurationOperations diff --git a/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/AzureBodyDurationVersionTolerant/bodydurationversiontolerant/aio/operations/_operations.py b/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/AzureBodyDurationVersionTolerant/bodydurationversiontolerant/aio/operations/_operations.py index bc829151ae3..0b866955e48 100644 --- a/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/AzureBodyDurationVersionTolerant/bodydurationversiontolerant/aio/operations/_operations.py +++ b/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/AzureBodyDurationVersionTolerant/bodydurationversiontolerant/aio/operations/_operations.py @@ -23,7 +23,7 @@ from azure.core.tracing.decorator_async import distributed_trace_async from azure.core.utils import case_insensitive_dict -from ..._serialization import Deserializer, Serializer +from ..._utils.serialization import Deserializer, Serializer from ...operations._operations import ( build_duration_get_invalid_request, build_duration_get_null_request, diff --git a/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/AzureBodyDurationVersionTolerant/bodydurationversiontolerant/operations/_operations.py b/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/AzureBodyDurationVersionTolerant/bodydurationversiontolerant/operations/_operations.py index b4fc8928afe..f7a0268a07d 100644 --- a/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/AzureBodyDurationVersionTolerant/bodydurationversiontolerant/operations/_operations.py +++ b/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/AzureBodyDurationVersionTolerant/bodydurationversiontolerant/operations/_operations.py @@ -24,7 +24,7 @@ from azure.core.utils import case_insensitive_dict from .._configuration import AutoRestDurationTestServiceConfiguration -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/AzureParameterGroupingVersionTolerant/azureparametergroupingversiontolerant/_client.py b/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/AzureParameterGroupingVersionTolerant/azureparametergroupingversiontolerant/_client.py index 96ea67af51c..9100ccf7808 100644 --- a/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/AzureParameterGroupingVersionTolerant/azureparametergroupingversiontolerant/_client.py +++ b/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/AzureParameterGroupingVersionTolerant/azureparametergroupingversiontolerant/_client.py @@ -15,7 +15,7 @@ from azure.core.rest import HttpRequest, HttpResponse from ._configuration import AutoRestParameterGroupingTestServiceConfiguration -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer from .operations import ParameterGroupingOperations diff --git a/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/AzureParameterGroupingVersionTolerant/azureparametergroupingversiontolerant/_utils/__init__.py b/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/AzureParameterGroupingVersionTolerant/azureparametergroupingversiontolerant/_utils/__init__.py new file mode 100644 index 00000000000..0af9b28f660 --- /dev/null +++ b/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/AzureParameterGroupingVersionTolerant/azureparametergroupingversiontolerant/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/SubscriptionIdApiVersionVersionTolerant/subscriptionidapiversionversiontolerant/_serialization.py b/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/AzureParameterGroupingVersionTolerant/azureparametergroupingversiontolerant/_utils/serialization.py similarity index 100% rename from packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/SubscriptionIdApiVersionVersionTolerant/subscriptionidapiversionversiontolerant/_serialization.py rename to packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/AzureParameterGroupingVersionTolerant/azureparametergroupingversiontolerant/_utils/serialization.py diff --git a/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/AzureParameterGroupingVersionTolerant/azureparametergroupingversiontolerant/aio/_client.py b/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/AzureParameterGroupingVersionTolerant/azureparametergroupingversiontolerant/aio/_client.py index d642fb485d0..d6f1e2eee31 100644 --- a/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/AzureParameterGroupingVersionTolerant/azureparametergroupingversiontolerant/aio/_client.py +++ b/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/AzureParameterGroupingVersionTolerant/azureparametergroupingversiontolerant/aio/_client.py @@ -14,7 +14,7 @@ from azure.core.pipeline import policies from azure.core.rest import AsyncHttpResponse, HttpRequest -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import AutoRestParameterGroupingTestServiceConfiguration from .operations import ParameterGroupingOperations diff --git a/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/AzureParameterGroupingVersionTolerant/azureparametergroupingversiontolerant/aio/operations/_operations.py b/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/AzureParameterGroupingVersionTolerant/azureparametergroupingversiontolerant/aio/operations/_operations.py index 38b89201053..e512cff39c9 100644 --- a/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/AzureParameterGroupingVersionTolerant/azureparametergroupingversiontolerant/aio/operations/_operations.py +++ b/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/AzureParameterGroupingVersionTolerant/azureparametergroupingversiontolerant/aio/operations/_operations.py @@ -22,7 +22,7 @@ from azure.core.tracing.decorator_async import distributed_trace_async from azure.core.utils import case_insensitive_dict -from ..._serialization import Deserializer, Serializer +from ..._utils.serialization import Deserializer, Serializer from ...operations._operations import ( build_parameter_grouping_group_with_constant_request, build_parameter_grouping_post_multi_param_groups_request, diff --git a/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/AzureParameterGroupingVersionTolerant/azureparametergroupingversiontolerant/operations/_operations.py b/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/AzureParameterGroupingVersionTolerant/azureparametergroupingversiontolerant/operations/_operations.py index 19a5a371c43..d343f31e923 100644 --- a/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/AzureParameterGroupingVersionTolerant/azureparametergroupingversiontolerant/operations/_operations.py +++ b/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/AzureParameterGroupingVersionTolerant/azureparametergroupingversiontolerant/operations/_operations.py @@ -23,7 +23,7 @@ from azure.core.utils import case_insensitive_dict from .._configuration import AutoRestParameterGroupingTestServiceConfiguration -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/AzureReportVersionTolerant/azurereportversiontolerant/_client.py b/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/AzureReportVersionTolerant/azurereportversiontolerant/_client.py index 4f243a22057..31b6fb51de0 100644 --- a/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/AzureReportVersionTolerant/azurereportversiontolerant/_client.py +++ b/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/AzureReportVersionTolerant/azurereportversiontolerant/_client.py @@ -16,7 +16,7 @@ from ._configuration import AutoRestReportServiceForAzureConfiguration from ._operations import AutoRestReportServiceForAzureOperationsMixin -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer class AutoRestReportServiceForAzure( diff --git a/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/AzureReportVersionTolerant/azurereportversiontolerant/_operations/_operations.py b/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/AzureReportVersionTolerant/azurereportversiontolerant/_operations/_operations.py index 75ed2ecc4b2..266c10274c3 100644 --- a/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/AzureReportVersionTolerant/azurereportversiontolerant/_operations/_operations.py +++ b/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/AzureReportVersionTolerant/azurereportversiontolerant/_operations/_operations.py @@ -8,6 +8,7 @@ from collections.abc import MutableMapping from typing import Any, Callable, Dict, Optional, TypeVar, cast +from azure.core import PipelineClient from azure.core.exceptions import ( ClientAuthenticationError, HttpResponseError, @@ -21,8 +22,9 @@ from azure.core.tracing.decorator import distributed_trace from azure.core.utils import case_insensitive_dict -from .._serialization import Serializer -from .._vendor import AutoRestReportServiceForAzureMixinABC +from .._configuration import AutoRestReportServiceForAzureConfiguration +from .._utils.serialization import Serializer +from .._utils.utils import ClientMixinABC T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] @@ -53,7 +55,7 @@ def build_auto_rest_report_service_for_azure_get_report_request( # pylint: disa class AutoRestReportServiceForAzureOperationsMixin( # pylint: disable=name-too-long - AutoRestReportServiceForAzureMixinABC + ClientMixinABC[PipelineClient, AutoRestReportServiceForAzureConfiguration] ): @distributed_trace diff --git a/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/AzureReportVersionTolerant/azurereportversiontolerant/_utils/__init__.py b/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/AzureReportVersionTolerant/azurereportversiontolerant/_utils/__init__.py new file mode 100644 index 00000000000..0af9b28f660 --- /dev/null +++ b/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/AzureReportVersionTolerant/azurereportversiontolerant/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/autorest.python/test/dpg/version-tolerant/Expected/AcceptanceTests/DPGCustomizationCustomizedVersionTolerant/dpgcustomizationcustomizedversiontolerant/_serialization.py b/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/AzureReportVersionTolerant/azurereportversiontolerant/_utils/serialization.py similarity index 100% rename from packages/autorest.python/test/dpg/version-tolerant/Expected/AcceptanceTests/DPGCustomizationCustomizedVersionTolerant/dpgcustomizationcustomizedversiontolerant/_serialization.py rename to packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/AzureReportVersionTolerant/azurereportversiontolerant/_utils/serialization.py diff --git a/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/AzureReportVersionTolerant/azurereportversiontolerant/_utils/utils.py b/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/AzureReportVersionTolerant/azurereportversiontolerant/_utils/utils.py new file mode 100644 index 00000000000..39b612f39a9 --- /dev/null +++ b/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/AzureReportVersionTolerant/azurereportversiontolerant/_utils/utils.py @@ -0,0 +1,25 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from abc import ABC +from typing import Generic, TYPE_CHECKING, TypeVar + +if TYPE_CHECKING: + from .serialization import Deserializer, Serializer + + +TClient = TypeVar("TClient") +TConfig = TypeVar("TConfig") + + +class ClientMixinABC(ABC, Generic[TClient, TConfig]): + """DO NOT use this class. It is for internal typing use only.""" + + _client: TClient + _config: TConfig + _serialize: "Serializer" + _deserialize: "Deserializer" diff --git a/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/AzureReportVersionTolerant/azurereportversiontolerant/_vendor.py b/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/AzureReportVersionTolerant/azurereportversiontolerant/_vendor.py deleted file mode 100644 index 3af6dbaa6be..00000000000 --- a/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/AzureReportVersionTolerant/azurereportversiontolerant/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) AutoRest Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import AutoRestReportServiceForAzureConfiguration - -if TYPE_CHECKING: - from azure.core import PipelineClient - - from ._serialization import Deserializer, Serializer - - -class AutoRestReportServiceForAzureMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "PipelineClient" - _config: AutoRestReportServiceForAzureConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/AzureReportVersionTolerant/azurereportversiontolerant/aio/_client.py b/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/AzureReportVersionTolerant/azurereportversiontolerant/aio/_client.py index f6ea3ba768e..3d720467521 100644 --- a/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/AzureReportVersionTolerant/azurereportversiontolerant/aio/_client.py +++ b/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/AzureReportVersionTolerant/azurereportversiontolerant/aio/_client.py @@ -14,7 +14,7 @@ from azure.core.pipeline import policies from azure.core.rest import AsyncHttpResponse, HttpRequest -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import AutoRestReportServiceForAzureConfiguration from ._operations import AutoRestReportServiceForAzureOperationsMixin diff --git a/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/AzureReportVersionTolerant/azurereportversiontolerant/aio/_operations/_operations.py b/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/AzureReportVersionTolerant/azurereportversiontolerant/aio/_operations/_operations.py index 185c4dc217b..4004e042b39 100644 --- a/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/AzureReportVersionTolerant/azurereportversiontolerant/aio/_operations/_operations.py +++ b/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/AzureReportVersionTolerant/azurereportversiontolerant/aio/_operations/_operations.py @@ -9,6 +9,7 @@ from collections.abc import MutableMapping from typing import Any, Callable, Dict, Optional, TypeVar, cast +from azure.core import AsyncPipelineClient from azure.core.exceptions import ( ClientAuthenticationError, HttpResponseError, @@ -22,14 +23,15 @@ from azure.core.tracing.decorator_async import distributed_trace_async from ..._operations._operations import build_auto_rest_report_service_for_azure_get_report_request -from .._vendor import AutoRestReportServiceForAzureMixinABC +from ..._utils.utils import ClientMixinABC +from .._configuration import AutoRestReportServiceForAzureConfiguration T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, AsyncHttpResponse], T, Dict[str, Any]], Any]] class AutoRestReportServiceForAzureOperationsMixin( # pylint: disable=name-too-long - AutoRestReportServiceForAzureMixinABC + ClientMixinABC[AsyncPipelineClient, AutoRestReportServiceForAzureConfiguration] ): @distributed_trace_async diff --git a/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/AzureReportVersionTolerant/azurereportversiontolerant/aio/_vendor.py b/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/AzureReportVersionTolerant/azurereportversiontolerant/aio/_vendor.py deleted file mode 100644 index 769b210a071..00000000000 --- a/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/AzureReportVersionTolerant/azurereportversiontolerant/aio/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) AutoRest Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import AutoRestReportServiceForAzureConfiguration - -if TYPE_CHECKING: - from azure.core import AsyncPipelineClient - - from .._serialization import Deserializer, Serializer - - -class AutoRestReportServiceForAzureMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "AsyncPipelineClient" - _config: AutoRestReportServiceForAzureConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/AzureSpecialsVersionTolerant/azurespecialpropertiesversiontolerant/_client.py b/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/AzureSpecialsVersionTolerant/azurespecialpropertiesversiontolerant/_client.py index 98571a2893c..487cba566f2 100644 --- a/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/AzureSpecialsVersionTolerant/azurespecialpropertiesversiontolerant/_client.py +++ b/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/AzureSpecialsVersionTolerant/azurespecialpropertiesversiontolerant/_client.py @@ -18,7 +18,7 @@ from azure.mgmt.core.tools import get_arm_endpoints from ._configuration import AutoRestAzureSpecialParametersTestClientConfiguration -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer from .operations import ( ApiVersionDefaultOperations, ApiVersionLocalOperations, diff --git a/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/AzureSpecialsVersionTolerant/azurespecialpropertiesversiontolerant/_utils/__init__.py b/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/AzureSpecialsVersionTolerant/azurespecialpropertiesversiontolerant/_utils/__init__.py new file mode 100644 index 00000000000..0af9b28f660 --- /dev/null +++ b/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/AzureSpecialsVersionTolerant/azurespecialpropertiesversiontolerant/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/autorest.python/test/dpg/version-tolerant/Expected/AcceptanceTests/DPGCustomizationInitialVersionTolerant/dpgcustomizationinitialversiontolerant/_serialization.py b/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/AzureSpecialsVersionTolerant/azurespecialpropertiesversiontolerant/_utils/serialization.py similarity index 100% rename from packages/autorest.python/test/dpg/version-tolerant/Expected/AcceptanceTests/DPGCustomizationInitialVersionTolerant/dpgcustomizationinitialversiontolerant/_serialization.py rename to packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/AzureSpecialsVersionTolerant/azurespecialpropertiesversiontolerant/_utils/serialization.py diff --git a/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/AzureSpecialsVersionTolerant/azurespecialpropertiesversiontolerant/aio/_client.py b/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/AzureSpecialsVersionTolerant/azurespecialpropertiesversiontolerant/aio/_client.py index 6cdfd296e6f..a06c134429e 100644 --- a/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/AzureSpecialsVersionTolerant/azurespecialpropertiesversiontolerant/aio/_client.py +++ b/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/AzureSpecialsVersionTolerant/azurespecialpropertiesversiontolerant/aio/_client.py @@ -17,7 +17,7 @@ from azure.mgmt.core.policies import AsyncARMAutoResourceProviderRegistrationPolicy from azure.mgmt.core.tools import get_arm_endpoints -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import AutoRestAzureSpecialParametersTestClientConfiguration from .operations import ( ApiVersionDefaultOperations, diff --git a/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/AzureSpecialsVersionTolerant/azurespecialpropertiesversiontolerant/aio/operations/_operations.py b/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/AzureSpecialsVersionTolerant/azurespecialpropertiesversiontolerant/aio/operations/_operations.py index d179be3038c..30d8a4056d8 100644 --- a/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/AzureSpecialsVersionTolerant/azurespecialpropertiesversiontolerant/aio/operations/_operations.py +++ b/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/AzureSpecialsVersionTolerant/azurespecialpropertiesversiontolerant/aio/operations/_operations.py @@ -24,7 +24,7 @@ from azure.core.utils import case_insensitive_dict from azure.mgmt.core.exceptions import ARMErrorFormat -from ..._serialization import Deserializer, Serializer +from ..._utils.serialization import Deserializer, Serializer from ...operations._operations import ( build_api_version_default_get_method_global_not_provided_valid_request, build_api_version_default_get_method_global_valid_request, diff --git a/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/AzureSpecialsVersionTolerant/azurespecialpropertiesversiontolerant/operations/_operations.py b/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/AzureSpecialsVersionTolerant/azurespecialpropertiesversiontolerant/operations/_operations.py index 545247e8311..870cdd9fe48 100644 --- a/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/AzureSpecialsVersionTolerant/azurespecialpropertiesversiontolerant/operations/_operations.py +++ b/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/AzureSpecialsVersionTolerant/azurespecialpropertiesversiontolerant/operations/_operations.py @@ -25,7 +25,7 @@ from azure.mgmt.core.exceptions import ARMErrorFormat from .._configuration import AutoRestAzureSpecialParametersTestClientConfiguration -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/CustomBaseUriVersionTolerant/custombaseurlversiontolerant/_client.py b/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/CustomBaseUriVersionTolerant/custombaseurlversiontolerant/_client.py index 2e2922eb871..ef2e3db6534 100644 --- a/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/CustomBaseUriVersionTolerant/custombaseurlversiontolerant/_client.py +++ b/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/CustomBaseUriVersionTolerant/custombaseurlversiontolerant/_client.py @@ -15,7 +15,7 @@ from azure.core.rest import HttpRequest, HttpResponse from ._configuration import AutoRestParameterizedHostTestClientConfiguration -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer from .operations import PathsOperations diff --git a/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/CustomBaseUriVersionTolerant/custombaseurlversiontolerant/_utils/__init__.py b/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/CustomBaseUriVersionTolerant/custombaseurlversiontolerant/_utils/__init__.py new file mode 100644 index 00000000000..0af9b28f660 --- /dev/null +++ b/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/CustomBaseUriVersionTolerant/custombaseurlversiontolerant/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/autorest.python/test/dpg/version-tolerant/Expected/AcceptanceTests/DPGServiceDrivenInitialVersionTolerant/dpgservicedriveninitialversiontolerant/_serialization.py b/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/CustomBaseUriVersionTolerant/custombaseurlversiontolerant/_utils/serialization.py similarity index 100% rename from packages/autorest.python/test/dpg/version-tolerant/Expected/AcceptanceTests/DPGServiceDrivenInitialVersionTolerant/dpgservicedriveninitialversiontolerant/_serialization.py rename to packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/CustomBaseUriVersionTolerant/custombaseurlversiontolerant/_utils/serialization.py diff --git a/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/CustomBaseUriVersionTolerant/custombaseurlversiontolerant/aio/_client.py b/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/CustomBaseUriVersionTolerant/custombaseurlversiontolerant/aio/_client.py index 24bc4d89166..0c857272e94 100644 --- a/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/CustomBaseUriVersionTolerant/custombaseurlversiontolerant/aio/_client.py +++ b/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/CustomBaseUriVersionTolerant/custombaseurlversiontolerant/aio/_client.py @@ -14,7 +14,7 @@ from azure.core.pipeline import policies from azure.core.rest import AsyncHttpResponse, HttpRequest -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import AutoRestParameterizedHostTestClientConfiguration from .operations import PathsOperations diff --git a/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/CustomBaseUriVersionTolerant/custombaseurlversiontolerant/aio/operations/_operations.py b/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/CustomBaseUriVersionTolerant/custombaseurlversiontolerant/aio/operations/_operations.py index c2f9d10d4e1..f22ba71db4f 100644 --- a/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/CustomBaseUriVersionTolerant/custombaseurlversiontolerant/aio/operations/_operations.py +++ b/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/CustomBaseUriVersionTolerant/custombaseurlversiontolerant/aio/operations/_operations.py @@ -21,7 +21,7 @@ from azure.core.rest import AsyncHttpResponse, HttpRequest from azure.core.tracing.decorator_async import distributed_trace_async -from ..._serialization import Deserializer, Serializer +from ..._utils.serialization import Deserializer, Serializer from ...operations._operations import build_paths_get_empty_request from .._configuration import AutoRestParameterizedHostTestClientConfiguration diff --git a/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/CustomBaseUriVersionTolerant/custombaseurlversiontolerant/operations/_operations.py b/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/CustomBaseUriVersionTolerant/custombaseurlversiontolerant/operations/_operations.py index d1ef42c250c..7a499bc8585 100644 --- a/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/CustomBaseUriVersionTolerant/custombaseurlversiontolerant/operations/_operations.py +++ b/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/CustomBaseUriVersionTolerant/custombaseurlversiontolerant/operations/_operations.py @@ -23,7 +23,7 @@ from azure.core.utils import case_insensitive_dict from .._configuration import AutoRestParameterizedHostTestClientConfiguration -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/CustomPollerPagerVersionTolerant/custompollerpagerversiontolerant/_client.py b/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/CustomPollerPagerVersionTolerant/custompollerpagerversiontolerant/_client.py index 1f6e0e08d92..0b7db561f0d 100644 --- a/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/CustomPollerPagerVersionTolerant/custompollerpagerversiontolerant/_client.py +++ b/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/CustomPollerPagerVersionTolerant/custompollerpagerversiontolerant/_client.py @@ -18,7 +18,7 @@ from azure.mgmt.core.tools import get_arm_endpoints from ._configuration import AutoRestPagingTestServiceConfiguration -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer from .operations import PagingOperations if TYPE_CHECKING: diff --git a/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/CustomPollerPagerVersionTolerant/custompollerpagerversiontolerant/_utils/__init__.py b/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/CustomPollerPagerVersionTolerant/custompollerpagerversiontolerant/_utils/__init__.py new file mode 100644 index 00000000000..0af9b28f660 --- /dev/null +++ b/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/CustomPollerPagerVersionTolerant/custompollerpagerversiontolerant/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/autorest.python/test/dpg/version-tolerant/Expected/AcceptanceTests/DPGServiceDrivenUpdateOneVersionTolerant/dpgservicedrivenupdateoneversiontolerant/_serialization.py b/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/CustomPollerPagerVersionTolerant/custompollerpagerversiontolerant/_utils/serialization.py similarity index 100% rename from packages/autorest.python/test/dpg/version-tolerant/Expected/AcceptanceTests/DPGServiceDrivenUpdateOneVersionTolerant/dpgservicedrivenupdateoneversiontolerant/_serialization.py rename to packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/CustomPollerPagerVersionTolerant/custompollerpagerversiontolerant/_utils/serialization.py diff --git a/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/CustomPollerPagerVersionTolerant/custompollerpagerversiontolerant/aio/_client.py b/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/CustomPollerPagerVersionTolerant/custompollerpagerversiontolerant/aio/_client.py index e30858bf239..998c1f075d8 100644 --- a/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/CustomPollerPagerVersionTolerant/custompollerpagerversiontolerant/aio/_client.py +++ b/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/CustomPollerPagerVersionTolerant/custompollerpagerversiontolerant/aio/_client.py @@ -17,7 +17,7 @@ from azure.mgmt.core.policies import AsyncARMAutoResourceProviderRegistrationPolicy from azure.mgmt.core.tools import get_arm_endpoints -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import AutoRestPagingTestServiceConfiguration from .operations import PagingOperations diff --git a/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/CustomPollerPagerVersionTolerant/custompollerpagerversiontolerant/aio/operations/_operations.py b/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/CustomPollerPagerVersionTolerant/custompollerpagerversiontolerant/aio/operations/_operations.py index db0890044ed..c691f36ceb8 100644 --- a/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/CustomPollerPagerVersionTolerant/custompollerpagerversiontolerant/aio/operations/_operations.py +++ b/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/CustomPollerPagerVersionTolerant/custompollerpagerversiontolerant/aio/operations/_operations.py @@ -47,7 +47,7 @@ from azure.mgmt.core.exceptions import ARMErrorFormat from azure.mgmt.core.polling.async_arm_polling import AsyncARMPolling -from ..._serialization import Deserializer, Serializer +from ..._utils.serialization import Deserializer, Serializer from ...operations._operations import ( build_paging_append_api_version_request, build_paging_duplicate_params_request, diff --git a/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/CustomPollerPagerVersionTolerant/custompollerpagerversiontolerant/operations/_operations.py b/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/CustomPollerPagerVersionTolerant/custompollerpagerversiontolerant/operations/_operations.py index d82d804d229..999a6faf1e9 100644 --- a/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/CustomPollerPagerVersionTolerant/custompollerpagerversiontolerant/operations/_operations.py +++ b/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/CustomPollerPagerVersionTolerant/custompollerpagerversiontolerant/operations/_operations.py @@ -34,7 +34,7 @@ from azure.mgmt.core.polling.arm_polling import ARMPolling from .._configuration import AutoRestPagingTestServiceConfiguration -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer JSON = MutableMapping[str, Any] T = TypeVar("T") diff --git a/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/CustomUrlPagingVersionTolerant/custombaseurlpagingversiontolerant/_client.py b/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/CustomUrlPagingVersionTolerant/custombaseurlpagingversiontolerant/_client.py index 06bb111b020..fee40a61362 100644 --- a/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/CustomUrlPagingVersionTolerant/custombaseurlpagingversiontolerant/_client.py +++ b/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/CustomUrlPagingVersionTolerant/custombaseurlpagingversiontolerant/_client.py @@ -15,7 +15,7 @@ from azure.core.rest import HttpRequest, HttpResponse from ._configuration import AutoRestParameterizedHostTestPagingClientConfiguration -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer from .operations import PagingOperations diff --git a/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/CustomUrlPagingVersionTolerant/custombaseurlpagingversiontolerant/_utils/__init__.py b/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/CustomUrlPagingVersionTolerant/custombaseurlpagingversiontolerant/_utils/__init__.py new file mode 100644 index 00000000000..0af9b28f660 --- /dev/null +++ b/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/CustomUrlPagingVersionTolerant/custombaseurlpagingversiontolerant/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/autorest.python/test/dpg/version-tolerant/Expected/AcceptanceTests/DPGTestModelsVersionTolerant/dpgtestmodelsversiontolerant/_serialization.py b/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/CustomUrlPagingVersionTolerant/custombaseurlpagingversiontolerant/_utils/serialization.py similarity index 100% rename from packages/autorest.python/test/dpg/version-tolerant/Expected/AcceptanceTests/DPGTestModelsVersionTolerant/dpgtestmodelsversiontolerant/_serialization.py rename to packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/CustomUrlPagingVersionTolerant/custombaseurlpagingversiontolerant/_utils/serialization.py diff --git a/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/CustomUrlPagingVersionTolerant/custombaseurlpagingversiontolerant/aio/_client.py b/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/CustomUrlPagingVersionTolerant/custombaseurlpagingversiontolerant/aio/_client.py index f1bb93da7fe..109050b717c 100644 --- a/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/CustomUrlPagingVersionTolerant/custombaseurlpagingversiontolerant/aio/_client.py +++ b/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/CustomUrlPagingVersionTolerant/custombaseurlpagingversiontolerant/aio/_client.py @@ -14,7 +14,7 @@ from azure.core.pipeline import policies from azure.core.rest import AsyncHttpResponse, HttpRequest -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import AutoRestParameterizedHostTestPagingClientConfiguration from .operations import PagingOperations diff --git a/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/CustomUrlPagingVersionTolerant/custombaseurlpagingversiontolerant/aio/operations/_operations.py b/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/CustomUrlPagingVersionTolerant/custombaseurlpagingversiontolerant/aio/operations/_operations.py index e2ffa330b28..123dade20cb 100644 --- a/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/CustomUrlPagingVersionTolerant/custombaseurlpagingversiontolerant/aio/operations/_operations.py +++ b/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/CustomUrlPagingVersionTolerant/custombaseurlpagingversiontolerant/aio/operations/_operations.py @@ -22,7 +22,7 @@ from azure.core.rest import AsyncHttpResponse, HttpRequest from azure.core.tracing.decorator import distributed_trace -from ..._serialization import Deserializer, Serializer +from ..._utils.serialization import Deserializer, Serializer from ...operations._operations import ( build_paging_get_pages_partial_url_operation_next_request, build_paging_get_pages_partial_url_operation_request, diff --git a/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/CustomUrlPagingVersionTolerant/custombaseurlpagingversiontolerant/operations/_operations.py b/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/CustomUrlPagingVersionTolerant/custombaseurlpagingversiontolerant/operations/_operations.py index c6b38d70a2c..a2b97fe0f48 100644 --- a/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/CustomUrlPagingVersionTolerant/custombaseurlpagingversiontolerant/operations/_operations.py +++ b/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/CustomUrlPagingVersionTolerant/custombaseurlpagingversiontolerant/operations/_operations.py @@ -24,7 +24,7 @@ from azure.core.utils import case_insensitive_dict from .._configuration import AutoRestParameterizedHostTestPagingClientConfiguration -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer JSON = MutableMapping[str, Any] T = TypeVar("T") diff --git a/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/HeadExceptionsVersionTolerant/headexceptionsversiontolerant/_client.py b/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/HeadExceptionsVersionTolerant/headexceptionsversiontolerant/_client.py index 4fa12a6f66c..b6b575bac12 100644 --- a/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/HeadExceptionsVersionTolerant/headexceptionsversiontolerant/_client.py +++ b/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/HeadExceptionsVersionTolerant/headexceptionsversiontolerant/_client.py @@ -18,7 +18,7 @@ from azure.mgmt.core.tools import get_arm_endpoints from ._configuration import AutoRestHeadExceptionTestServiceConfiguration -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer from .operations import HeadExceptionOperations if TYPE_CHECKING: diff --git a/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/HeadExceptionsVersionTolerant/headexceptionsversiontolerant/_utils/__init__.py b/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/HeadExceptionsVersionTolerant/headexceptionsversiontolerant/_utils/__init__.py new file mode 100644 index 00000000000..0af9b28f660 --- /dev/null +++ b/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/HeadExceptionsVersionTolerant/headexceptionsversiontolerant/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/AdditionalProperties/additionalproperties/_serialization.py b/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/HeadExceptionsVersionTolerant/headexceptionsversiontolerant/_utils/serialization.py similarity index 100% rename from packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/AdditionalProperties/additionalproperties/_serialization.py rename to packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/HeadExceptionsVersionTolerant/headexceptionsversiontolerant/_utils/serialization.py diff --git a/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/HeadExceptionsVersionTolerant/headexceptionsversiontolerant/aio/_client.py b/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/HeadExceptionsVersionTolerant/headexceptionsversiontolerant/aio/_client.py index 82395760165..84aadb9a04f 100644 --- a/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/HeadExceptionsVersionTolerant/headexceptionsversiontolerant/aio/_client.py +++ b/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/HeadExceptionsVersionTolerant/headexceptionsversiontolerant/aio/_client.py @@ -17,7 +17,7 @@ from azure.mgmt.core.policies import AsyncARMAutoResourceProviderRegistrationPolicy from azure.mgmt.core.tools import get_arm_endpoints -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import AutoRestHeadExceptionTestServiceConfiguration from .operations import HeadExceptionOperations diff --git a/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/HeadExceptionsVersionTolerant/headexceptionsversiontolerant/aio/operations/_operations.py b/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/HeadExceptionsVersionTolerant/headexceptionsversiontolerant/aio/operations/_operations.py index c6d107dfa5c..819bf3414e9 100644 --- a/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/HeadExceptionsVersionTolerant/headexceptionsversiontolerant/aio/operations/_operations.py +++ b/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/HeadExceptionsVersionTolerant/headexceptionsversiontolerant/aio/operations/_operations.py @@ -22,7 +22,7 @@ from azure.core.tracing.decorator_async import distributed_trace_async from azure.mgmt.core.exceptions import ARMErrorFormat -from ..._serialization import Deserializer, Serializer +from ..._utils.serialization import Deserializer, Serializer from ...operations._operations import ( build_head_exception_head200_request, build_head_exception_head204_request, diff --git a/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/HeadExceptionsVersionTolerant/headexceptionsversiontolerant/operations/_operations.py b/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/HeadExceptionsVersionTolerant/headexceptionsversiontolerant/operations/_operations.py index 07d334e9d8c..80ab5b24fdf 100644 --- a/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/HeadExceptionsVersionTolerant/headexceptionsversiontolerant/operations/_operations.py +++ b/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/HeadExceptionsVersionTolerant/headexceptionsversiontolerant/operations/_operations.py @@ -23,7 +23,7 @@ from azure.mgmt.core.exceptions import ARMErrorFormat from .._configuration import AutoRestHeadExceptionTestServiceConfiguration -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/HeadVersionTolerant/headversiontolerant/_client.py b/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/HeadVersionTolerant/headversiontolerant/_client.py index daefa8e54fd..bfd2b92d7eb 100644 --- a/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/HeadVersionTolerant/headversiontolerant/_client.py +++ b/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/HeadVersionTolerant/headversiontolerant/_client.py @@ -18,7 +18,7 @@ from azure.mgmt.core.tools import get_arm_endpoints from ._configuration import AutoRestHeadTestServiceConfiguration -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer from .operations import HttpSuccessOperations if TYPE_CHECKING: diff --git a/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/HeadVersionTolerant/headversiontolerant/_utils/__init__.py b/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/HeadVersionTolerant/headversiontolerant/_utils/__init__.py new file mode 100644 index 00000000000..0af9b28f660 --- /dev/null +++ b/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/HeadVersionTolerant/headversiontolerant/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Anything/anything/_serialization.py b/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/HeadVersionTolerant/headversiontolerant/_utils/serialization.py similarity index 100% rename from packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Anything/anything/_serialization.py rename to packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/HeadVersionTolerant/headversiontolerant/_utils/serialization.py diff --git a/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/HeadVersionTolerant/headversiontolerant/aio/_client.py b/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/HeadVersionTolerant/headversiontolerant/aio/_client.py index 8d54509fb80..ff757129999 100644 --- a/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/HeadVersionTolerant/headversiontolerant/aio/_client.py +++ b/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/HeadVersionTolerant/headversiontolerant/aio/_client.py @@ -17,7 +17,7 @@ from azure.mgmt.core.policies import AsyncARMAutoResourceProviderRegistrationPolicy from azure.mgmt.core.tools import get_arm_endpoints -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import AutoRestHeadTestServiceConfiguration from .operations import HttpSuccessOperations diff --git a/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/HeadVersionTolerant/headversiontolerant/aio/operations/_operations.py b/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/HeadVersionTolerant/headversiontolerant/aio/operations/_operations.py index 9dbcc2f5aed..704d30f4fc3 100644 --- a/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/HeadVersionTolerant/headversiontolerant/aio/operations/_operations.py +++ b/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/HeadVersionTolerant/headversiontolerant/aio/operations/_operations.py @@ -22,7 +22,7 @@ from azure.core.tracing.decorator_async import distributed_trace_async from azure.mgmt.core.exceptions import ARMErrorFormat -from ..._serialization import Deserializer, Serializer +from ..._utils.serialization import Deserializer, Serializer from ...operations._operations import ( build_http_success_head200_request, build_http_success_head204_request, diff --git a/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/HeadVersionTolerant/headversiontolerant/operations/_operations.py b/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/HeadVersionTolerant/headversiontolerant/operations/_operations.py index 181f2616584..00d592df91b 100644 --- a/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/HeadVersionTolerant/headversiontolerant/operations/_operations.py +++ b/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/HeadVersionTolerant/headversiontolerant/operations/_operations.py @@ -23,7 +23,7 @@ from azure.mgmt.core.exceptions import ARMErrorFormat from .._configuration import AutoRestHeadTestServiceConfiguration -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/LroPagingVersionTolerant/lropagingversiontolerant/_client.py b/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/LroPagingVersionTolerant/lropagingversiontolerant/_client.py index 28cd1b71c18..6614ebf22b3 100644 --- a/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/LroPagingVersionTolerant/lropagingversiontolerant/_client.py +++ b/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/LroPagingVersionTolerant/lropagingversiontolerant/_client.py @@ -15,7 +15,7 @@ from azure.core.rest import HttpRequest, HttpResponse from ._configuration import LroPagingClientConfiguration -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer from .operations import QuestionAnsweringProjectsOperations diff --git a/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/LroPagingVersionTolerant/lropagingversiontolerant/_utils/__init__.py b/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/LroPagingVersionTolerant/lropagingversiontolerant/_utils/__init__.py new file mode 100644 index 00000000000..0af9b28f660 --- /dev/null +++ b/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/LroPagingVersionTolerant/lropagingversiontolerant/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyArray/bodyarray/_serialization.py b/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/LroPagingVersionTolerant/lropagingversiontolerant/_utils/serialization.py similarity index 100% rename from packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyArray/bodyarray/_serialization.py rename to packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/LroPagingVersionTolerant/lropagingversiontolerant/_utils/serialization.py diff --git a/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/LroPagingVersionTolerant/lropagingversiontolerant/aio/_client.py b/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/LroPagingVersionTolerant/lropagingversiontolerant/aio/_client.py index 9e5eb9c898d..f67a7bde5c9 100644 --- a/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/LroPagingVersionTolerant/lropagingversiontolerant/aio/_client.py +++ b/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/LroPagingVersionTolerant/lropagingversiontolerant/aio/_client.py @@ -14,7 +14,7 @@ from azure.core.pipeline import policies from azure.core.rest import AsyncHttpResponse, HttpRequest -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import LroPagingClientConfiguration from .operations import QuestionAnsweringProjectsOperations diff --git a/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/LroPagingVersionTolerant/lropagingversiontolerant/aio/operations/_operations.py b/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/LroPagingVersionTolerant/lropagingversiontolerant/aio/operations/_operations.py index c041339c9dd..8c983b9c8e7 100644 --- a/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/LroPagingVersionTolerant/lropagingversiontolerant/aio/operations/_operations.py +++ b/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/LroPagingVersionTolerant/lropagingversiontolerant/aio/operations/_operations.py @@ -30,7 +30,7 @@ from azure.core.tracing.decorator_async import distributed_trace_async from azure.core.utils import case_insensitive_dict -from ..._serialization import Deserializer, Serializer +from ..._utils.serialization import Deserializer, Serializer from ...operations._operations import ( build_question_answering_projects_get_qnas_request, build_question_answering_projects_update_qnas_request, diff --git a/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/LroPagingVersionTolerant/lropagingversiontolerant/operations/_operations.py b/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/LroPagingVersionTolerant/lropagingversiontolerant/operations/_operations.py index a3edf57f16d..b6f3b60be3e 100644 --- a/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/LroPagingVersionTolerant/lropagingversiontolerant/operations/_operations.py +++ b/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/LroPagingVersionTolerant/lropagingversiontolerant/operations/_operations.py @@ -30,7 +30,7 @@ from azure.core.utils import case_insensitive_dict from .._configuration import LroPagingClientConfiguration -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer JSON = MutableMapping[str, Any] T = TypeVar("T") diff --git a/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/LroVersionTolerant/lroversiontolerant/_client.py b/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/LroVersionTolerant/lroversiontolerant/_client.py index 8d558487bac..fd28a1407de 100644 --- a/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/LroVersionTolerant/lroversiontolerant/_client.py +++ b/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/LroVersionTolerant/lroversiontolerant/_client.py @@ -18,7 +18,7 @@ from azure.mgmt.core.tools import get_arm_endpoints from ._configuration import AutoRestLongRunningOperationTestServiceConfiguration -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer from .operations import LRORetrysOperations, LROSADsOperations, LROsCustomHeaderOperations, LROsOperations if TYPE_CHECKING: diff --git a/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/LroVersionTolerant/lroversiontolerant/_utils/__init__.py b/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/LroVersionTolerant/lroversiontolerant/_utils/__init__.py new file mode 100644 index 00000000000..0af9b28f660 --- /dev/null +++ b/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/LroVersionTolerant/lroversiontolerant/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyArrayWithNamespaceFolders/vanilla/body/array/_serialization.py b/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/LroVersionTolerant/lroversiontolerant/_utils/serialization.py similarity index 100% rename from packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyArrayWithNamespaceFolders/vanilla/body/array/_serialization.py rename to packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/LroVersionTolerant/lroversiontolerant/_utils/serialization.py diff --git a/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/LroVersionTolerant/lroversiontolerant/aio/_client.py b/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/LroVersionTolerant/lroversiontolerant/aio/_client.py index b35c3c7c48b..28dada4d2ef 100644 --- a/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/LroVersionTolerant/lroversiontolerant/aio/_client.py +++ b/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/LroVersionTolerant/lroversiontolerant/aio/_client.py @@ -17,7 +17,7 @@ from azure.mgmt.core.policies import AsyncARMAutoResourceProviderRegistrationPolicy from azure.mgmt.core.tools import get_arm_endpoints -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import AutoRestLongRunningOperationTestServiceConfiguration from .operations import LRORetrysOperations, LROSADsOperations, LROsCustomHeaderOperations, LROsOperations diff --git a/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/LroVersionTolerant/lroversiontolerant/aio/operations/_operations.py b/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/LroVersionTolerant/lroversiontolerant/aio/operations/_operations.py index 689a9b62100..95357731d62 100644 --- a/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/LroVersionTolerant/lroversiontolerant/aio/operations/_operations.py +++ b/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/LroVersionTolerant/lroversiontolerant/aio/operations/_operations.py @@ -29,7 +29,7 @@ from azure.mgmt.core.exceptions import ARMErrorFormat from azure.mgmt.core.polling.async_arm_polling import AsyncARMPolling -from ..._serialization import Deserializer, Serializer +from ..._utils.serialization import Deserializer, Serializer from ...operations._operations import ( build_lr_os_custom_header_post202_retry200_request, build_lr_os_custom_header_post_async_retry_succeeded_request, diff --git a/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/LroVersionTolerant/lroversiontolerant/operations/_operations.py b/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/LroVersionTolerant/lroversiontolerant/operations/_operations.py index 4d06556b46c..3702cee3f7e 100644 --- a/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/LroVersionTolerant/lroversiontolerant/operations/_operations.py +++ b/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/LroVersionTolerant/lroversiontolerant/operations/_operations.py @@ -30,7 +30,7 @@ from azure.mgmt.core.polling.arm_polling import ARMPolling from .._configuration import AutoRestLongRunningOperationTestServiceConfiguration -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer JSON = MutableMapping[str, Any] T = TypeVar("T") diff --git a/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/LroWithParameterizedEndpointsVersionTolerant/lrowithparameterizedendpointsversiontolerant/_client.py b/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/LroWithParameterizedEndpointsVersionTolerant/lrowithparameterizedendpointsversiontolerant/_client.py index 5d8c00382b6..ce8ff8d355c 100644 --- a/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/LroWithParameterizedEndpointsVersionTolerant/lrowithparameterizedendpointsversiontolerant/_client.py +++ b/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/LroWithParameterizedEndpointsVersionTolerant/lrowithparameterizedendpointsversiontolerant/_client.py @@ -16,7 +16,7 @@ from ._configuration import LROWithParamaterizedEndpointsConfiguration from ._operations import LROWithParamaterizedEndpointsOperationsMixin -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer class LROWithParamaterizedEndpoints( diff --git a/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/LroWithParameterizedEndpointsVersionTolerant/lrowithparameterizedendpointsversiontolerant/_operations/_operations.py b/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/LroWithParameterizedEndpointsVersionTolerant/lrowithparameterizedendpointsversiontolerant/_operations/_operations.py index c74320bbc6a..ad9099d09fb 100644 --- a/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/LroWithParameterizedEndpointsVersionTolerant/lrowithparameterizedendpointsversiontolerant/_operations/_operations.py +++ b/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/LroWithParameterizedEndpointsVersionTolerant/lrowithparameterizedendpointsversiontolerant/_operations/_operations.py @@ -9,6 +9,7 @@ from collections.abc import MutableMapping from typing import Any, Callable, Dict, Iterator, Literal, Optional, TypeVar, Union, cast +from azure.core import PipelineClient from azure.core.exceptions import ( ClientAuthenticationError, HttpResponseError, @@ -26,8 +27,9 @@ from azure.core.tracing.decorator import distributed_trace from azure.core.utils import case_insensitive_dict -from .._serialization import Serializer -from .._vendor import LROWithParamaterizedEndpointsMixinABC +from .._configuration import LROWithParamaterizedEndpointsConfiguration +from .._utils.serialization import Serializer +from .._utils.utils import ClientMixinABC T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] @@ -75,7 +77,7 @@ def build_lro_with_paramaterized_endpoints_poll_with_constant_parameterized_endp class LROWithParamaterizedEndpointsOperationsMixin( # pylint: disable=name-too-long - LROWithParamaterizedEndpointsMixinABC + ClientMixinABC[PipelineClient, LROWithParamaterizedEndpointsConfiguration] ): def _poll_with_parameterized_endpoints_initial( # pylint: disable=name-too-long diff --git a/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/LroWithParameterizedEndpointsVersionTolerant/lrowithparameterizedendpointsversiontolerant/_utils/__init__.py b/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/LroWithParameterizedEndpointsVersionTolerant/lrowithparameterizedendpointsversiontolerant/_utils/__init__.py new file mode 100644 index 00000000000..0af9b28f660 --- /dev/null +++ b/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/LroWithParameterizedEndpointsVersionTolerant/lrowithparameterizedendpointsversiontolerant/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyBinary/bodybinary/_serialization.py b/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/LroWithParameterizedEndpointsVersionTolerant/lrowithparameterizedendpointsversiontolerant/_utils/serialization.py similarity index 100% rename from packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyBinary/bodybinary/_serialization.py rename to packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/LroWithParameterizedEndpointsVersionTolerant/lrowithparameterizedendpointsversiontolerant/_utils/serialization.py diff --git a/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/LroWithParameterizedEndpointsVersionTolerant/lrowithparameterizedendpointsversiontolerant/_utils/utils.py b/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/LroWithParameterizedEndpointsVersionTolerant/lrowithparameterizedendpointsversiontolerant/_utils/utils.py new file mode 100644 index 00000000000..39b612f39a9 --- /dev/null +++ b/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/LroWithParameterizedEndpointsVersionTolerant/lrowithparameterizedendpointsversiontolerant/_utils/utils.py @@ -0,0 +1,25 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from abc import ABC +from typing import Generic, TYPE_CHECKING, TypeVar + +if TYPE_CHECKING: + from .serialization import Deserializer, Serializer + + +TClient = TypeVar("TClient") +TConfig = TypeVar("TConfig") + + +class ClientMixinABC(ABC, Generic[TClient, TConfig]): + """DO NOT use this class. It is for internal typing use only.""" + + _client: TClient + _config: TConfig + _serialize: "Serializer" + _deserialize: "Deserializer" diff --git a/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/LroWithParameterizedEndpointsVersionTolerant/lrowithparameterizedendpointsversiontolerant/_vendor.py b/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/LroWithParameterizedEndpointsVersionTolerant/lrowithparameterizedendpointsversiontolerant/_vendor.py deleted file mode 100644 index fcf80212404..00000000000 --- a/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/LroWithParameterizedEndpointsVersionTolerant/lrowithparameterizedendpointsversiontolerant/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) AutoRest Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import LROWithParamaterizedEndpointsConfiguration - -if TYPE_CHECKING: - from azure.core import PipelineClient - - from ._serialization import Deserializer, Serializer - - -class LROWithParamaterizedEndpointsMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "PipelineClient" - _config: LROWithParamaterizedEndpointsConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/LroWithParameterizedEndpointsVersionTolerant/lrowithparameterizedendpointsversiontolerant/aio/_client.py b/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/LroWithParameterizedEndpointsVersionTolerant/lrowithparameterizedendpointsversiontolerant/aio/_client.py index 55b5b1d5086..7fede7659b7 100644 --- a/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/LroWithParameterizedEndpointsVersionTolerant/lrowithparameterizedendpointsversiontolerant/aio/_client.py +++ b/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/LroWithParameterizedEndpointsVersionTolerant/lrowithparameterizedendpointsversiontolerant/aio/_client.py @@ -14,7 +14,7 @@ from azure.core.pipeline import policies from azure.core.rest import AsyncHttpResponse, HttpRequest -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import LROWithParamaterizedEndpointsConfiguration from ._operations import LROWithParamaterizedEndpointsOperationsMixin diff --git a/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/LroWithParameterizedEndpointsVersionTolerant/lrowithparameterizedendpointsversiontolerant/aio/_operations/_operations.py b/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/LroWithParameterizedEndpointsVersionTolerant/lrowithparameterizedendpointsversiontolerant/aio/_operations/_operations.py index dd7c1937fec..878dc043c49 100644 --- a/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/LroWithParameterizedEndpointsVersionTolerant/lrowithparameterizedendpointsversiontolerant/aio/_operations/_operations.py +++ b/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/LroWithParameterizedEndpointsVersionTolerant/lrowithparameterizedendpointsversiontolerant/aio/_operations/_operations.py @@ -9,6 +9,7 @@ from collections.abc import MutableMapping from typing import Any, AsyncIterator, Callable, Dict, Literal, Optional, TypeVar, Union, cast +from azure.core import AsyncPipelineClient from azure.core.exceptions import ( ClientAuthenticationError, HttpResponseError, @@ -29,14 +30,15 @@ build_lro_with_paramaterized_endpoints_poll_with_constant_parameterized_endpoints_request, build_lro_with_paramaterized_endpoints_poll_with_parameterized_endpoints_request, ) -from .._vendor import LROWithParamaterizedEndpointsMixinABC +from ..._utils.utils import ClientMixinABC +from .._configuration import LROWithParamaterizedEndpointsConfiguration T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, AsyncHttpResponse], T, Dict[str, Any]], Any]] class LROWithParamaterizedEndpointsOperationsMixin( # pylint: disable=name-too-long - LROWithParamaterizedEndpointsMixinABC + ClientMixinABC[AsyncPipelineClient, LROWithParamaterizedEndpointsConfiguration] ): async def _poll_with_parameterized_endpoints_initial( # pylint: disable=name-too-long diff --git a/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/LroWithParameterizedEndpointsVersionTolerant/lrowithparameterizedendpointsversiontolerant/aio/_vendor.py b/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/LroWithParameterizedEndpointsVersionTolerant/lrowithparameterizedendpointsversiontolerant/aio/_vendor.py deleted file mode 100644 index 65404a7e264..00000000000 --- a/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/LroWithParameterizedEndpointsVersionTolerant/lrowithparameterizedendpointsversiontolerant/aio/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) AutoRest Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import LROWithParamaterizedEndpointsConfiguration - -if TYPE_CHECKING: - from azure.core import AsyncPipelineClient - - from .._serialization import Deserializer, Serializer - - -class LROWithParamaterizedEndpointsMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "AsyncPipelineClient" - _config: LROWithParamaterizedEndpointsConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/PagingVersionTolerant/pagingversiontolerant/_client.py b/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/PagingVersionTolerant/pagingversiontolerant/_client.py index 97ab44952b4..3c682244e32 100644 --- a/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/PagingVersionTolerant/pagingversiontolerant/_client.py +++ b/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/PagingVersionTolerant/pagingversiontolerant/_client.py @@ -15,7 +15,7 @@ from azure.core.rest import HttpRequest, HttpResponse from ._configuration import AutoRestPagingTestServiceConfiguration -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer from .operations import PagingOperations diff --git a/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/PagingVersionTolerant/pagingversiontolerant/_utils/__init__.py b/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/PagingVersionTolerant/pagingversiontolerant/_utils/__init__.py new file mode 100644 index 00000000000..0af9b28f660 --- /dev/null +++ b/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/PagingVersionTolerant/pagingversiontolerant/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyBoolean/bodyboolean/_serialization.py b/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/PagingVersionTolerant/pagingversiontolerant/_utils/serialization.py similarity index 100% rename from packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyBoolean/bodyboolean/_serialization.py rename to packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/PagingVersionTolerant/pagingversiontolerant/_utils/serialization.py diff --git a/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/PagingVersionTolerant/pagingversiontolerant/aio/_client.py b/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/PagingVersionTolerant/pagingversiontolerant/aio/_client.py index 56153e719c5..a485172c8d6 100644 --- a/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/PagingVersionTolerant/pagingversiontolerant/aio/_client.py +++ b/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/PagingVersionTolerant/pagingversiontolerant/aio/_client.py @@ -14,7 +14,7 @@ from azure.core.pipeline import policies from azure.core.rest import AsyncHttpResponse, HttpRequest -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import AutoRestPagingTestServiceConfiguration from .operations import PagingOperations diff --git a/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/PagingVersionTolerant/pagingversiontolerant/aio/operations/_operations.py b/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/PagingVersionTolerant/pagingversiontolerant/aio/operations/_operations.py index b3c13971be8..826bd8c0776 100644 --- a/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/PagingVersionTolerant/pagingversiontolerant/aio/operations/_operations.py +++ b/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/PagingVersionTolerant/pagingversiontolerant/aio/operations/_operations.py @@ -44,7 +44,7 @@ from azure.core.tracing.decorator_async import distributed_trace_async from azure.core.utils import case_insensitive_dict -from ..._serialization import Deserializer, Serializer +from ..._utils.serialization import Deserializer, Serializer from ...operations._operations import ( build_paging_append_api_version_request, build_paging_duplicate_params_request, diff --git a/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/PagingVersionTolerant/pagingversiontolerant/operations/_operations.py b/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/PagingVersionTolerant/pagingversiontolerant/operations/_operations.py index 7babb316212..521b018d454 100644 --- a/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/PagingVersionTolerant/pagingversiontolerant/operations/_operations.py +++ b/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/PagingVersionTolerant/pagingversiontolerant/operations/_operations.py @@ -31,7 +31,7 @@ from azure.core.utils import case_insensitive_dict from .._configuration import AutoRestPagingTestServiceConfiguration -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer JSON = MutableMapping[str, Any] T = TypeVar("T") diff --git a/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/StorageManagementClientVersionTolerant/storageversiontolerant/_client.py b/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/StorageManagementClientVersionTolerant/storageversiontolerant/_client.py index 337e4447f27..486f090df02 100644 --- a/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/StorageManagementClientVersionTolerant/storageversiontolerant/_client.py +++ b/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/StorageManagementClientVersionTolerant/storageversiontolerant/_client.py @@ -18,7 +18,7 @@ from azure.mgmt.core.tools import get_arm_endpoints from ._configuration import StorageManagementClientConfiguration -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer from .operations import StorageAccountsOperations, UsageOperations if TYPE_CHECKING: diff --git a/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/StorageManagementClientVersionTolerant/storageversiontolerant/_utils/__init__.py b/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/StorageManagementClientVersionTolerant/storageversiontolerant/_utils/__init__.py new file mode 100644 index 00000000000..0af9b28f660 --- /dev/null +++ b/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/StorageManagementClientVersionTolerant/storageversiontolerant/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyByte/bodybyte/_serialization.py b/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/StorageManagementClientVersionTolerant/storageversiontolerant/_utils/serialization.py similarity index 100% rename from packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyByte/bodybyte/_serialization.py rename to packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/StorageManagementClientVersionTolerant/storageversiontolerant/_utils/serialization.py diff --git a/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/StorageManagementClientVersionTolerant/storageversiontolerant/aio/_client.py b/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/StorageManagementClientVersionTolerant/storageversiontolerant/aio/_client.py index 1669853367d..c40dad635be 100644 --- a/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/StorageManagementClientVersionTolerant/storageversiontolerant/aio/_client.py +++ b/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/StorageManagementClientVersionTolerant/storageversiontolerant/aio/_client.py @@ -17,7 +17,7 @@ from azure.mgmt.core.policies import AsyncARMAutoResourceProviderRegistrationPolicy from azure.mgmt.core.tools import get_arm_endpoints -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import StorageManagementClientConfiguration from .operations import StorageAccountsOperations, UsageOperations diff --git a/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/StorageManagementClientVersionTolerant/storageversiontolerant/aio/operations/_operations.py b/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/StorageManagementClientVersionTolerant/storageversiontolerant/aio/operations/_operations.py index caf0f8a7f9d..6319db14654 100644 --- a/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/StorageManagementClientVersionTolerant/storageversiontolerant/aio/operations/_operations.py +++ b/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/StorageManagementClientVersionTolerant/storageversiontolerant/aio/operations/_operations.py @@ -32,7 +32,7 @@ from azure.mgmt.core.exceptions import ARMErrorFormat from azure.mgmt.core.polling.async_arm_polling import AsyncARMPolling -from ..._serialization import Deserializer, Serializer +from ..._utils.serialization import Deserializer, Serializer from ...operations._operations import ( build_storage_accounts_check_name_availability_request, build_storage_accounts_create_request, diff --git a/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/StorageManagementClientVersionTolerant/storageversiontolerant/operations/_operations.py b/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/StorageManagementClientVersionTolerant/storageversiontolerant/operations/_operations.py index f521215e854..5c30a0f2d2a 100644 --- a/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/StorageManagementClientVersionTolerant/storageversiontolerant/operations/_operations.py +++ b/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/StorageManagementClientVersionTolerant/storageversiontolerant/operations/_operations.py @@ -32,7 +32,7 @@ from azure.mgmt.core.polling.arm_polling import ARMPolling from .._configuration import StorageManagementClientConfiguration -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer JSON = MutableMapping[str, Any] T = TypeVar("T") diff --git a/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/SubscriptionIdApiVersionVersionTolerant/subscriptionidapiversionversiontolerant/_client.py b/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/SubscriptionIdApiVersionVersionTolerant/subscriptionidapiversionversiontolerant/_client.py index 86a4acc50c9..173e3259238 100644 --- a/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/SubscriptionIdApiVersionVersionTolerant/subscriptionidapiversionversiontolerant/_client.py +++ b/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/SubscriptionIdApiVersionVersionTolerant/subscriptionidapiversionversiontolerant/_client.py @@ -18,7 +18,7 @@ from azure.mgmt.core.tools import get_arm_endpoints from ._configuration import MicrosoftAzureTestUrlConfiguration -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer from .operations import GroupOperations if TYPE_CHECKING: diff --git a/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/SubscriptionIdApiVersionVersionTolerant/subscriptionidapiversionversiontolerant/_utils/__init__.py b/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/SubscriptionIdApiVersionVersionTolerant/subscriptionidapiversionversiontolerant/_utils/__init__.py new file mode 100644 index 00000000000..0af9b28f660 --- /dev/null +++ b/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/SubscriptionIdApiVersionVersionTolerant/subscriptionidapiversionversiontolerant/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyByteWithPackageName/bodybytewithpackagename/_serialization.py b/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/SubscriptionIdApiVersionVersionTolerant/subscriptionidapiversionversiontolerant/_utils/serialization.py similarity index 100% rename from packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyByteWithPackageName/bodybytewithpackagename/_serialization.py rename to packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/SubscriptionIdApiVersionVersionTolerant/subscriptionidapiversionversiontolerant/_utils/serialization.py diff --git a/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/SubscriptionIdApiVersionVersionTolerant/subscriptionidapiversionversiontolerant/aio/_client.py b/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/SubscriptionIdApiVersionVersionTolerant/subscriptionidapiversionversiontolerant/aio/_client.py index 545134460dd..da4c3c4b0e7 100644 --- a/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/SubscriptionIdApiVersionVersionTolerant/subscriptionidapiversionversiontolerant/aio/_client.py +++ b/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/SubscriptionIdApiVersionVersionTolerant/subscriptionidapiversionversiontolerant/aio/_client.py @@ -17,7 +17,7 @@ from azure.mgmt.core.policies import AsyncARMAutoResourceProviderRegistrationPolicy from azure.mgmt.core.tools import get_arm_endpoints -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import MicrosoftAzureTestUrlConfiguration from .operations import GroupOperations diff --git a/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/SubscriptionIdApiVersionVersionTolerant/subscriptionidapiversionversiontolerant/aio/operations/_operations.py b/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/SubscriptionIdApiVersionVersionTolerant/subscriptionidapiversionversiontolerant/aio/operations/_operations.py index d87de838bdc..53aeb7da208 100644 --- a/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/SubscriptionIdApiVersionVersionTolerant/subscriptionidapiversionversiontolerant/aio/operations/_operations.py +++ b/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/SubscriptionIdApiVersionVersionTolerant/subscriptionidapiversionversiontolerant/aio/operations/_operations.py @@ -22,7 +22,7 @@ from azure.core.tracing.decorator_async import distributed_trace_async from azure.mgmt.core.exceptions import ARMErrorFormat -from ..._serialization import Deserializer, Serializer +from ..._utils.serialization import Deserializer, Serializer from ...operations._operations import build_group_get_sample_resource_group_request from .._configuration import MicrosoftAzureTestUrlConfiguration diff --git a/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/SubscriptionIdApiVersionVersionTolerant/subscriptionidapiversionversiontolerant/operations/_operations.py b/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/SubscriptionIdApiVersionVersionTolerant/subscriptionidapiversionversiontolerant/operations/_operations.py index 935dddd3f54..3b3906d0abd 100644 --- a/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/SubscriptionIdApiVersionVersionTolerant/subscriptionidapiversionversiontolerant/operations/_operations.py +++ b/packages/autorest.python/test/azure/version-tolerant/Expected/AcceptanceTests/SubscriptionIdApiVersionVersionTolerant/subscriptionidapiversionversiontolerant/operations/_operations.py @@ -24,7 +24,7 @@ from azure.mgmt.core.exceptions import ARMErrorFormat from .._configuration import MicrosoftAzureTestUrlConfiguration -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer JSON = MutableMapping[str, Any] T = TypeVar("T") diff --git a/packages/autorest.python/test/azure/version-tolerant/tox.ini b/packages/autorest.python/test/azure/version-tolerant/tox.ini index 252d42ee16f..40cbebeac6c 100644 --- a/packages/autorest.python/test/azure/version-tolerant/tox.ini +++ b/packages/autorest.python/test/azure/version-tolerant/tox.ini @@ -8,7 +8,7 @@ deps= -r requirements.txt -r ../../../../../eng/dev_requirements.txt commands= - pytest --cov=Expected + pytest [testenv:lint] deps= @@ -28,7 +28,7 @@ commands = [testenv:ci] commands = - pytest --cov=Expected + pytest [testenv:apiview] commands = diff --git a/packages/autorest.python/test/dpg/version-tolerant/Expected/AcceptanceTests/DPGCustomizationCustomizedVersionTolerant/dpgcustomizationcustomizedversiontolerant/_client.py b/packages/autorest.python/test/dpg/version-tolerant/Expected/AcceptanceTests/DPGCustomizationCustomizedVersionTolerant/dpgcustomizationcustomizedversiontolerant/_client.py index 19a047fc7bc..b45d5b1d027 100644 --- a/packages/autorest.python/test/dpg/version-tolerant/Expected/AcceptanceTests/DPGCustomizationCustomizedVersionTolerant/dpgcustomizationcustomizedversiontolerant/_client.py +++ b/packages/autorest.python/test/dpg/version-tolerant/Expected/AcceptanceTests/DPGCustomizationCustomizedVersionTolerant/dpgcustomizationcustomizedversiontolerant/_client.py @@ -16,7 +16,7 @@ from ._configuration import DPGClientConfiguration from ._operations import DPGClientOperationsMixin -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer class DPGClient(DPGClientOperationsMixin): # pylint: disable=client-accepts-api-version-keyword diff --git a/packages/autorest.python/test/dpg/version-tolerant/Expected/AcceptanceTests/DPGCustomizationCustomizedVersionTolerant/dpgcustomizationcustomizedversiontolerant/_operations/_operations.py b/packages/autorest.python/test/dpg/version-tolerant/Expected/AcceptanceTests/DPGCustomizationCustomizedVersionTolerant/dpgcustomizationcustomizedversiontolerant/_operations/_operations.py index 45ddc99ae13..821ae81aad3 100644 --- a/packages/autorest.python/test/dpg/version-tolerant/Expected/AcceptanceTests/DPGCustomizationCustomizedVersionTolerant/dpgcustomizationcustomizedversiontolerant/_operations/_operations.py +++ b/packages/autorest.python/test/dpg/version-tolerant/Expected/AcceptanceTests/DPGCustomizationCustomizedVersionTolerant/dpgcustomizationcustomizedversiontolerant/_operations/_operations.py @@ -9,6 +9,7 @@ from io import IOBase from typing import Any, Callable, Dict, IO, Iterable, Iterator, Optional, TypeVar, Union, cast, overload +from azure.core import PipelineClient from azure.core.exceptions import ( ClientAuthenticationError, HttpResponseError, @@ -27,8 +28,9 @@ from azure.core.tracing.decorator import distributed_trace from azure.core.utils import case_insensitive_dict -from .._serialization import Serializer -from .._vendor import DPGClientMixinABC +from .._configuration import DPGClientConfiguration +from .._utils.serialization import Serializer +from .._utils.utils import ClientMixinABC JSON = MutableMapping[str, Any] T = TypeVar("T") @@ -117,7 +119,7 @@ def build_dpg_lro_request(mode: str, **kwargs: Any) -> HttpRequest: return HttpRequest(method="PUT", url=_url, headers=_headers, **kwargs) -class DPGClientOperationsMixin(DPGClientMixinABC): +class DPGClientOperationsMixin(ClientMixinABC[PipelineClient, DPGClientConfiguration]): @distributed_trace def get_model(self, mode: str, **kwargs: Any) -> JSON: diff --git a/packages/autorest.python/test/dpg/version-tolerant/Expected/AcceptanceTests/DPGCustomizationCustomizedVersionTolerant/dpgcustomizationcustomizedversiontolerant/_utils/__init__.py b/packages/autorest.python/test/dpg/version-tolerant/Expected/AcceptanceTests/DPGCustomizationCustomizedVersionTolerant/dpgcustomizationcustomizedversiontolerant/_utils/__init__.py new file mode 100644 index 00000000000..0af9b28f660 --- /dev/null +++ b/packages/autorest.python/test/dpg/version-tolerant/Expected/AcceptanceTests/DPGCustomizationCustomizedVersionTolerant/dpgcustomizationcustomizedversiontolerant/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyDate/bodydate/_serialization.py b/packages/autorest.python/test/dpg/version-tolerant/Expected/AcceptanceTests/DPGCustomizationCustomizedVersionTolerant/dpgcustomizationcustomizedversiontolerant/_utils/serialization.py similarity index 100% rename from packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyDate/bodydate/_serialization.py rename to packages/autorest.python/test/dpg/version-tolerant/Expected/AcceptanceTests/DPGCustomizationCustomizedVersionTolerant/dpgcustomizationcustomizedversiontolerant/_utils/serialization.py diff --git a/packages/autorest.python/test/dpg/version-tolerant/Expected/AcceptanceTests/DPGCustomizationCustomizedVersionTolerant/dpgcustomizationcustomizedversiontolerant/_utils/utils.py b/packages/autorest.python/test/dpg/version-tolerant/Expected/AcceptanceTests/DPGCustomizationCustomizedVersionTolerant/dpgcustomizationcustomizedversiontolerant/_utils/utils.py new file mode 100644 index 00000000000..39b612f39a9 --- /dev/null +++ b/packages/autorest.python/test/dpg/version-tolerant/Expected/AcceptanceTests/DPGCustomizationCustomizedVersionTolerant/dpgcustomizationcustomizedversiontolerant/_utils/utils.py @@ -0,0 +1,25 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from abc import ABC +from typing import Generic, TYPE_CHECKING, TypeVar + +if TYPE_CHECKING: + from .serialization import Deserializer, Serializer + + +TClient = TypeVar("TClient") +TConfig = TypeVar("TConfig") + + +class ClientMixinABC(ABC, Generic[TClient, TConfig]): + """DO NOT use this class. It is for internal typing use only.""" + + _client: TClient + _config: TConfig + _serialize: "Serializer" + _deserialize: "Deserializer" diff --git a/packages/autorest.python/test/dpg/version-tolerant/Expected/AcceptanceTests/DPGCustomizationCustomizedVersionTolerant/dpgcustomizationcustomizedversiontolerant/_vendor.py b/packages/autorest.python/test/dpg/version-tolerant/Expected/AcceptanceTests/DPGCustomizationCustomizedVersionTolerant/dpgcustomizationcustomizedversiontolerant/_vendor.py deleted file mode 100644 index 804ea632d95..00000000000 --- a/packages/autorest.python/test/dpg/version-tolerant/Expected/AcceptanceTests/DPGCustomizationCustomizedVersionTolerant/dpgcustomizationcustomizedversiontolerant/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) AutoRest Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import DPGClientConfiguration - -if TYPE_CHECKING: - from azure.core import PipelineClient - - from ._serialization import Deserializer, Serializer - - -class DPGClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "PipelineClient" - _config: DPGClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/autorest.python/test/dpg/version-tolerant/Expected/AcceptanceTests/DPGCustomizationCustomizedVersionTolerant/dpgcustomizationcustomizedversiontolerant/aio/_client.py b/packages/autorest.python/test/dpg/version-tolerant/Expected/AcceptanceTests/DPGCustomizationCustomizedVersionTolerant/dpgcustomizationcustomizedversiontolerant/aio/_client.py index 144e0aefd15..b8831f49f07 100644 --- a/packages/autorest.python/test/dpg/version-tolerant/Expected/AcceptanceTests/DPGCustomizationCustomizedVersionTolerant/dpgcustomizationcustomizedversiontolerant/aio/_client.py +++ b/packages/autorest.python/test/dpg/version-tolerant/Expected/AcceptanceTests/DPGCustomizationCustomizedVersionTolerant/dpgcustomizationcustomizedversiontolerant/aio/_client.py @@ -14,7 +14,7 @@ from azure.core.pipeline import policies from azure.core.rest import AsyncHttpResponse, HttpRequest -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import DPGClientConfiguration from ._operations import DPGClientOperationsMixin diff --git a/packages/autorest.python/test/dpg/version-tolerant/Expected/AcceptanceTests/DPGCustomizationCustomizedVersionTolerant/dpgcustomizationcustomizedversiontolerant/aio/_operations/_operations.py b/packages/autorest.python/test/dpg/version-tolerant/Expected/AcceptanceTests/DPGCustomizationCustomizedVersionTolerant/dpgcustomizationcustomizedversiontolerant/aio/_operations/_operations.py index f158d4cb908..38ac80d5a65 100644 --- a/packages/autorest.python/test/dpg/version-tolerant/Expected/AcceptanceTests/DPGCustomizationCustomizedVersionTolerant/dpgcustomizationcustomizedversiontolerant/aio/_operations/_operations.py +++ b/packages/autorest.python/test/dpg/version-tolerant/Expected/AcceptanceTests/DPGCustomizationCustomizedVersionTolerant/dpgcustomizationcustomizedversiontolerant/aio/_operations/_operations.py @@ -10,6 +10,7 @@ from io import IOBase from typing import Any, AsyncIterable, AsyncIterator, Callable, Dict, IO, Optional, TypeVar, Union, cast, overload +from azure.core import AsyncPipelineClient from azure.core.async_paging import AsyncItemPaged, AsyncList from azure.core.exceptions import ( ClientAuthenticationError, @@ -35,14 +36,15 @@ build_dpg_lro_request, build_dpg_post_model_request, ) -from .._vendor import DPGClientMixinABC +from ..._utils.utils import ClientMixinABC +from .._configuration import DPGClientConfiguration JSON = MutableMapping[str, Any] T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, AsyncHttpResponse], T, Dict[str, Any]], Any]] -class DPGClientOperationsMixin(DPGClientMixinABC): +class DPGClientOperationsMixin(ClientMixinABC[AsyncPipelineClient, DPGClientConfiguration]): @distributed_trace_async async def get_model(self, mode: str, **kwargs: Any) -> JSON: diff --git a/packages/autorest.python/test/dpg/version-tolerant/Expected/AcceptanceTests/DPGCustomizationCustomizedVersionTolerant/dpgcustomizationcustomizedversiontolerant/aio/_vendor.py b/packages/autorest.python/test/dpg/version-tolerant/Expected/AcceptanceTests/DPGCustomizationCustomizedVersionTolerant/dpgcustomizationcustomizedversiontolerant/aio/_vendor.py deleted file mode 100644 index 189c699866d..00000000000 --- a/packages/autorest.python/test/dpg/version-tolerant/Expected/AcceptanceTests/DPGCustomizationCustomizedVersionTolerant/dpgcustomizationcustomizedversiontolerant/aio/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) AutoRest Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import DPGClientConfiguration - -if TYPE_CHECKING: - from azure.core import AsyncPipelineClient - - from .._serialization import Deserializer, Serializer - - -class DPGClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "AsyncPipelineClient" - _config: DPGClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/autorest.python/test/dpg/version-tolerant/Expected/AcceptanceTests/DPGCustomizationInitialVersionTolerant/dpgcustomizationinitialversiontolerant/_client.py b/packages/autorest.python/test/dpg/version-tolerant/Expected/AcceptanceTests/DPGCustomizationInitialVersionTolerant/dpgcustomizationinitialversiontolerant/_client.py index 19a047fc7bc..b45d5b1d027 100644 --- a/packages/autorest.python/test/dpg/version-tolerant/Expected/AcceptanceTests/DPGCustomizationInitialVersionTolerant/dpgcustomizationinitialversiontolerant/_client.py +++ b/packages/autorest.python/test/dpg/version-tolerant/Expected/AcceptanceTests/DPGCustomizationInitialVersionTolerant/dpgcustomizationinitialversiontolerant/_client.py @@ -16,7 +16,7 @@ from ._configuration import DPGClientConfiguration from ._operations import DPGClientOperationsMixin -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer class DPGClient(DPGClientOperationsMixin): # pylint: disable=client-accepts-api-version-keyword diff --git a/packages/autorest.python/test/dpg/version-tolerant/Expected/AcceptanceTests/DPGCustomizationInitialVersionTolerant/dpgcustomizationinitialversiontolerant/_operations/_operations.py b/packages/autorest.python/test/dpg/version-tolerant/Expected/AcceptanceTests/DPGCustomizationInitialVersionTolerant/dpgcustomizationinitialversiontolerant/_operations/_operations.py index 45ddc99ae13..821ae81aad3 100644 --- a/packages/autorest.python/test/dpg/version-tolerant/Expected/AcceptanceTests/DPGCustomizationInitialVersionTolerant/dpgcustomizationinitialversiontolerant/_operations/_operations.py +++ b/packages/autorest.python/test/dpg/version-tolerant/Expected/AcceptanceTests/DPGCustomizationInitialVersionTolerant/dpgcustomizationinitialversiontolerant/_operations/_operations.py @@ -9,6 +9,7 @@ from io import IOBase from typing import Any, Callable, Dict, IO, Iterable, Iterator, Optional, TypeVar, Union, cast, overload +from azure.core import PipelineClient from azure.core.exceptions import ( ClientAuthenticationError, HttpResponseError, @@ -27,8 +28,9 @@ from azure.core.tracing.decorator import distributed_trace from azure.core.utils import case_insensitive_dict -from .._serialization import Serializer -from .._vendor import DPGClientMixinABC +from .._configuration import DPGClientConfiguration +from .._utils.serialization import Serializer +from .._utils.utils import ClientMixinABC JSON = MutableMapping[str, Any] T = TypeVar("T") @@ -117,7 +119,7 @@ def build_dpg_lro_request(mode: str, **kwargs: Any) -> HttpRequest: return HttpRequest(method="PUT", url=_url, headers=_headers, **kwargs) -class DPGClientOperationsMixin(DPGClientMixinABC): +class DPGClientOperationsMixin(ClientMixinABC[PipelineClient, DPGClientConfiguration]): @distributed_trace def get_model(self, mode: str, **kwargs: Any) -> JSON: diff --git a/packages/autorest.python/test/dpg/version-tolerant/Expected/AcceptanceTests/DPGCustomizationInitialVersionTolerant/dpgcustomizationinitialversiontolerant/_utils/__init__.py b/packages/autorest.python/test/dpg/version-tolerant/Expected/AcceptanceTests/DPGCustomizationInitialVersionTolerant/dpgcustomizationinitialversiontolerant/_utils/__init__.py new file mode 100644 index 00000000000..0af9b28f660 --- /dev/null +++ b/packages/autorest.python/test/dpg/version-tolerant/Expected/AcceptanceTests/DPGCustomizationInitialVersionTolerant/dpgcustomizationinitialversiontolerant/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyDateTime/bodydatetime/_serialization.py b/packages/autorest.python/test/dpg/version-tolerant/Expected/AcceptanceTests/DPGCustomizationInitialVersionTolerant/dpgcustomizationinitialversiontolerant/_utils/serialization.py similarity index 100% rename from packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyDateTime/bodydatetime/_serialization.py rename to packages/autorest.python/test/dpg/version-tolerant/Expected/AcceptanceTests/DPGCustomizationInitialVersionTolerant/dpgcustomizationinitialversiontolerant/_utils/serialization.py diff --git a/packages/autorest.python/test/dpg/version-tolerant/Expected/AcceptanceTests/DPGCustomizationInitialVersionTolerant/dpgcustomizationinitialversiontolerant/_utils/utils.py b/packages/autorest.python/test/dpg/version-tolerant/Expected/AcceptanceTests/DPGCustomizationInitialVersionTolerant/dpgcustomizationinitialversiontolerant/_utils/utils.py new file mode 100644 index 00000000000..39b612f39a9 --- /dev/null +++ b/packages/autorest.python/test/dpg/version-tolerant/Expected/AcceptanceTests/DPGCustomizationInitialVersionTolerant/dpgcustomizationinitialversiontolerant/_utils/utils.py @@ -0,0 +1,25 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from abc import ABC +from typing import Generic, TYPE_CHECKING, TypeVar + +if TYPE_CHECKING: + from .serialization import Deserializer, Serializer + + +TClient = TypeVar("TClient") +TConfig = TypeVar("TConfig") + + +class ClientMixinABC(ABC, Generic[TClient, TConfig]): + """DO NOT use this class. It is for internal typing use only.""" + + _client: TClient + _config: TConfig + _serialize: "Serializer" + _deserialize: "Deserializer" diff --git a/packages/autorest.python/test/dpg/version-tolerant/Expected/AcceptanceTests/DPGCustomizationInitialVersionTolerant/dpgcustomizationinitialversiontolerant/_vendor.py b/packages/autorest.python/test/dpg/version-tolerant/Expected/AcceptanceTests/DPGCustomizationInitialVersionTolerant/dpgcustomizationinitialversiontolerant/_vendor.py deleted file mode 100644 index 804ea632d95..00000000000 --- a/packages/autorest.python/test/dpg/version-tolerant/Expected/AcceptanceTests/DPGCustomizationInitialVersionTolerant/dpgcustomizationinitialversiontolerant/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) AutoRest Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import DPGClientConfiguration - -if TYPE_CHECKING: - from azure.core import PipelineClient - - from ._serialization import Deserializer, Serializer - - -class DPGClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "PipelineClient" - _config: DPGClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/autorest.python/test/dpg/version-tolerant/Expected/AcceptanceTests/DPGCustomizationInitialVersionTolerant/dpgcustomizationinitialversiontolerant/aio/_client.py b/packages/autorest.python/test/dpg/version-tolerant/Expected/AcceptanceTests/DPGCustomizationInitialVersionTolerant/dpgcustomizationinitialversiontolerant/aio/_client.py index 144e0aefd15..b8831f49f07 100644 --- a/packages/autorest.python/test/dpg/version-tolerant/Expected/AcceptanceTests/DPGCustomizationInitialVersionTolerant/dpgcustomizationinitialversiontolerant/aio/_client.py +++ b/packages/autorest.python/test/dpg/version-tolerant/Expected/AcceptanceTests/DPGCustomizationInitialVersionTolerant/dpgcustomizationinitialversiontolerant/aio/_client.py @@ -14,7 +14,7 @@ from azure.core.pipeline import policies from azure.core.rest import AsyncHttpResponse, HttpRequest -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import DPGClientConfiguration from ._operations import DPGClientOperationsMixin diff --git a/packages/autorest.python/test/dpg/version-tolerant/Expected/AcceptanceTests/DPGCustomizationInitialVersionTolerant/dpgcustomizationinitialversiontolerant/aio/_operations/_operations.py b/packages/autorest.python/test/dpg/version-tolerant/Expected/AcceptanceTests/DPGCustomizationInitialVersionTolerant/dpgcustomizationinitialversiontolerant/aio/_operations/_operations.py index f158d4cb908..38ac80d5a65 100644 --- a/packages/autorest.python/test/dpg/version-tolerant/Expected/AcceptanceTests/DPGCustomizationInitialVersionTolerant/dpgcustomizationinitialversiontolerant/aio/_operations/_operations.py +++ b/packages/autorest.python/test/dpg/version-tolerant/Expected/AcceptanceTests/DPGCustomizationInitialVersionTolerant/dpgcustomizationinitialversiontolerant/aio/_operations/_operations.py @@ -10,6 +10,7 @@ from io import IOBase from typing import Any, AsyncIterable, AsyncIterator, Callable, Dict, IO, Optional, TypeVar, Union, cast, overload +from azure.core import AsyncPipelineClient from azure.core.async_paging import AsyncItemPaged, AsyncList from azure.core.exceptions import ( ClientAuthenticationError, @@ -35,14 +36,15 @@ build_dpg_lro_request, build_dpg_post_model_request, ) -from .._vendor import DPGClientMixinABC +from ..._utils.utils import ClientMixinABC +from .._configuration import DPGClientConfiguration JSON = MutableMapping[str, Any] T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, AsyncHttpResponse], T, Dict[str, Any]], Any]] -class DPGClientOperationsMixin(DPGClientMixinABC): +class DPGClientOperationsMixin(ClientMixinABC[AsyncPipelineClient, DPGClientConfiguration]): @distributed_trace_async async def get_model(self, mode: str, **kwargs: Any) -> JSON: diff --git a/packages/autorest.python/test/dpg/version-tolerant/Expected/AcceptanceTests/DPGCustomizationInitialVersionTolerant/dpgcustomizationinitialversiontolerant/aio/_vendor.py b/packages/autorest.python/test/dpg/version-tolerant/Expected/AcceptanceTests/DPGCustomizationInitialVersionTolerant/dpgcustomizationinitialversiontolerant/aio/_vendor.py deleted file mode 100644 index 189c699866d..00000000000 --- a/packages/autorest.python/test/dpg/version-tolerant/Expected/AcceptanceTests/DPGCustomizationInitialVersionTolerant/dpgcustomizationinitialversiontolerant/aio/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) AutoRest Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import DPGClientConfiguration - -if TYPE_CHECKING: - from azure.core import AsyncPipelineClient - - from .._serialization import Deserializer, Serializer - - -class DPGClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "AsyncPipelineClient" - _config: DPGClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/autorest.python/test/dpg/version-tolerant/Expected/AcceptanceTests/DPGServiceDrivenInitialVersionTolerant/dpgservicedriveninitialversiontolerant/_client.py b/packages/autorest.python/test/dpg/version-tolerant/Expected/AcceptanceTests/DPGServiceDrivenInitialVersionTolerant/dpgservicedriveninitialversiontolerant/_client.py index f0f9ff55c9b..da8d7f4488a 100644 --- a/packages/autorest.python/test/dpg/version-tolerant/Expected/AcceptanceTests/DPGServiceDrivenInitialVersionTolerant/dpgservicedriveninitialversiontolerant/_client.py +++ b/packages/autorest.python/test/dpg/version-tolerant/Expected/AcceptanceTests/DPGServiceDrivenInitialVersionTolerant/dpgservicedriveninitialversiontolerant/_client.py @@ -15,7 +15,7 @@ from azure.core.rest import HttpRequest, HttpResponse from ._configuration import DPGClientConfiguration -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer from .operations import ParamsOperations diff --git a/packages/autorest.python/test/dpg/version-tolerant/Expected/AcceptanceTests/DPGServiceDrivenInitialVersionTolerant/dpgservicedriveninitialversiontolerant/_utils/__init__.py b/packages/autorest.python/test/dpg/version-tolerant/Expected/AcceptanceTests/DPGServiceDrivenInitialVersionTolerant/dpgservicedriveninitialversiontolerant/_utils/__init__.py new file mode 100644 index 00000000000..0af9b28f660 --- /dev/null +++ b/packages/autorest.python/test/dpg/version-tolerant/Expected/AcceptanceTests/DPGServiceDrivenInitialVersionTolerant/dpgservicedriveninitialversiontolerant/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyDateTimeRfc1123/bodydatetimerfc1123/_serialization.py b/packages/autorest.python/test/dpg/version-tolerant/Expected/AcceptanceTests/DPGServiceDrivenInitialVersionTolerant/dpgservicedriveninitialversiontolerant/_utils/serialization.py similarity index 100% rename from packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyDateTimeRfc1123/bodydatetimerfc1123/_serialization.py rename to packages/autorest.python/test/dpg/version-tolerant/Expected/AcceptanceTests/DPGServiceDrivenInitialVersionTolerant/dpgservicedriveninitialversiontolerant/_utils/serialization.py diff --git a/packages/autorest.python/test/dpg/version-tolerant/Expected/AcceptanceTests/DPGServiceDrivenInitialVersionTolerant/dpgservicedriveninitialversiontolerant/aio/_client.py b/packages/autorest.python/test/dpg/version-tolerant/Expected/AcceptanceTests/DPGServiceDrivenInitialVersionTolerant/dpgservicedriveninitialversiontolerant/aio/_client.py index 7c3fbd7cd53..247c65d3fc9 100644 --- a/packages/autorest.python/test/dpg/version-tolerant/Expected/AcceptanceTests/DPGServiceDrivenInitialVersionTolerant/dpgservicedriveninitialversiontolerant/aio/_client.py +++ b/packages/autorest.python/test/dpg/version-tolerant/Expected/AcceptanceTests/DPGServiceDrivenInitialVersionTolerant/dpgservicedriveninitialversiontolerant/aio/_client.py @@ -14,7 +14,7 @@ from azure.core.pipeline import policies from azure.core.rest import AsyncHttpResponse, HttpRequest -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import DPGClientConfiguration from .operations import ParamsOperations diff --git a/packages/autorest.python/test/dpg/version-tolerant/Expected/AcceptanceTests/DPGServiceDrivenInitialVersionTolerant/dpgservicedriveninitialversiontolerant/aio/operations/_operations.py b/packages/autorest.python/test/dpg/version-tolerant/Expected/AcceptanceTests/DPGServiceDrivenInitialVersionTolerant/dpgservicedriveninitialversiontolerant/aio/operations/_operations.py index 698ffdbef7a..6b5f32986ce 100644 --- a/packages/autorest.python/test/dpg/version-tolerant/Expected/AcceptanceTests/DPGServiceDrivenInitialVersionTolerant/dpgservicedriveninitialversiontolerant/aio/operations/_operations.py +++ b/packages/autorest.python/test/dpg/version-tolerant/Expected/AcceptanceTests/DPGServiceDrivenInitialVersionTolerant/dpgservicedriveninitialversiontolerant/aio/operations/_operations.py @@ -23,7 +23,7 @@ from azure.core.tracing.decorator_async import distributed_trace_async from azure.core.utils import case_insensitive_dict -from ..._serialization import Deserializer, Serializer +from ..._utils.serialization import Deserializer, Serializer from ...operations._operations import ( build_params_get_optional_request, build_params_get_required_request, diff --git a/packages/autorest.python/test/dpg/version-tolerant/Expected/AcceptanceTests/DPGServiceDrivenInitialVersionTolerant/dpgservicedriveninitialversiontolerant/operations/_operations.py b/packages/autorest.python/test/dpg/version-tolerant/Expected/AcceptanceTests/DPGServiceDrivenInitialVersionTolerant/dpgservicedriveninitialversiontolerant/operations/_operations.py index 0b99e79f53d..9b4512c12d6 100644 --- a/packages/autorest.python/test/dpg/version-tolerant/Expected/AcceptanceTests/DPGServiceDrivenInitialVersionTolerant/dpgservicedriveninitialversiontolerant/operations/_operations.py +++ b/packages/autorest.python/test/dpg/version-tolerant/Expected/AcceptanceTests/DPGServiceDrivenInitialVersionTolerant/dpgservicedriveninitialversiontolerant/operations/_operations.py @@ -24,7 +24,7 @@ from azure.core.utils import case_insensitive_dict from .._configuration import DPGClientConfiguration -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer JSON = MutableMapping[str, Any] T = TypeVar("T") diff --git a/packages/autorest.python/test/dpg/version-tolerant/Expected/AcceptanceTests/DPGServiceDrivenUpdateOneVersionTolerant/dpgservicedrivenupdateoneversiontolerant/_client.py b/packages/autorest.python/test/dpg/version-tolerant/Expected/AcceptanceTests/DPGServiceDrivenUpdateOneVersionTolerant/dpgservicedrivenupdateoneversiontolerant/_client.py index fadbe9118bd..bfeb7fe51a6 100644 --- a/packages/autorest.python/test/dpg/version-tolerant/Expected/AcceptanceTests/DPGServiceDrivenUpdateOneVersionTolerant/dpgservicedrivenupdateoneversiontolerant/_client.py +++ b/packages/autorest.python/test/dpg/version-tolerant/Expected/AcceptanceTests/DPGServiceDrivenUpdateOneVersionTolerant/dpgservicedrivenupdateoneversiontolerant/_client.py @@ -15,7 +15,7 @@ from azure.core.rest import HttpRequest, HttpResponse from ._configuration import DPGClientConfiguration -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer from .operations import ParamsOperations diff --git a/packages/autorest.python/test/dpg/version-tolerant/Expected/AcceptanceTests/DPGServiceDrivenUpdateOneVersionTolerant/dpgservicedrivenupdateoneversiontolerant/_utils/__init__.py b/packages/autorest.python/test/dpg/version-tolerant/Expected/AcceptanceTests/DPGServiceDrivenUpdateOneVersionTolerant/dpgservicedrivenupdateoneversiontolerant/_utils/__init__.py new file mode 100644 index 00000000000..0af9b28f660 --- /dev/null +++ b/packages/autorest.python/test/dpg/version-tolerant/Expected/AcceptanceTests/DPGServiceDrivenUpdateOneVersionTolerant/dpgservicedrivenupdateoneversiontolerant/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyDictionary/bodydictionary/_serialization.py b/packages/autorest.python/test/dpg/version-tolerant/Expected/AcceptanceTests/DPGServiceDrivenUpdateOneVersionTolerant/dpgservicedrivenupdateoneversiontolerant/_utils/serialization.py similarity index 100% rename from packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyDictionary/bodydictionary/_serialization.py rename to packages/autorest.python/test/dpg/version-tolerant/Expected/AcceptanceTests/DPGServiceDrivenUpdateOneVersionTolerant/dpgservicedrivenupdateoneversiontolerant/_utils/serialization.py diff --git a/packages/autorest.python/test/dpg/version-tolerant/Expected/AcceptanceTests/DPGServiceDrivenUpdateOneVersionTolerant/dpgservicedrivenupdateoneversiontolerant/aio/_client.py b/packages/autorest.python/test/dpg/version-tolerant/Expected/AcceptanceTests/DPGServiceDrivenUpdateOneVersionTolerant/dpgservicedrivenupdateoneversiontolerant/aio/_client.py index c810aee54d0..647c2082290 100644 --- a/packages/autorest.python/test/dpg/version-tolerant/Expected/AcceptanceTests/DPGServiceDrivenUpdateOneVersionTolerant/dpgservicedrivenupdateoneversiontolerant/aio/_client.py +++ b/packages/autorest.python/test/dpg/version-tolerant/Expected/AcceptanceTests/DPGServiceDrivenUpdateOneVersionTolerant/dpgservicedrivenupdateoneversiontolerant/aio/_client.py @@ -14,7 +14,7 @@ from azure.core.pipeline import policies from azure.core.rest import AsyncHttpResponse, HttpRequest -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import DPGClientConfiguration from .operations import ParamsOperations diff --git a/packages/autorest.python/test/dpg/version-tolerant/Expected/AcceptanceTests/DPGServiceDrivenUpdateOneVersionTolerant/dpgservicedrivenupdateoneversiontolerant/aio/operations/_operations.py b/packages/autorest.python/test/dpg/version-tolerant/Expected/AcceptanceTests/DPGServiceDrivenUpdateOneVersionTolerant/dpgservicedrivenupdateoneversiontolerant/aio/operations/_operations.py index fbb7955c866..482dab3b2a3 100644 --- a/packages/autorest.python/test/dpg/version-tolerant/Expected/AcceptanceTests/DPGServiceDrivenUpdateOneVersionTolerant/dpgservicedrivenupdateoneversiontolerant/aio/operations/_operations.py +++ b/packages/autorest.python/test/dpg/version-tolerant/Expected/AcceptanceTests/DPGServiceDrivenUpdateOneVersionTolerant/dpgservicedrivenupdateoneversiontolerant/aio/operations/_operations.py @@ -23,7 +23,7 @@ from azure.core.tracing.decorator_async import distributed_trace_async from azure.core.utils import case_insensitive_dict -from ..._serialization import Deserializer, Serializer +from ..._utils.serialization import Deserializer, Serializer from ...operations._operations import ( build_params_delete_parameters_request, build_params_get_new_operation_request, diff --git a/packages/autorest.python/test/dpg/version-tolerant/Expected/AcceptanceTests/DPGServiceDrivenUpdateOneVersionTolerant/dpgservicedrivenupdateoneversiontolerant/operations/_operations.py b/packages/autorest.python/test/dpg/version-tolerant/Expected/AcceptanceTests/DPGServiceDrivenUpdateOneVersionTolerant/dpgservicedrivenupdateoneversiontolerant/operations/_operations.py index 1754fe8d790..940321517e8 100644 --- a/packages/autorest.python/test/dpg/version-tolerant/Expected/AcceptanceTests/DPGServiceDrivenUpdateOneVersionTolerant/dpgservicedrivenupdateoneversiontolerant/operations/_operations.py +++ b/packages/autorest.python/test/dpg/version-tolerant/Expected/AcceptanceTests/DPGServiceDrivenUpdateOneVersionTolerant/dpgservicedrivenupdateoneversiontolerant/operations/_operations.py @@ -24,7 +24,7 @@ from azure.core.utils import case_insensitive_dict from .._configuration import DPGClientConfiguration -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer JSON = MutableMapping[str, Any] T = TypeVar("T") diff --git a/packages/autorest.python/test/dpg/version-tolerant/Expected/AcceptanceTests/DPGTestModelsVersionTolerant/dpgtestmodelsversiontolerant/_client.py b/packages/autorest.python/test/dpg/version-tolerant/Expected/AcceptanceTests/DPGTestModelsVersionTolerant/dpgtestmodelsversiontolerant/_client.py index 5742e9e47ca..c0fe42cd547 100644 --- a/packages/autorest.python/test/dpg/version-tolerant/Expected/AcceptanceTests/DPGTestModelsVersionTolerant/dpgtestmodelsversiontolerant/_client.py +++ b/packages/autorest.python/test/dpg/version-tolerant/Expected/AcceptanceTests/DPGTestModelsVersionTolerant/dpgtestmodelsversiontolerant/_client.py @@ -17,7 +17,7 @@ from . import models as _models from ._configuration import DPGClientConfiguration from ._operations import DPGClientOperationsMixin -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer class DPGClient(DPGClientOperationsMixin): # pylint: disable=client-accepts-api-version-keyword diff --git a/packages/autorest.python/test/dpg/version-tolerant/Expected/AcceptanceTests/DPGTestModelsVersionTolerant/dpgtestmodelsversiontolerant/_operations/_operations.py b/packages/autorest.python/test/dpg/version-tolerant/Expected/AcceptanceTests/DPGTestModelsVersionTolerant/dpgtestmodelsversiontolerant/_operations/_operations.py index 3a9db2808b6..564b0942434 100644 --- a/packages/autorest.python/test/dpg/version-tolerant/Expected/AcceptanceTests/DPGTestModelsVersionTolerant/dpgtestmodelsversiontolerant/_operations/_operations.py +++ b/packages/autorest.python/test/dpg/version-tolerant/Expected/AcceptanceTests/DPGTestModelsVersionTolerant/dpgtestmodelsversiontolerant/_operations/_operations.py @@ -9,6 +9,7 @@ from io import IOBase from typing import Any, Callable, Dict, IO, Iterable, Iterator, Optional, TypeVar, Union, cast, overload +from azure.core import PipelineClient from azure.core.exceptions import ( ClientAuthenticationError, HttpResponseError, @@ -28,8 +29,9 @@ from azure.core.utils import case_insensitive_dict from .. import models as _models -from .._serialization import Serializer -from .._vendor import DPGClientMixinABC +from .._configuration import DPGClientConfiguration +from .._utils.serialization import Serializer +from .._utils.utils import ClientMixinABC T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] @@ -117,7 +119,7 @@ def build_dpg_lro_request(mode: str, **kwargs: Any) -> HttpRequest: return HttpRequest(method="PUT", url=_url, headers=_headers, **kwargs) -class DPGClientOperationsMixin(DPGClientMixinABC): +class DPGClientOperationsMixin(ClientMixinABC[PipelineClient, DPGClientConfiguration]): @distributed_trace def get_model(self, mode: str, **kwargs: Any) -> _models.Product: diff --git a/packages/autorest.python/test/dpg/version-tolerant/Expected/AcceptanceTests/DPGTestModelsVersionTolerant/dpgtestmodelsversiontolerant/_utils/__init__.py b/packages/autorest.python/test/dpg/version-tolerant/Expected/AcceptanceTests/DPGTestModelsVersionTolerant/dpgtestmodelsversiontolerant/_utils/__init__.py new file mode 100644 index 00000000000..0af9b28f660 --- /dev/null +++ b/packages/autorest.python/test/dpg/version-tolerant/Expected/AcceptanceTests/DPGTestModelsVersionTolerant/dpgtestmodelsversiontolerant/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyDuration/bodyduration/_serialization.py b/packages/autorest.python/test/dpg/version-tolerant/Expected/AcceptanceTests/DPGTestModelsVersionTolerant/dpgtestmodelsversiontolerant/_utils/serialization.py similarity index 100% rename from packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyDuration/bodyduration/_serialization.py rename to packages/autorest.python/test/dpg/version-tolerant/Expected/AcceptanceTests/DPGTestModelsVersionTolerant/dpgtestmodelsversiontolerant/_utils/serialization.py diff --git a/packages/autorest.python/test/dpg/version-tolerant/Expected/AcceptanceTests/DPGTestModelsVersionTolerant/dpgtestmodelsversiontolerant/_utils/utils.py b/packages/autorest.python/test/dpg/version-tolerant/Expected/AcceptanceTests/DPGTestModelsVersionTolerant/dpgtestmodelsversiontolerant/_utils/utils.py new file mode 100644 index 00000000000..39b612f39a9 --- /dev/null +++ b/packages/autorest.python/test/dpg/version-tolerant/Expected/AcceptanceTests/DPGTestModelsVersionTolerant/dpgtestmodelsversiontolerant/_utils/utils.py @@ -0,0 +1,25 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from abc import ABC +from typing import Generic, TYPE_CHECKING, TypeVar + +if TYPE_CHECKING: + from .serialization import Deserializer, Serializer + + +TClient = TypeVar("TClient") +TConfig = TypeVar("TConfig") + + +class ClientMixinABC(ABC, Generic[TClient, TConfig]): + """DO NOT use this class. It is for internal typing use only.""" + + _client: TClient + _config: TConfig + _serialize: "Serializer" + _deserialize: "Deserializer" diff --git a/packages/autorest.python/test/dpg/version-tolerant/Expected/AcceptanceTests/DPGTestModelsVersionTolerant/dpgtestmodelsversiontolerant/_vendor.py b/packages/autorest.python/test/dpg/version-tolerant/Expected/AcceptanceTests/DPGTestModelsVersionTolerant/dpgtestmodelsversiontolerant/_vendor.py deleted file mode 100644 index 804ea632d95..00000000000 --- a/packages/autorest.python/test/dpg/version-tolerant/Expected/AcceptanceTests/DPGTestModelsVersionTolerant/dpgtestmodelsversiontolerant/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) AutoRest Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import DPGClientConfiguration - -if TYPE_CHECKING: - from azure.core import PipelineClient - - from ._serialization import Deserializer, Serializer - - -class DPGClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "PipelineClient" - _config: DPGClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/autorest.python/test/dpg/version-tolerant/Expected/AcceptanceTests/DPGTestModelsVersionTolerant/dpgtestmodelsversiontolerant/aio/_client.py b/packages/autorest.python/test/dpg/version-tolerant/Expected/AcceptanceTests/DPGTestModelsVersionTolerant/dpgtestmodelsversiontolerant/aio/_client.py index 44eae55ef6f..c8ff1f304a9 100644 --- a/packages/autorest.python/test/dpg/version-tolerant/Expected/AcceptanceTests/DPGTestModelsVersionTolerant/dpgtestmodelsversiontolerant/aio/_client.py +++ b/packages/autorest.python/test/dpg/version-tolerant/Expected/AcceptanceTests/DPGTestModelsVersionTolerant/dpgtestmodelsversiontolerant/aio/_client.py @@ -15,7 +15,7 @@ from azure.core.rest import AsyncHttpResponse, HttpRequest from .. import models as _models -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import DPGClientConfiguration from ._operations import DPGClientOperationsMixin diff --git a/packages/autorest.python/test/dpg/version-tolerant/Expected/AcceptanceTests/DPGTestModelsVersionTolerant/dpgtestmodelsversiontolerant/aio/_operations/_operations.py b/packages/autorest.python/test/dpg/version-tolerant/Expected/AcceptanceTests/DPGTestModelsVersionTolerant/dpgtestmodelsversiontolerant/aio/_operations/_operations.py index 661fabd95d1..68e211c2b1d 100644 --- a/packages/autorest.python/test/dpg/version-tolerant/Expected/AcceptanceTests/DPGTestModelsVersionTolerant/dpgtestmodelsversiontolerant/aio/_operations/_operations.py +++ b/packages/autorest.python/test/dpg/version-tolerant/Expected/AcceptanceTests/DPGTestModelsVersionTolerant/dpgtestmodelsversiontolerant/aio/_operations/_operations.py @@ -10,6 +10,7 @@ from io import IOBase from typing import Any, AsyncIterable, AsyncIterator, Callable, Dict, IO, Optional, TypeVar, Union, cast, overload +from azure.core import AsyncPipelineClient from azure.core.async_paging import AsyncItemPaged, AsyncList from azure.core.exceptions import ( ClientAuthenticationError, @@ -36,13 +37,14 @@ build_dpg_lro_request, build_dpg_post_model_request, ) -from .._vendor import DPGClientMixinABC +from ..._utils.utils import ClientMixinABC +from .._configuration import DPGClientConfiguration T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, AsyncHttpResponse], T, Dict[str, Any]], Any]] -class DPGClientOperationsMixin(DPGClientMixinABC): +class DPGClientOperationsMixin(ClientMixinABC[AsyncPipelineClient, DPGClientConfiguration]): @distributed_trace_async async def get_model(self, mode: str, **kwargs: Any) -> _models.Product: diff --git a/packages/autorest.python/test/dpg/version-tolerant/Expected/AcceptanceTests/DPGTestModelsVersionTolerant/dpgtestmodelsversiontolerant/aio/_vendor.py b/packages/autorest.python/test/dpg/version-tolerant/Expected/AcceptanceTests/DPGTestModelsVersionTolerant/dpgtestmodelsversiontolerant/aio/_vendor.py deleted file mode 100644 index 189c699866d..00000000000 --- a/packages/autorest.python/test/dpg/version-tolerant/Expected/AcceptanceTests/DPGTestModelsVersionTolerant/dpgtestmodelsversiontolerant/aio/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) AutoRest Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import DPGClientConfiguration - -if TYPE_CHECKING: - from azure.core import AsyncPipelineClient - - from .._serialization import Deserializer, Serializer - - -class DPGClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "AsyncPipelineClient" - _config: DPGClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/autorest.python/test/dpg/version-tolerant/Expected/AcceptanceTests/DPGTestModelsVersionTolerant/dpgtestmodelsversiontolerant/models/_models.py b/packages/autorest.python/test/dpg/version-tolerant/Expected/AcceptanceTests/DPGTestModelsVersionTolerant/dpgtestmodelsversiontolerant/models/_models.py index 2779069dfd1..b17741edd0c 100644 --- a/packages/autorest.python/test/dpg/version-tolerant/Expected/AcceptanceTests/DPGTestModelsVersionTolerant/dpgtestmodelsversiontolerant/models/_models.py +++ b/packages/autorest.python/test/dpg/version-tolerant/Expected/AcceptanceTests/DPGTestModelsVersionTolerant/dpgtestmodelsversiontolerant/models/_models.py @@ -8,7 +8,7 @@ from typing import Any, List, Optional, TYPE_CHECKING, Union -from .. import _serialization +from .._utils import serialization as _serialization if TYPE_CHECKING: from .. import models as _models diff --git a/packages/autorest.python/test/dpg/version-tolerant/tox.ini b/packages/autorest.python/test/dpg/version-tolerant/tox.ini index cbf8bdc8890..7b4268a5426 100644 --- a/packages/autorest.python/test/dpg/version-tolerant/tox.ini +++ b/packages/autorest.python/test/dpg/version-tolerant/tox.ini @@ -8,7 +8,7 @@ deps= -r requirements.txt -r ../../../../../eng/dev_requirements.txt commands= - pytest --cov=Expected + pytest [testenv:lint] deps= @@ -28,7 +28,7 @@ commands = [testenv:ci] commands = - pytest --cov=Expected + pytest [testenv:apiview] commands = diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/Multiapi/multiapi/_multiapi_service_client.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/Multiapi/multiapi/_multiapi_service_client.py index 5240ed54ee0..580e2d639cc 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/Multiapi/multiapi/_multiapi_service_client.py +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/Multiapi/multiapi/_multiapi_service_client.py @@ -22,7 +22,7 @@ from ._configuration import MultiapiServiceClientConfiguration from ._operations_mixin import MultiapiServiceClientOperationsMixin -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer if TYPE_CHECKING: # pylint: disable=unused-import,ungrouped-imports diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/Multiapi/multiapi/_operations_mixin.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/Multiapi/multiapi/_operations_mixin.py index a63283bed25..06147c51c86 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/Multiapi/multiapi/_operations_mixin.py +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/Multiapi/multiapi/_operations_mixin.py @@ -8,7 +8,7 @@ # Changes may cause incorrect behavior and will be lost if the code is # regenerated. # -------------------------------------------------------------------------- -from ._serialization import Serializer, Deserializer +from ._utils.serialization import Serializer, Deserializer from io import IOBase from typing import Any, IO, Iterable, Iterator, Optional, Union diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/Multiapi/multiapi/_utils/__init__.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/Multiapi/multiapi/_utils/__init__.py new file mode 100644 index 00000000000..59333308532 --- /dev/null +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/Multiapi/multiapi/_utils/__init__.py @@ -0,0 +1,10 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is +# regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/Multiapi/multiapi/_utils/serialization.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/Multiapi/multiapi/_utils/serialization.py new file mode 100644 index 00000000000..05bcd7d403a --- /dev/null +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/Multiapi/multiapi/_utils/serialization.py @@ -0,0 +1,2025 @@ +# coding=utf-8 + +# pyright: reportUnnecessaryTypeIgnoreComment=false + +from base64 import b64decode, b64encode +import calendar +import datetime +import decimal +import email +from enum import Enum +import json +import logging +import re +import sys +import codecs +from typing import ( + Dict, + Any, + cast, + Optional, + Union, + AnyStr, + IO, + Mapping, + Callable, + MutableMapping, + List, +) + +try: + from urllib import quote # type: ignore +except ImportError: + from urllib.parse import quote +import xml.etree.ElementTree as ET + +import isodate # type: ignore +from typing_extensions import Self + +from azure.core.exceptions import DeserializationError, SerializationError +from azure.core.serialization import NULL as CoreNull + +_BOM = codecs.BOM_UTF8.decode(encoding="utf-8") + +JSON = MutableMapping[str, Any] + + +class RawDeserializer: + + # Accept "text" because we're open minded people... + JSON_REGEXP = re.compile(r"^(application|text)/([a-z+.]+\+)?json$") + + # Name used in context + CONTEXT_NAME = "deserialized_data" + + @classmethod + def deserialize_from_text(cls, data: Optional[Union[AnyStr, IO]], content_type: Optional[str] = None) -> Any: + """Decode data according to content-type. + + Accept a stream of data as well, but will be load at once in memory for now. + + If no content-type, will return the string version (not bytes, not stream) + + :param data: Input, could be bytes or stream (will be decoded with UTF8) or text + :type data: str or bytes or IO + :param str content_type: The content type. + :return: The deserialized data. + :rtype: object + """ + if hasattr(data, "read"): + # Assume a stream + data = cast(IO, data).read() + + if isinstance(data, bytes): + data_as_str = data.decode(encoding="utf-8-sig") + else: + # Explain to mypy the correct type. + data_as_str = cast(str, data) + + # Remove Byte Order Mark if present in string + data_as_str = data_as_str.lstrip(_BOM) + + if content_type is None: + return data + + if cls.JSON_REGEXP.match(content_type): + try: + return json.loads(data_as_str) + except ValueError as err: + raise DeserializationError("JSON is invalid: {}".format(err), err) from err + elif "xml" in (content_type or []): + try: + + try: + if isinstance(data, unicode): # type: ignore + # If I'm Python 2.7 and unicode XML will scream if I try a "fromstring" on unicode string + data_as_str = data_as_str.encode(encoding="utf-8") # type: ignore + except NameError: + pass + + return ET.fromstring(data_as_str) # nosec + except ET.ParseError as err: + # It might be because the server has an issue, and returned JSON with + # content-type XML.... + # So let's try a JSON load, and if it's still broken + # let's flow the initial exception + def _json_attemp(data): + try: + return True, json.loads(data) + except ValueError: + return False, None # Don't care about this one + + success, json_result = _json_attemp(data) + if success: + return json_result + # If i'm here, it's not JSON, it's not XML, let's scream + # and raise the last context in this block (the XML exception) + # The function hack is because Py2.7 messes up with exception + # context otherwise. + _LOGGER.critical("Wasn't XML not JSON, failing") + raise DeserializationError("XML is invalid") from err + elif content_type.startswith("text/"): + return data_as_str + raise DeserializationError("Cannot deserialize content-type: {}".format(content_type)) + + @classmethod + def deserialize_from_http_generics(cls, body_bytes: Optional[Union[AnyStr, IO]], headers: Mapping) -> Any: + """Deserialize from HTTP response. + + Use bytes and headers to NOT use any requests/aiohttp or whatever + specific implementation. + Headers will tested for "content-type" + + :param bytes body_bytes: The body of the response. + :param dict headers: The headers of the response. + :returns: The deserialized data. + :rtype: object + """ + # Try to use content-type from headers if available + content_type = None + if "content-type" in headers: + content_type = headers["content-type"].split(";")[0].strip().lower() + # Ouch, this server did not declare what it sent... + # Let's guess it's JSON... + # Also, since Autorest was considering that an empty body was a valid JSON, + # need that test as well.... + else: + content_type = "application/json" + + if body_bytes: + return cls.deserialize_from_text(body_bytes, content_type) + return None + + +_LOGGER = logging.getLogger(__name__) + +try: + _long_type = long # type: ignore +except NameError: + _long_type = int + +TZ_UTC = datetime.timezone.utc + +_FLATTEN = re.compile(r"(? None: + self.additional_properties: Optional[Dict[str, Any]] = {} + for k in kwargs: # pylint: disable=consider-using-dict-items + if k not in self._attribute_map: + _LOGGER.warning("%s is not a known attribute of class %s and will be ignored", k, self.__class__) + elif k in self._validation and self._validation[k].get("readonly", False): + _LOGGER.warning("Readonly attribute %s will be ignored in class %s", k, self.__class__) + else: + setattr(self, k, kwargs[k]) + + def __eq__(self, other: Any) -> bool: + """Compare objects by comparing all attributes. + + :param object other: The object to compare + :returns: True if objects are equal + :rtype: bool + """ + if isinstance(other, self.__class__): + return self.__dict__ == other.__dict__ + return False + + def __ne__(self, other: Any) -> bool: + """Compare objects by comparing all attributes. + + :param object other: The object to compare + :returns: True if objects are not equal + :rtype: bool + """ + return not self.__eq__(other) + + def __str__(self) -> str: + return str(self.__dict__) + + @classmethod + def enable_additional_properties_sending(cls) -> None: + cls._attribute_map["additional_properties"] = {"key": "", "type": "{object}"} + + @classmethod + def is_xml_model(cls) -> bool: + try: + cls._xml_map # type: ignore + except AttributeError: + return False + return True + + @classmethod + def _create_xml_node(cls): + """Create XML node. + + :returns: The XML node + :rtype: xml.etree.ElementTree.Element + """ + try: + xml_map = cls._xml_map # type: ignore + except AttributeError: + xml_map = {} + + return _create_xml_node(xml_map.get("name", cls.__name__), xml_map.get("prefix", None), xml_map.get("ns", None)) + + def serialize(self, keep_readonly: bool = False, **kwargs: Any) -> JSON: + """Return the JSON that would be sent to server from this model. + + This is an alias to `as_dict(full_restapi_key_transformer, keep_readonly=False)`. + + If you want XML serialization, you can pass the kwargs is_xml=True. + + :param bool keep_readonly: If you want to serialize the readonly attributes + :returns: A dict JSON compatible object + :rtype: dict + """ + serializer = Serializer(self._infer_class_models()) + return serializer._serialize( # type: ignore # pylint: disable=protected-access + self, keep_readonly=keep_readonly, **kwargs + ) + + def as_dict( + self, + keep_readonly: bool = True, + key_transformer: Callable[[str, Dict[str, Any], Any], Any] = attribute_transformer, + **kwargs: Any + ) -> JSON: + """Return a dict that can be serialized using json.dump. + + Advanced usage might optionally use a callback as parameter: + + .. code::python + + def my_key_transformer(key, attr_desc, value): + return key + + Key is the attribute name used in Python. Attr_desc + is a dict of metadata. Currently contains 'type' with the + msrest type and 'key' with the RestAPI encoded key. + Value is the current value in this object. + + The string returned will be used to serialize the key. + If the return type is a list, this is considered hierarchical + result dict. + + See the three examples in this file: + + - attribute_transformer + - full_restapi_key_transformer + - last_restapi_key_transformer + + If you want XML serialization, you can pass the kwargs is_xml=True. + + :param bool keep_readonly: If you want to serialize the readonly attributes + :param function key_transformer: A key transformer function. + :returns: A dict JSON compatible object + :rtype: dict + """ + serializer = Serializer(self._infer_class_models()) + return serializer._serialize( # type: ignore # pylint: disable=protected-access + self, key_transformer=key_transformer, keep_readonly=keep_readonly, **kwargs + ) + + @classmethod + def _infer_class_models(cls): + try: + str_models = cls.__module__.rsplit(".", 1)[0] + models = sys.modules[str_models] + client_models = {k: v for k, v in models.__dict__.items() if isinstance(v, type)} + if cls.__name__ not in client_models: + raise ValueError("Not Autorest generated code") + except Exception: # pylint: disable=broad-exception-caught + # Assume it's not Autorest generated (tests?). Add ourselves as dependencies. + client_models = {cls.__name__: cls} + return client_models + + @classmethod + def deserialize(cls, data: Any, content_type: Optional[str] = None) -> Self: + """Parse a str using the RestAPI syntax and return a model. + + :param str data: A str using RestAPI structure. JSON by default. + :param str content_type: JSON by default, set application/xml if XML. + :returns: An instance of this model + :raises DeserializationError: if something went wrong + :rtype: Self + """ + deserializer = Deserializer(cls._infer_class_models()) + return deserializer(cls.__name__, data, content_type=content_type) # type: ignore + + @classmethod + def from_dict( + cls, + data: Any, + key_extractors: Optional[Callable[[str, Dict[str, Any], Any], Any]] = None, + content_type: Optional[str] = None, + ) -> Self: + """Parse a dict using given key extractor return a model. + + By default consider key + extractors (rest_key_case_insensitive_extractor, attribute_key_case_insensitive_extractor + and last_rest_key_case_insensitive_extractor) + + :param dict data: A dict using RestAPI structure + :param function key_extractors: A key extractor function. + :param str content_type: JSON by default, set application/xml if XML. + :returns: An instance of this model + :raises DeserializationError: if something went wrong + :rtype: Self + """ + deserializer = Deserializer(cls._infer_class_models()) + deserializer.key_extractors = ( # type: ignore + [ # type: ignore + attribute_key_case_insensitive_extractor, + rest_key_case_insensitive_extractor, + last_rest_key_case_insensitive_extractor, + ] + if key_extractors is None + else key_extractors + ) + return deserializer(cls.__name__, data, content_type=content_type) # type: ignore + + @classmethod + def _flatten_subtype(cls, key, objects): + if "_subtype_map" not in cls.__dict__: + return {} + result = dict(cls._subtype_map[key]) + for valuetype in cls._subtype_map[key].values(): + result.update(objects[valuetype]._flatten_subtype(key, objects)) # pylint: disable=protected-access + return result + + @classmethod + def _classify(cls, response, objects): + """Check the class _subtype_map for any child classes. + We want to ignore any inherited _subtype_maps. + + :param dict response: The initial data + :param dict objects: The class objects + :returns: The class to be used + :rtype: class + """ + for subtype_key in cls.__dict__.get("_subtype_map", {}).keys(): + subtype_value = None + + if not isinstance(response, ET.Element): + rest_api_response_key = cls._get_rest_key_parts(subtype_key)[-1] + subtype_value = response.get(rest_api_response_key, None) or response.get(subtype_key, None) + else: + subtype_value = xml_key_extractor(subtype_key, cls._attribute_map[subtype_key], response) + if subtype_value: + # Try to match base class. Can be class name only + # (bug to fix in Autorest to support x-ms-discriminator-name) + if cls.__name__ == subtype_value: + return cls + flatten_mapping_type = cls._flatten_subtype(subtype_key, objects) + try: + return objects[flatten_mapping_type[subtype_value]] # type: ignore + except KeyError: + _LOGGER.warning( + "Subtype value %s has no mapping, use base class %s.", + subtype_value, + cls.__name__, + ) + break + else: + _LOGGER.warning("Discriminator %s is absent or null, use base class %s.", subtype_key, cls.__name__) + break + return cls + + @classmethod + def _get_rest_key_parts(cls, attr_key): + """Get the RestAPI key of this attr, split it and decode part + :param str attr_key: Attribute key must be in attribute_map. + :returns: A list of RestAPI part + :rtype: list + """ + rest_split_key = _FLATTEN.split(cls._attribute_map[attr_key]["key"]) + return [_decode_attribute_map_key(key_part) for key_part in rest_split_key] + + +def _decode_attribute_map_key(key): + """This decode a key in an _attribute_map to the actual key we want to look at + inside the received data. + + :param str key: A key string from the generated code + :returns: The decoded key + :rtype: str + """ + return key.replace("\\.", ".") + + +class Serializer: # pylint: disable=too-many-public-methods + """Request object model serializer.""" + + basic_types = {str: "str", int: "int", bool: "bool", float: "float"} + + _xml_basic_types_serializers = {"bool": lambda x: str(x).lower()} + days = {0: "Mon", 1: "Tue", 2: "Wed", 3: "Thu", 4: "Fri", 5: "Sat", 6: "Sun"} + months = { + 1: "Jan", + 2: "Feb", + 3: "Mar", + 4: "Apr", + 5: "May", + 6: "Jun", + 7: "Jul", + 8: "Aug", + 9: "Sep", + 10: "Oct", + 11: "Nov", + 12: "Dec", + } + validation = { + "min_length": lambda x, y: len(x) < y, + "max_length": lambda x, y: len(x) > y, + "minimum": lambda x, y: x < y, + "maximum": lambda x, y: x > y, + "minimum_ex": lambda x, y: x <= y, + "maximum_ex": lambda x, y: x >= y, + "min_items": lambda x, y: len(x) < y, + "max_items": lambda x, y: len(x) > y, + "pattern": lambda x, y: not re.match(y, x, re.UNICODE), + "unique": lambda x, y: len(x) != len(set(x)), + "multiple": lambda x, y: x % y != 0, + } + + def __init__(self, classes: Optional[Mapping[str, type]] = None) -> None: + self.serialize_type = { + "iso-8601": Serializer.serialize_iso, + "rfc-1123": Serializer.serialize_rfc, + "unix-time": Serializer.serialize_unix, + "duration": Serializer.serialize_duration, + "date": Serializer.serialize_date, + "time": Serializer.serialize_time, + "decimal": Serializer.serialize_decimal, + "long": Serializer.serialize_long, + "bytearray": Serializer.serialize_bytearray, + "base64": Serializer.serialize_base64, + "object": self.serialize_object, + "[]": self.serialize_iter, + "{}": self.serialize_dict, + } + self.dependencies: Dict[str, type] = dict(classes) if classes else {} + self.key_transformer = full_restapi_key_transformer + self.client_side_validation = True + + def _serialize( # pylint: disable=too-many-nested-blocks, too-many-branches, too-many-statements, too-many-locals + self, target_obj, data_type=None, **kwargs + ): + """Serialize data into a string according to type. + + :param object target_obj: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str, dict + :raises SerializationError: if serialization fails. + :returns: The serialized data. + """ + key_transformer = kwargs.get("key_transformer", self.key_transformer) + keep_readonly = kwargs.get("keep_readonly", False) + if target_obj is None: + return None + + attr_name = None + class_name = target_obj.__class__.__name__ + + if data_type: + return self.serialize_data(target_obj, data_type, **kwargs) + + if not hasattr(target_obj, "_attribute_map"): + data_type = type(target_obj).__name__ + if data_type in self.basic_types.values(): + return self.serialize_data(target_obj, data_type, **kwargs) + + # Force "is_xml" kwargs if we detect a XML model + try: + is_xml_model_serialization = kwargs["is_xml"] + except KeyError: + is_xml_model_serialization = kwargs.setdefault("is_xml", target_obj.is_xml_model()) + + serialized = {} + if is_xml_model_serialization: + serialized = target_obj._create_xml_node() # pylint: disable=protected-access + try: + attributes = target_obj._attribute_map # pylint: disable=protected-access + for attr, attr_desc in attributes.items(): + attr_name = attr + if not keep_readonly and target_obj._validation.get( # pylint: disable=protected-access + attr_name, {} + ).get("readonly", False): + continue + + if attr_name == "additional_properties" and attr_desc["key"] == "": + if target_obj.additional_properties is not None: + serialized.update(target_obj.additional_properties) + continue + try: + + orig_attr = getattr(target_obj, attr) + if is_xml_model_serialization: + pass # Don't provide "transformer" for XML for now. Keep "orig_attr" + else: # JSON + keys, orig_attr = key_transformer(attr, attr_desc.copy(), orig_attr) + keys = keys if isinstance(keys, list) else [keys] + + kwargs["serialization_ctxt"] = attr_desc + new_attr = self.serialize_data(orig_attr, attr_desc["type"], **kwargs) + + if is_xml_model_serialization: + xml_desc = attr_desc.get("xml", {}) + xml_name = xml_desc.get("name", attr_desc["key"]) + xml_prefix = xml_desc.get("prefix", None) + xml_ns = xml_desc.get("ns", None) + if xml_desc.get("attr", False): + if xml_ns: + ET.register_namespace(xml_prefix, xml_ns) + xml_name = "{{{}}}{}".format(xml_ns, xml_name) + serialized.set(xml_name, new_attr) # type: ignore + continue + if xml_desc.get("text", False): + serialized.text = new_attr # type: ignore + continue + if isinstance(new_attr, list): + serialized.extend(new_attr) # type: ignore + elif isinstance(new_attr, ET.Element): + # If the down XML has no XML/Name, + # we MUST replace the tag with the local tag. But keeping the namespaces. + if "name" not in getattr(orig_attr, "_xml_map", {}): + splitted_tag = new_attr.tag.split("}") + if len(splitted_tag) == 2: # Namespace + new_attr.tag = "}".join([splitted_tag[0], xml_name]) + else: + new_attr.tag = xml_name + serialized.append(new_attr) # type: ignore + else: # That's a basic type + # Integrate namespace if necessary + local_node = _create_xml_node(xml_name, xml_prefix, xml_ns) + local_node.text = str(new_attr) + serialized.append(local_node) # type: ignore + else: # JSON + for k in reversed(keys): # type: ignore + new_attr = {k: new_attr} + + _new_attr = new_attr + _serialized = serialized + for k in keys: # type: ignore + if k not in _serialized: + _serialized.update(_new_attr) # type: ignore + _new_attr = _new_attr[k] # type: ignore + _serialized = _serialized[k] + except ValueError as err: + if isinstance(err, SerializationError): + raise + + except (AttributeError, KeyError, TypeError) as err: + msg = "Attribute {} in object {} cannot be serialized.\n{}".format(attr_name, class_name, str(target_obj)) + raise SerializationError(msg) from err + return serialized + + def body(self, data, data_type, **kwargs): + """Serialize data intended for a request body. + + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: dict + :raises SerializationError: if serialization fails. + :raises ValueError: if data is None + :returns: The serialized request body + """ + + # Just in case this is a dict + internal_data_type_str = data_type.strip("[]{}") + internal_data_type = self.dependencies.get(internal_data_type_str, None) + try: + is_xml_model_serialization = kwargs["is_xml"] + except KeyError: + if internal_data_type and issubclass(internal_data_type, Model): + is_xml_model_serialization = kwargs.setdefault("is_xml", internal_data_type.is_xml_model()) + else: + is_xml_model_serialization = False + if internal_data_type and not isinstance(internal_data_type, Enum): + try: + deserializer = Deserializer(self.dependencies) + # Since it's on serialization, it's almost sure that format is not JSON REST + # We're not able to deal with additional properties for now. + deserializer.additional_properties_detection = False + if is_xml_model_serialization: + deserializer.key_extractors = [ # type: ignore + attribute_key_case_insensitive_extractor, + ] + else: + deserializer.key_extractors = [ + rest_key_case_insensitive_extractor, + attribute_key_case_insensitive_extractor, + last_rest_key_case_insensitive_extractor, + ] + data = deserializer._deserialize(data_type, data) # pylint: disable=protected-access + except DeserializationError as err: + raise SerializationError("Unable to build a model: " + str(err)) from err + + return self._serialize(data, data_type, **kwargs) + + def url(self, name, data, data_type, **kwargs): + """Serialize data intended for a URL path. + + :param str name: The name of the URL path parameter. + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str + :returns: The serialized URL path + :raises TypeError: if serialization fails. + :raises ValueError: if data is None + """ + try: + output = self.serialize_data(data, data_type, **kwargs) + if data_type == "bool": + output = json.dumps(output) + + if kwargs.get("skip_quote") is True: + output = str(output) + output = output.replace("{", quote("{")).replace("}", quote("}")) + else: + output = quote(str(output), safe="") + except SerializationError as exc: + raise TypeError("{} must be type {}.".format(name, data_type)) from exc + return output + + def query(self, name, data, data_type, **kwargs): + """Serialize data intended for a URL query. + + :param str name: The name of the query parameter. + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str, list + :raises TypeError: if serialization fails. + :raises ValueError: if data is None + :returns: The serialized query parameter + """ + try: + # Treat the list aside, since we don't want to encode the div separator + if data_type.startswith("["): + internal_data_type = data_type[1:-1] + do_quote = not kwargs.get("skip_quote", False) + return self.serialize_iter(data, internal_data_type, do_quote=do_quote, **kwargs) + + # Not a list, regular serialization + output = self.serialize_data(data, data_type, **kwargs) + if data_type == "bool": + output = json.dumps(output) + if kwargs.get("skip_quote") is True: + output = str(output) + else: + output = quote(str(output), safe="") + except SerializationError as exc: + raise TypeError("{} must be type {}.".format(name, data_type)) from exc + return str(output) + + def header(self, name, data, data_type, **kwargs): + """Serialize data intended for a request header. + + :param str name: The name of the header. + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str + :raises TypeError: if serialization fails. + :raises ValueError: if data is None + :returns: The serialized header + """ + try: + if data_type in ["[str]"]: + data = ["" if d is None else d for d in data] + + output = self.serialize_data(data, data_type, **kwargs) + if data_type == "bool": + output = json.dumps(output) + except SerializationError as exc: + raise TypeError("{} must be type {}.".format(name, data_type)) from exc + return str(output) + + def serialize_data(self, data, data_type, **kwargs): + """Serialize generic data according to supplied data type. + + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :raises AttributeError: if required data is None. + :raises ValueError: if data is None + :raises SerializationError: if serialization fails. + :returns: The serialized data. + :rtype: str, int, float, bool, dict, list + """ + if data is None: + raise ValueError("No value for given attribute") + + try: + if data is CoreNull: + return None + if data_type in self.basic_types.values(): + return self.serialize_basic(data, data_type, **kwargs) + + if data_type in self.serialize_type: + return self.serialize_type[data_type](data, **kwargs) + + # If dependencies is empty, try with current data class + # It has to be a subclass of Enum anyway + enum_type = self.dependencies.get(data_type, data.__class__) + if issubclass(enum_type, Enum): + return Serializer.serialize_enum(data, enum_obj=enum_type) + + iter_type = data_type[0] + data_type[-1] + if iter_type in self.serialize_type: + return self.serialize_type[iter_type](data, data_type[1:-1], **kwargs) + + except (ValueError, TypeError) as err: + msg = "Unable to serialize value: {!r} as type: {!r}." + raise SerializationError(msg.format(data, data_type)) from err + return self._serialize(data, **kwargs) + + @classmethod + def _get_custom_serializers(cls, data_type, **kwargs): # pylint: disable=inconsistent-return-statements + custom_serializer = kwargs.get("basic_types_serializers", {}).get(data_type) + if custom_serializer: + return custom_serializer + if kwargs.get("is_xml", False): + return cls._xml_basic_types_serializers.get(data_type) + + @classmethod + def serialize_basic(cls, data, data_type, **kwargs): + """Serialize basic builting data type. + Serializes objects to str, int, float or bool. + + Possible kwargs: + - basic_types_serializers dict[str, callable] : If set, use the callable as serializer + - is_xml bool : If set, use xml_basic_types_serializers + + :param obj data: Object to be serialized. + :param str data_type: Type of object in the iterable. + :rtype: str, int, float, bool + :return: serialized object + """ + custom_serializer = cls._get_custom_serializers(data_type, **kwargs) + if custom_serializer: + return custom_serializer(data) + if data_type == "str": + return cls.serialize_unicode(data) + return eval(data_type)(data) # nosec # pylint: disable=eval-used + + @classmethod + def serialize_unicode(cls, data): + """Special handling for serializing unicode strings in Py2. + Encode to UTF-8 if unicode, otherwise handle as a str. + + :param str data: Object to be serialized. + :rtype: str + :return: serialized object + """ + try: # If I received an enum, return its value + return data.value + except AttributeError: + pass + + try: + if isinstance(data, unicode): # type: ignore + # Don't change it, JSON and XML ElementTree are totally able + # to serialize correctly u'' strings + return data + except NameError: + return str(data) + return str(data) + + def serialize_iter(self, data, iter_type, div=None, **kwargs): + """Serialize iterable. + + Supported kwargs: + - serialization_ctxt dict : The current entry of _attribute_map, or same format. + serialization_ctxt['type'] should be same as data_type. + - is_xml bool : If set, serialize as XML + + :param list data: Object to be serialized. + :param str iter_type: Type of object in the iterable. + :param str div: If set, this str will be used to combine the elements + in the iterable into a combined string. Default is 'None'. + Defaults to False. + :rtype: list, str + :return: serialized iterable + """ + if isinstance(data, str): + raise SerializationError("Refuse str type as a valid iter type.") + + serialization_ctxt = kwargs.get("serialization_ctxt", {}) + is_xml = kwargs.get("is_xml", False) + + serialized = [] + for d in data: + try: + serialized.append(self.serialize_data(d, iter_type, **kwargs)) + except ValueError as err: + if isinstance(err, SerializationError): + raise + serialized.append(None) + + if kwargs.get("do_quote", False): + serialized = ["" if s is None else quote(str(s), safe="") for s in serialized] + + if div: + serialized = ["" if s is None else str(s) for s in serialized] + serialized = div.join(serialized) + + if "xml" in serialization_ctxt or is_xml: + # XML serialization is more complicated + xml_desc = serialization_ctxt.get("xml", {}) + xml_name = xml_desc.get("name") + if not xml_name: + xml_name = serialization_ctxt["key"] + + # Create a wrap node if necessary (use the fact that Element and list have "append") + is_wrapped = xml_desc.get("wrapped", False) + node_name = xml_desc.get("itemsName", xml_name) + if is_wrapped: + final_result = _create_xml_node(xml_name, xml_desc.get("prefix", None), xml_desc.get("ns", None)) + else: + final_result = [] + # All list elements to "local_node" + for el in serialized: + if isinstance(el, ET.Element): + el_node = el + else: + el_node = _create_xml_node(node_name, xml_desc.get("prefix", None), xml_desc.get("ns", None)) + if el is not None: # Otherwise it writes "None" :-p + el_node.text = str(el) + final_result.append(el_node) + return final_result + return serialized + + def serialize_dict(self, attr, dict_type, **kwargs): + """Serialize a dictionary of objects. + + :param dict attr: Object to be serialized. + :param str dict_type: Type of object in the dictionary. + :rtype: dict + :return: serialized dictionary + """ + serialization_ctxt = kwargs.get("serialization_ctxt", {}) + serialized = {} + for key, value in attr.items(): + try: + serialized[self.serialize_unicode(key)] = self.serialize_data(value, dict_type, **kwargs) + except ValueError as err: + if isinstance(err, SerializationError): + raise + serialized[self.serialize_unicode(key)] = None + + if "xml" in serialization_ctxt: + # XML serialization is more complicated + xml_desc = serialization_ctxt["xml"] + xml_name = xml_desc["name"] + + final_result = _create_xml_node(xml_name, xml_desc.get("prefix", None), xml_desc.get("ns", None)) + for key, value in serialized.items(): + ET.SubElement(final_result, key).text = value + return final_result + + return serialized + + def serialize_object(self, attr, **kwargs): # pylint: disable=too-many-return-statements + """Serialize a generic object. + This will be handled as a dictionary. If object passed in is not + a basic type (str, int, float, dict, list) it will simply be + cast to str. + + :param dict attr: Object to be serialized. + :rtype: dict or str + :return: serialized object + """ + if attr is None: + return None + if isinstance(attr, ET.Element): + return attr + obj_type = type(attr) + if obj_type in self.basic_types: + return self.serialize_basic(attr, self.basic_types[obj_type], **kwargs) + if obj_type is _long_type: + return self.serialize_long(attr) + if obj_type is str: + return self.serialize_unicode(attr) + if obj_type is datetime.datetime: + return self.serialize_iso(attr) + if obj_type is datetime.date: + return self.serialize_date(attr) + if obj_type is datetime.time: + return self.serialize_time(attr) + if obj_type is datetime.timedelta: + return self.serialize_duration(attr) + if obj_type is decimal.Decimal: + return self.serialize_decimal(attr) + + # If it's a model or I know this dependency, serialize as a Model + if obj_type in self.dependencies.values() or isinstance(attr, Model): + return self._serialize(attr) + + if obj_type == dict: + serialized = {} + for key, value in attr.items(): + try: + serialized[self.serialize_unicode(key)] = self.serialize_object(value, **kwargs) + except ValueError: + serialized[self.serialize_unicode(key)] = None + return serialized + + if obj_type == list: + serialized = [] + for obj in attr: + try: + serialized.append(self.serialize_object(obj, **kwargs)) + except ValueError: + pass + return serialized + return str(attr) + + @staticmethod + def serialize_enum(attr, enum_obj=None): + try: + result = attr.value + except AttributeError: + result = attr + try: + enum_obj(result) # type: ignore + return result + except ValueError as exc: + for enum_value in enum_obj: # type: ignore + if enum_value.value.lower() == str(attr).lower(): + return enum_value.value + error = "{!r} is not valid value for enum {!r}" + raise SerializationError(error.format(attr, enum_obj)) from exc + + @staticmethod + def serialize_bytearray(attr, **kwargs): # pylint: disable=unused-argument + """Serialize bytearray into base-64 string. + + :param str attr: Object to be serialized. + :rtype: str + :return: serialized base64 + """ + return b64encode(attr).decode() + + @staticmethod + def serialize_base64(attr, **kwargs): # pylint: disable=unused-argument + """Serialize str into base-64 string. + + :param str attr: Object to be serialized. + :rtype: str + :return: serialized base64 + """ + encoded = b64encode(attr).decode("ascii") + return encoded.strip("=").replace("+", "-").replace("/", "_") + + @staticmethod + def serialize_decimal(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Decimal object to float. + + :param decimal attr: Object to be serialized. + :rtype: float + :return: serialized decimal + """ + return float(attr) + + @staticmethod + def serialize_long(attr, **kwargs): # pylint: disable=unused-argument + """Serialize long (Py2) or int (Py3). + + :param int attr: Object to be serialized. + :rtype: int/long + :return: serialized long + """ + return _long_type(attr) + + @staticmethod + def serialize_date(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Date object into ISO-8601 formatted string. + + :param Date attr: Object to be serialized. + :rtype: str + :return: serialized date + """ + if isinstance(attr, str): + attr = isodate.parse_date(attr) + t = "{:04}-{:02}-{:02}".format(attr.year, attr.month, attr.day) + return t + + @staticmethod + def serialize_time(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Time object into ISO-8601 formatted string. + + :param datetime.time attr: Object to be serialized. + :rtype: str + :return: serialized time + """ + if isinstance(attr, str): + attr = isodate.parse_time(attr) + t = "{:02}:{:02}:{:02}".format(attr.hour, attr.minute, attr.second) + if attr.microsecond: + t += ".{:02}".format(attr.microsecond) + return t + + @staticmethod + def serialize_duration(attr, **kwargs): # pylint: disable=unused-argument + """Serialize TimeDelta object into ISO-8601 formatted string. + + :param TimeDelta attr: Object to be serialized. + :rtype: str + :return: serialized duration + """ + if isinstance(attr, str): + attr = isodate.parse_duration(attr) + return isodate.duration_isoformat(attr) + + @staticmethod + def serialize_rfc(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Datetime object into RFC-1123 formatted string. + + :param Datetime attr: Object to be serialized. + :rtype: str + :raises TypeError: if format invalid. + :return: serialized rfc + """ + try: + if not attr.tzinfo: + _LOGGER.warning("Datetime with no tzinfo will be considered UTC.") + utc = attr.utctimetuple() + except AttributeError as exc: + raise TypeError("RFC1123 object must be valid Datetime object.") from exc + + return "{}, {:02} {} {:04} {:02}:{:02}:{:02} GMT".format( + Serializer.days[utc.tm_wday], + utc.tm_mday, + Serializer.months[utc.tm_mon], + utc.tm_year, + utc.tm_hour, + utc.tm_min, + utc.tm_sec, + ) + + @staticmethod + def serialize_iso(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Datetime object into ISO-8601 formatted string. + + :param Datetime attr: Object to be serialized. + :rtype: str + :raises SerializationError: if format invalid. + :return: serialized iso + """ + if isinstance(attr, str): + attr = isodate.parse_datetime(attr) + try: + if not attr.tzinfo: + _LOGGER.warning("Datetime with no tzinfo will be considered UTC.") + utc = attr.utctimetuple() + if utc.tm_year > 9999 or utc.tm_year < 1: + raise OverflowError("Hit max or min date") + + microseconds = str(attr.microsecond).rjust(6, "0").rstrip("0").ljust(3, "0") + if microseconds: + microseconds = "." + microseconds + date = "{:04}-{:02}-{:02}T{:02}:{:02}:{:02}".format( + utc.tm_year, utc.tm_mon, utc.tm_mday, utc.tm_hour, utc.tm_min, utc.tm_sec + ) + return date + microseconds + "Z" + except (ValueError, OverflowError) as err: + msg = "Unable to serialize datetime object." + raise SerializationError(msg) from err + except AttributeError as err: + msg = "ISO-8601 object must be valid Datetime object." + raise TypeError(msg) from err + + @staticmethod + def serialize_unix(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Datetime object into IntTime format. + This is represented as seconds. + + :param Datetime attr: Object to be serialized. + :rtype: int + :raises SerializationError: if format invalid + :return: serialied unix + """ + if isinstance(attr, int): + return attr + try: + if not attr.tzinfo: + _LOGGER.warning("Datetime with no tzinfo will be considered UTC.") + return int(calendar.timegm(attr.utctimetuple())) + except AttributeError as exc: + raise TypeError("Unix time object must be valid Datetime object.") from exc + + +def rest_key_extractor(attr, attr_desc, data): # pylint: disable=unused-argument + key = attr_desc["key"] + working_data = data + + while "." in key: + # Need the cast, as for some reasons "split" is typed as list[str | Any] + dict_keys = cast(List[str], _FLATTEN.split(key)) + if len(dict_keys) == 1: + key = _decode_attribute_map_key(dict_keys[0]) + break + working_key = _decode_attribute_map_key(dict_keys[0]) + working_data = working_data.get(working_key, data) + if working_data is None: + # If at any point while following flatten JSON path see None, it means + # that all properties under are None as well + return None + key = ".".join(dict_keys[1:]) + + return working_data.get(key) + + +def rest_key_case_insensitive_extractor( # pylint: disable=unused-argument, inconsistent-return-statements + attr, attr_desc, data +): + key = attr_desc["key"] + working_data = data + + while "." in key: + dict_keys = _FLATTEN.split(key) + if len(dict_keys) == 1: + key = _decode_attribute_map_key(dict_keys[0]) + break + working_key = _decode_attribute_map_key(dict_keys[0]) + working_data = attribute_key_case_insensitive_extractor(working_key, None, working_data) + if working_data is None: + # If at any point while following flatten JSON path see None, it means + # that all properties under are None as well + return None + key = ".".join(dict_keys[1:]) + + if working_data: + return attribute_key_case_insensitive_extractor(key, None, working_data) + + +def last_rest_key_extractor(attr, attr_desc, data): # pylint: disable=unused-argument + """Extract the attribute in "data" based on the last part of the JSON path key. + + :param str attr: The attribute to extract + :param dict attr_desc: The attribute description + :param dict data: The data to extract from + :rtype: object + :returns: The extracted attribute + """ + key = attr_desc["key"] + dict_keys = _FLATTEN.split(key) + return attribute_key_extractor(dict_keys[-1], None, data) + + +def last_rest_key_case_insensitive_extractor(attr, attr_desc, data): # pylint: disable=unused-argument + """Extract the attribute in "data" based on the last part of the JSON path key. + + This is the case insensitive version of "last_rest_key_extractor" + :param str attr: The attribute to extract + :param dict attr_desc: The attribute description + :param dict data: The data to extract from + :rtype: object + :returns: The extracted attribute + """ + key = attr_desc["key"] + dict_keys = _FLATTEN.split(key) + return attribute_key_case_insensitive_extractor(dict_keys[-1], None, data) + + +def attribute_key_extractor(attr, _, data): + return data.get(attr) + + +def attribute_key_case_insensitive_extractor(attr, _, data): + found_key = None + lower_attr = attr.lower() + for key in data: + if lower_attr == key.lower(): + found_key = key + break + + return data.get(found_key) + + +def _extract_name_from_internal_type(internal_type): + """Given an internal type XML description, extract correct XML name with namespace. + + :param dict internal_type: An model type + :rtype: tuple + :returns: A tuple XML name + namespace dict + """ + internal_type_xml_map = getattr(internal_type, "_xml_map", {}) + xml_name = internal_type_xml_map.get("name", internal_type.__name__) + xml_ns = internal_type_xml_map.get("ns", None) + if xml_ns: + xml_name = "{{{}}}{}".format(xml_ns, xml_name) + return xml_name + + +def xml_key_extractor(attr, attr_desc, data): # pylint: disable=unused-argument,too-many-return-statements + if isinstance(data, dict): + return None + + # Test if this model is XML ready first + if not isinstance(data, ET.Element): + return None + + xml_desc = attr_desc.get("xml", {}) + xml_name = xml_desc.get("name", attr_desc["key"]) + + # Look for a children + is_iter_type = attr_desc["type"].startswith("[") + is_wrapped = xml_desc.get("wrapped", False) + internal_type = attr_desc.get("internalType", None) + internal_type_xml_map = getattr(internal_type, "_xml_map", {}) + + # Integrate namespace if necessary + xml_ns = xml_desc.get("ns", internal_type_xml_map.get("ns", None)) + if xml_ns: + xml_name = "{{{}}}{}".format(xml_ns, xml_name) + + # If it's an attribute, that's simple + if xml_desc.get("attr", False): + return data.get(xml_name) + + # If it's x-ms-text, that's simple too + if xml_desc.get("text", False): + return data.text + + # Scenario where I take the local name: + # - Wrapped node + # - Internal type is an enum (considered basic types) + # - Internal type has no XML/Name node + if is_wrapped or (internal_type and (issubclass(internal_type, Enum) or "name" not in internal_type_xml_map)): + children = data.findall(xml_name) + # If internal type has a local name and it's not a list, I use that name + elif not is_iter_type and internal_type and "name" in internal_type_xml_map: + xml_name = _extract_name_from_internal_type(internal_type) + children = data.findall(xml_name) + # That's an array + else: + if internal_type: # Complex type, ignore itemsName and use the complex type name + items_name = _extract_name_from_internal_type(internal_type) + else: + items_name = xml_desc.get("itemsName", xml_name) + children = data.findall(items_name) + + if len(children) == 0: + if is_iter_type: + if is_wrapped: + return None # is_wrapped no node, we want None + return [] # not wrapped, assume empty list + return None # Assume it's not there, maybe an optional node. + + # If is_iter_type and not wrapped, return all found children + if is_iter_type: + if not is_wrapped: + return children + # Iter and wrapped, should have found one node only (the wrap one) + if len(children) != 1: + raise DeserializationError( + "Tried to deserialize an array not wrapped, and found several nodes '{}'. Maybe you should declare this array as wrapped?".format( + xml_name + ) + ) + return list(children[0]) # Might be empty list and that's ok. + + # Here it's not a itertype, we should have found one element only or empty + if len(children) > 1: + raise DeserializationError("Find several XML '{}' where it was not expected".format(xml_name)) + return children[0] + + +class Deserializer: + """Response object model deserializer. + + :param dict classes: Class type dictionary for deserializing complex types. + :ivar list key_extractors: Ordered list of extractors to be used by this deserializer. + """ + + basic_types = {str: "str", int: "int", bool: "bool", float: "float"} + + valid_date = re.compile(r"\d{4}[-]\d{2}[-]\d{2}T\d{2}:\d{2}:\d{2}\.?\d*Z?[-+]?[\d{2}]?:?[\d{2}]?") + + def __init__(self, classes: Optional[Mapping[str, type]] = None) -> None: + self.deserialize_type = { + "iso-8601": Deserializer.deserialize_iso, + "rfc-1123": Deserializer.deserialize_rfc, + "unix-time": Deserializer.deserialize_unix, + "duration": Deserializer.deserialize_duration, + "date": Deserializer.deserialize_date, + "time": Deserializer.deserialize_time, + "decimal": Deserializer.deserialize_decimal, + "long": Deserializer.deserialize_long, + "bytearray": Deserializer.deserialize_bytearray, + "base64": Deserializer.deserialize_base64, + "object": self.deserialize_object, + "[]": self.deserialize_iter, + "{}": self.deserialize_dict, + } + self.deserialize_expected_types = { + "duration": (isodate.Duration, datetime.timedelta), + "iso-8601": (datetime.datetime), + } + self.dependencies: Dict[str, type] = dict(classes) if classes else {} + self.key_extractors = [rest_key_extractor, xml_key_extractor] + # Additional properties only works if the "rest_key_extractor" is used to + # extract the keys. Making it to work whatever the key extractor is too much + # complicated, with no real scenario for now. + # So adding a flag to disable additional properties detection. This flag should be + # used if your expect the deserialization to NOT come from a JSON REST syntax. + # Otherwise, result are unexpected + self.additional_properties_detection = True + + def __call__(self, target_obj, response_data, content_type=None): + """Call the deserializer to process a REST response. + + :param str target_obj: Target data type to deserialize to. + :param requests.Response response_data: REST response object. + :param str content_type: Swagger "produces" if available. + :raises DeserializationError: if deserialization fails. + :return: Deserialized object. + :rtype: object + """ + data = self._unpack_content(response_data, content_type) + return self._deserialize(target_obj, data) + + def _deserialize(self, target_obj, data): # pylint: disable=inconsistent-return-statements + """Call the deserializer on a model. + + Data needs to be already deserialized as JSON or XML ElementTree + + :param str target_obj: Target data type to deserialize to. + :param object data: Object to deserialize. + :raises DeserializationError: if deserialization fails. + :return: Deserialized object. + :rtype: object + """ + # This is already a model, go recursive just in case + if hasattr(data, "_attribute_map"): + constants = [name for name, config in getattr(data, "_validation", {}).items() if config.get("constant")] + try: + for attr, mapconfig in data._attribute_map.items(): # pylint: disable=protected-access + if attr in constants: + continue + value = getattr(data, attr) + if value is None: + continue + local_type = mapconfig["type"] + internal_data_type = local_type.strip("[]{}") + if internal_data_type not in self.dependencies or isinstance(internal_data_type, Enum): + continue + setattr(data, attr, self._deserialize(local_type, value)) + return data + except AttributeError: + return + + response, class_name = self._classify_target(target_obj, data) + + if isinstance(response, str): + return self.deserialize_data(data, response) + if isinstance(response, type) and issubclass(response, Enum): + return self.deserialize_enum(data, response) + + if data is None or data is CoreNull: + return data + try: + attributes = response._attribute_map # type: ignore # pylint: disable=protected-access + d_attrs = {} + for attr, attr_desc in attributes.items(): + # Check empty string. If it's not empty, someone has a real "additionalProperties"... + if attr == "additional_properties" and attr_desc["key"] == "": + continue + raw_value = None + # Enhance attr_desc with some dynamic data + attr_desc = attr_desc.copy() # Do a copy, do not change the real one + internal_data_type = attr_desc["type"].strip("[]{}") + if internal_data_type in self.dependencies: + attr_desc["internalType"] = self.dependencies[internal_data_type] + + for key_extractor in self.key_extractors: + found_value = key_extractor(attr, attr_desc, data) + if found_value is not None: + if raw_value is not None and raw_value != found_value: + msg = ( + "Ignoring extracted value '%s' from %s for key '%s'" + " (duplicate extraction, follow extractors order)" + ) + _LOGGER.warning(msg, found_value, key_extractor, attr) + continue + raw_value = found_value + + value = self.deserialize_data(raw_value, attr_desc["type"]) + d_attrs[attr] = value + except (AttributeError, TypeError, KeyError) as err: + msg = "Unable to deserialize to object: " + class_name # type: ignore + raise DeserializationError(msg) from err + additional_properties = self._build_additional_properties(attributes, data) + return self._instantiate_model(response, d_attrs, additional_properties) + + def _build_additional_properties(self, attribute_map, data): + if not self.additional_properties_detection: + return None + if "additional_properties" in attribute_map and attribute_map.get("additional_properties", {}).get("key") != "": + # Check empty string. If it's not empty, someone has a real "additionalProperties" + return None + if isinstance(data, ET.Element): + data = {el.tag: el.text for el in data} + + known_keys = { + _decode_attribute_map_key(_FLATTEN.split(desc["key"])[0]) + for desc in attribute_map.values() + if desc["key"] != "" + } + present_keys = set(data.keys()) + missing_keys = present_keys - known_keys + return {key: data[key] for key in missing_keys} + + def _classify_target(self, target, data): + """Check to see whether the deserialization target object can + be classified into a subclass. + Once classification has been determined, initialize object. + + :param str target: The target object type to deserialize to. + :param str/dict data: The response data to deserialize. + :return: The classified target object and its class name. + :rtype: tuple + """ + if target is None: + return None, None + + if isinstance(target, str): + try: + target = self.dependencies[target] + except KeyError: + return target, target + + try: + target = target._classify(data, self.dependencies) # type: ignore # pylint: disable=protected-access + except AttributeError: + pass # Target is not a Model, no classify + return target, target.__class__.__name__ # type: ignore + + def failsafe_deserialize(self, target_obj, data, content_type=None): + """Ignores any errors encountered in deserialization, + and falls back to not deserializing the object. Recommended + for use in error deserialization, as we want to return the + HttpResponseError to users, and not have them deal with + a deserialization error. + + :param str target_obj: The target object type to deserialize to. + :param str/dict data: The response data to deserialize. + :param str content_type: Swagger "produces" if available. + :return: Deserialized object. + :rtype: object + """ + try: + return self(target_obj, data, content_type=content_type) + except: # pylint: disable=bare-except + _LOGGER.debug( + "Ran into a deserialization error. Ignoring since this is failsafe deserialization", exc_info=True + ) + return None + + @staticmethod + def _unpack_content(raw_data, content_type=None): + """Extract the correct structure for deserialization. + + If raw_data is a PipelineResponse, try to extract the result of RawDeserializer. + if we can't, raise. Your Pipeline should have a RawDeserializer. + + If not a pipeline response and raw_data is bytes or string, use content-type + to decode it. If no content-type, try JSON. + + If raw_data is something else, bypass all logic and return it directly. + + :param obj raw_data: Data to be processed. + :param str content_type: How to parse if raw_data is a string/bytes. + :raises JSONDecodeError: If JSON is requested and parsing is impossible. + :raises UnicodeDecodeError: If bytes is not UTF8 + :rtype: object + :return: Unpacked content. + """ + # Assume this is enough to detect a Pipeline Response without importing it + context = getattr(raw_data, "context", {}) + if context: + if RawDeserializer.CONTEXT_NAME in context: + return context[RawDeserializer.CONTEXT_NAME] + raise ValueError("This pipeline didn't have the RawDeserializer policy; can't deserialize") + + # Assume this is enough to recognize universal_http.ClientResponse without importing it + if hasattr(raw_data, "body"): + return RawDeserializer.deserialize_from_http_generics(raw_data.text(), raw_data.headers) + + # Assume this enough to recognize requests.Response without importing it. + if hasattr(raw_data, "_content_consumed"): + return RawDeserializer.deserialize_from_http_generics(raw_data.text, raw_data.headers) + + if isinstance(raw_data, (str, bytes)) or hasattr(raw_data, "read"): + return RawDeserializer.deserialize_from_text(raw_data, content_type) # type: ignore + return raw_data + + def _instantiate_model(self, response, attrs, additional_properties=None): + """Instantiate a response model passing in deserialized args. + + :param Response response: The response model class. + :param dict attrs: The deserialized response attributes. + :param dict additional_properties: Additional properties to be set. + :rtype: Response + :return: The instantiated response model. + """ + if callable(response): + subtype = getattr(response, "_subtype_map", {}) + try: + readonly = [ + k + for k, v in response._validation.items() # pylint: disable=protected-access # type: ignore + if v.get("readonly") + ] + const = [ + k + for k, v in response._validation.items() # pylint: disable=protected-access # type: ignore + if v.get("constant") + ] + kwargs = {k: v for k, v in attrs.items() if k not in subtype and k not in readonly + const} + response_obj = response(**kwargs) + for attr in readonly: + setattr(response_obj, attr, attrs.get(attr)) + if additional_properties: + response_obj.additional_properties = additional_properties # type: ignore + return response_obj + except TypeError as err: + msg = "Unable to deserialize {} into model {}. ".format(kwargs, response) # type: ignore + raise DeserializationError(msg + str(err)) from err + else: + try: + for attr, value in attrs.items(): + setattr(response, attr, value) + return response + except Exception as exp: + msg = "Unable to populate response model. " + msg += "Type: {}, Error: {}".format(type(response), exp) + raise DeserializationError(msg) from exp + + def deserialize_data(self, data, data_type): # pylint: disable=too-many-return-statements + """Process data for deserialization according to data type. + + :param str data: The response string to be deserialized. + :param str data_type: The type to deserialize to. + :raises DeserializationError: if deserialization fails. + :return: Deserialized object. + :rtype: object + """ + if data is None: + return data + + try: + if not data_type: + return data + if data_type in self.basic_types.values(): + return self.deserialize_basic(data, data_type) + if data_type in self.deserialize_type: + if isinstance(data, self.deserialize_expected_types.get(data_type, tuple())): + return data + + is_a_text_parsing_type = lambda x: x not in [ # pylint: disable=unnecessary-lambda-assignment + "object", + "[]", + r"{}", + ] + if isinstance(data, ET.Element) and is_a_text_parsing_type(data_type) and not data.text: + return None + data_val = self.deserialize_type[data_type](data) + return data_val + + iter_type = data_type[0] + data_type[-1] + if iter_type in self.deserialize_type: + return self.deserialize_type[iter_type](data, data_type[1:-1]) + + obj_type = self.dependencies[data_type] + if issubclass(obj_type, Enum): + if isinstance(data, ET.Element): + data = data.text + return self.deserialize_enum(data, obj_type) + + except (ValueError, TypeError, AttributeError) as err: + msg = "Unable to deserialize response data." + msg += " Data: {}, {}".format(data, data_type) + raise DeserializationError(msg) from err + return self._deserialize(obj_type, data) + + def deserialize_iter(self, attr, iter_type): + """Deserialize an iterable. + + :param list attr: Iterable to be deserialized. + :param str iter_type: The type of object in the iterable. + :return: Deserialized iterable. + :rtype: list + """ + if attr is None: + return None + if isinstance(attr, ET.Element): # If I receive an element here, get the children + attr = list(attr) + if not isinstance(attr, (list, set)): + raise DeserializationError("Cannot deserialize as [{}] an object of type {}".format(iter_type, type(attr))) + return [self.deserialize_data(a, iter_type) for a in attr] + + def deserialize_dict(self, attr, dict_type): + """Deserialize a dictionary. + + :param dict/list attr: Dictionary to be deserialized. Also accepts + a list of key, value pairs. + :param str dict_type: The object type of the items in the dictionary. + :return: Deserialized dictionary. + :rtype: dict + """ + if isinstance(attr, list): + return {x["key"]: self.deserialize_data(x["value"], dict_type) for x in attr} + + if isinstance(attr, ET.Element): + # Transform value into {"Key": "value"} + attr = {el.tag: el.text for el in attr} + return {k: self.deserialize_data(v, dict_type) for k, v in attr.items()} + + def deserialize_object(self, attr, **kwargs): # pylint: disable=too-many-return-statements + """Deserialize a generic object. + This will be handled as a dictionary. + + :param dict attr: Dictionary to be deserialized. + :return: Deserialized object. + :rtype: dict + :raises TypeError: if non-builtin datatype encountered. + """ + if attr is None: + return None + if isinstance(attr, ET.Element): + # Do no recurse on XML, just return the tree as-is + return attr + if isinstance(attr, str): + return self.deserialize_basic(attr, "str") + obj_type = type(attr) + if obj_type in self.basic_types: + return self.deserialize_basic(attr, self.basic_types[obj_type]) + if obj_type is _long_type: + return self.deserialize_long(attr) + + if obj_type == dict: + deserialized = {} + for key, value in attr.items(): + try: + deserialized[key] = self.deserialize_object(value, **kwargs) + except ValueError: + deserialized[key] = None + return deserialized + + if obj_type == list: + deserialized = [] + for obj in attr: + try: + deserialized.append(self.deserialize_object(obj, **kwargs)) + except ValueError: + pass + return deserialized + + error = "Cannot deserialize generic object with type: " + raise TypeError(error + str(obj_type)) + + def deserialize_basic(self, attr, data_type): # pylint: disable=too-many-return-statements + """Deserialize basic builtin data type from string. + Will attempt to convert to str, int, float and bool. + This function will also accept '1', '0', 'true' and 'false' as + valid bool values. + + :param str attr: response string to be deserialized. + :param str data_type: deserialization data type. + :return: Deserialized basic type. + :rtype: str, int, float or bool + :raises TypeError: if string format is not valid. + """ + # If we're here, data is supposed to be a basic type. + # If it's still an XML node, take the text + if isinstance(attr, ET.Element): + attr = attr.text + if not attr: + if data_type == "str": + # None or '', node is empty string. + return "" + # None or '', node with a strong type is None. + # Don't try to model "empty bool" or "empty int" + return None + + if data_type == "bool": + if attr in [True, False, 1, 0]: + return bool(attr) + if isinstance(attr, str): + if attr.lower() in ["true", "1"]: + return True + if attr.lower() in ["false", "0"]: + return False + raise TypeError("Invalid boolean value: {}".format(attr)) + + if data_type == "str": + return self.deserialize_unicode(attr) + return eval(data_type)(attr) # nosec # pylint: disable=eval-used + + @staticmethod + def deserialize_unicode(data): + """Preserve unicode objects in Python 2, otherwise return data + as a string. + + :param str data: response string to be deserialized. + :return: Deserialized string. + :rtype: str or unicode + """ + # We might be here because we have an enum modeled as string, + # and we try to deserialize a partial dict with enum inside + if isinstance(data, Enum): + return data + + # Consider this is real string + try: + if isinstance(data, unicode): # type: ignore + return data + except NameError: + return str(data) + return str(data) + + @staticmethod + def deserialize_enum(data, enum_obj): + """Deserialize string into enum object. + + If the string is not a valid enum value it will be returned as-is + and a warning will be logged. + + :param str data: Response string to be deserialized. If this value is + None or invalid it will be returned as-is. + :param Enum enum_obj: Enum object to deserialize to. + :return: Deserialized enum object. + :rtype: Enum + """ + if isinstance(data, enum_obj) or data is None: + return data + if isinstance(data, Enum): + data = data.value + if isinstance(data, int): + # Workaround. We might consider remove it in the future. + try: + return list(enum_obj.__members__.values())[data] + except IndexError as exc: + error = "{!r} is not a valid index for enum {!r}" + raise DeserializationError(error.format(data, enum_obj)) from exc + try: + return enum_obj(str(data)) + except ValueError: + for enum_value in enum_obj: + if enum_value.value.lower() == str(data).lower(): + return enum_value + # We don't fail anymore for unknown value, we deserialize as a string + _LOGGER.warning("Deserializer is not able to find %s as valid enum in %s", data, enum_obj) + return Deserializer.deserialize_unicode(data) + + @staticmethod + def deserialize_bytearray(attr): + """Deserialize string into bytearray. + + :param str attr: response string to be deserialized. + :return: Deserialized bytearray + :rtype: bytearray + :raises TypeError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + return bytearray(b64decode(attr)) # type: ignore + + @staticmethod + def deserialize_base64(attr): + """Deserialize base64 encoded string into string. + + :param str attr: response string to be deserialized. + :return: Deserialized base64 string + :rtype: bytearray + :raises TypeError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + padding = "=" * (3 - (len(attr) + 3) % 4) # type: ignore + attr = attr + padding # type: ignore + encoded = attr.replace("-", "+").replace("_", "/") + return b64decode(encoded) + + @staticmethod + def deserialize_decimal(attr): + """Deserialize string into Decimal object. + + :param str attr: response string to be deserialized. + :return: Deserialized decimal + :raises DeserializationError: if string format invalid. + :rtype: decimal + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + return decimal.Decimal(str(attr)) # type: ignore + except decimal.DecimalException as err: + msg = "Invalid decimal {}".format(attr) + raise DeserializationError(msg) from err + + @staticmethod + def deserialize_long(attr): + """Deserialize string into long (Py2) or int (Py3). + + :param str attr: response string to be deserialized. + :return: Deserialized int + :rtype: long or int + :raises ValueError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + return _long_type(attr) # type: ignore + + @staticmethod + def deserialize_duration(attr): + """Deserialize ISO-8601 formatted string into TimeDelta object. + + :param str attr: response string to be deserialized. + :return: Deserialized duration + :rtype: TimeDelta + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + duration = isodate.parse_duration(attr) + except (ValueError, OverflowError, AttributeError) as err: + msg = "Cannot deserialize duration object." + raise DeserializationError(msg) from err + return duration + + @staticmethod + def deserialize_date(attr): + """Deserialize ISO-8601 formatted string into Date object. + + :param str attr: response string to be deserialized. + :return: Deserialized date + :rtype: Date + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + if re.search(r"[^\W\d_]", attr, re.I + re.U): # type: ignore + raise DeserializationError("Date must have only digits and -. Received: %s" % attr) + # This must NOT use defaultmonth/defaultday. Using None ensure this raises an exception. + return isodate.parse_date(attr, defaultmonth=0, defaultday=0) + + @staticmethod + def deserialize_time(attr): + """Deserialize ISO-8601 formatted string into time object. + + :param str attr: response string to be deserialized. + :return: Deserialized time + :rtype: datetime.time + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + if re.search(r"[^\W\d_]", attr, re.I + re.U): # type: ignore + raise DeserializationError("Date must have only digits and -. Received: %s" % attr) + return isodate.parse_time(attr) + + @staticmethod + def deserialize_rfc(attr): + """Deserialize RFC-1123 formatted string into Datetime object. + + :param str attr: response string to be deserialized. + :return: Deserialized RFC datetime + :rtype: Datetime + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + parsed_date = email.utils.parsedate_tz(attr) # type: ignore + date_obj = datetime.datetime( + *parsed_date[:6], tzinfo=datetime.timezone(datetime.timedelta(minutes=(parsed_date[9] or 0) / 60)) + ) + if not date_obj.tzinfo: + date_obj = date_obj.astimezone(tz=TZ_UTC) + except ValueError as err: + msg = "Cannot deserialize to rfc datetime object." + raise DeserializationError(msg) from err + return date_obj + + @staticmethod + def deserialize_iso(attr): + """Deserialize ISO-8601 formatted string into Datetime object. + + :param str attr: response string to be deserialized. + :return: Deserialized ISO datetime + :rtype: Datetime + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + attr = attr.upper() # type: ignore + match = Deserializer.valid_date.match(attr) + if not match: + raise ValueError("Invalid datetime string: " + attr) + + check_decimal = attr.split(".") + if len(check_decimal) > 1: + decimal_str = "" + for digit in check_decimal[1]: + if digit.isdigit(): + decimal_str += digit + else: + break + if len(decimal_str) > 6: + attr = attr.replace(decimal_str, decimal_str[0:6]) + + date_obj = isodate.parse_datetime(attr) + test_utc = date_obj.utctimetuple() + if test_utc.tm_year > 9999 or test_utc.tm_year < 1: + raise OverflowError("Hit max or min date") + except (ValueError, OverflowError, AttributeError) as err: + msg = "Cannot deserialize datetime object." + raise DeserializationError(msg) from err + return date_obj + + @staticmethod + def deserialize_unix(attr): + """Serialize Datetime object into IntTime format. + This is represented as seconds. + + :param int attr: Object to be serialized. + :return: Deserialized datetime + :rtype: Datetime + :raises DeserializationError: if format invalid + """ + if isinstance(attr, ET.Element): + attr = int(attr.text) # type: ignore + try: + attr = int(attr) + date_obj = datetime.datetime.fromtimestamp(attr, TZ_UTC) + except ValueError as err: + msg = "Cannot deserialize to unix datetime object." + raise DeserializationError(msg) from err + return date_obj diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/Multiapi/multiapi/aio/_multiapi_service_client.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/Multiapi/multiapi/aio/_multiapi_service_client.py index 365891d215c..34d74133d0d 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/Multiapi/multiapi/aio/_multiapi_service_client.py +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/Multiapi/multiapi/aio/_multiapi_service_client.py @@ -20,7 +20,7 @@ from azure.profiles import KnownProfiles, ProfileDefinition from azure.profiles.multiapiclient import MultiApiClientMixin -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import MultiapiServiceClientConfiguration from ._operations_mixin import MultiapiServiceClientOperationsMixin diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/Multiapi/multiapi/aio/_operations_mixin.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/Multiapi/multiapi/aio/_operations_mixin.py index db0e76b029a..12cc546f38e 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/Multiapi/multiapi/aio/_operations_mixin.py +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/Multiapi/multiapi/aio/_operations_mixin.py @@ -8,7 +8,7 @@ # Changes may cause incorrect behavior and will be lost if the code is # regenerated. # -------------------------------------------------------------------------- -from .._serialization import Serializer, Deserializer +from .._utils.serialization import Serializer, Deserializer from io import IOBase from typing import Any, AsyncIterable, AsyncIterator, IO, Optional, Union diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/Multiapi/multiapi/v0/_metadata.json b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/Multiapi/multiapi/v0/_metadata.json index 324008105d8..74cca69637f 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/Multiapi/multiapi/v0/_metadata.json +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/Multiapi/multiapi/v0/_metadata.json @@ -10,8 +10,8 @@ "azure_arm": true, "has_public_lro_operations": false, "client_side_validation": false, - "sync_imports": "{\"conditional\": {\"stdlib\": {\"typing\": [\"Any\", \"Optional\"]}}, \"regular\": {\"sdkcore\": {\"azure.mgmt.core\": [\"ARMPipelineClient\"], \"azure.core.pipeline\": [\"policies\"], \"azure.mgmt.core.policies\": [\"ARMAutoResourceProviderRegistrationPolicy\"], \"azure.core.settings\": [\"settings\"], \"azure.mgmt.core.tools\": [\"get_arm_endpoints\"], \"azure.profiles\": [\"KnownProfiles\", \"ProfileDefinition\"], \"azure.profiles.multiapiclient\": [\"MultiApiClientMixin\"]}, \"stdlib\": {\"typing\": [\"Optional\", \"cast\"], \"typing_extensions\": [\"Self\"]}, \"local\": {\"._configuration\": [\"MultiapiServiceClientConfiguration\"], \".._serialization\": [\"Deserializer\", \"Serializer\"]}}, \"typing\": {\"sdkcore\": {\"azure.core.credentials\": [\"TokenCredential\"]}}}", - "async_imports": "{\"conditional\": {\"stdlib\": {\"typing\": [\"Any\", \"Optional\"]}}, \"regular\": {\"sdkcore\": {\"azure.mgmt.core\": [\"AsyncARMPipelineClient\"], \"azure.core.pipeline\": [\"policies\"], \"azure.mgmt.core.policies\": [\"AsyncARMAutoResourceProviderRegistrationPolicy\"], \"azure.core.settings\": [\"settings\"], \"azure.mgmt.core.tools\": [\"get_arm_endpoints\"], \"azure.profiles\": [\"KnownProfiles\", \"ProfileDefinition\"], \"azure.profiles.multiapiclient\": [\"MultiApiClientMixin\"]}, \"stdlib\": {\"typing\": [\"Optional\", \"cast\"], \"typing_extensions\": [\"Self\"]}, \"local\": {\"._configuration\": [\"MultiapiServiceClientConfiguration\"], \"..._serialization\": [\"Deserializer\", \"Serializer\"]}}, \"typing\": {\"sdkcore\": {\"azure.core.credentials_async\": [\"AsyncTokenCredential\"]}}}" + "sync_imports": "{\"conditional\": {\"stdlib\": {\"typing\": [\"Any\", \"Optional\"]}}, \"regular\": {\"sdkcore\": {\"azure.mgmt.core\": [\"ARMPipelineClient\"], \"azure.core.pipeline\": [\"policies\"], \"azure.mgmt.core.policies\": [\"ARMAutoResourceProviderRegistrationPolicy\"], \"azure.core.settings\": [\"settings\"], \"azure.mgmt.core.tools\": [\"get_arm_endpoints\"], \"azure.profiles\": [\"KnownProfiles\", \"ProfileDefinition\"], \"azure.profiles.multiapiclient\": [\"MultiApiClientMixin\"]}, \"stdlib\": {\"typing\": [\"Optional\", \"cast\"], \"typing_extensions\": [\"Self\"]}, \"local\": {\"._configuration\": [\"MultiapiServiceClientConfiguration\"], \"._utils.serialization\": [\"Deserializer\", \"Serializer\"]}}, \"typing\": {\"sdkcore\": {\"azure.core.credentials\": [\"TokenCredential\"]}}}", + "async_imports": "{\"conditional\": {\"stdlib\": {\"typing\": [\"Any\", \"Optional\"]}}, \"regular\": {\"sdkcore\": {\"azure.mgmt.core\": [\"AsyncARMPipelineClient\"], \"azure.core.pipeline\": [\"policies\"], \"azure.mgmt.core.policies\": [\"AsyncARMAutoResourceProviderRegistrationPolicy\"], \"azure.core.settings\": [\"settings\"], \"azure.mgmt.core.tools\": [\"get_arm_endpoints\"], \"azure.profiles\": [\"KnownProfiles\", \"ProfileDefinition\"], \"azure.profiles.multiapiclient\": [\"MultiApiClientMixin\"]}, \"stdlib\": {\"typing\": [\"Optional\", \"cast\"], \"typing_extensions\": [\"Self\"]}, \"local\": {\"._configuration\": [\"MultiapiServiceClientConfiguration\"], \".._utils.serialization\": [\"Deserializer\", \"Serializer\"]}}, \"typing\": {\"sdkcore\": {\"azure.core.credentials_async\": [\"AsyncTokenCredential\"]}}}" }, "global_parameters": { "sync": { diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/Multiapi/multiapi/v0/_multiapi_service_client.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/Multiapi/multiapi/v0/_multiapi_service_client.py index 83df6441588..cf004e34f17 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/Multiapi/multiapi/v0/_multiapi_service_client.py +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/Multiapi/multiapi/v0/_multiapi_service_client.py @@ -18,8 +18,8 @@ from azure.mgmt.core.tools import get_arm_endpoints from . import models as _models -from .._serialization import Deserializer, Serializer from ._configuration import MultiapiServiceClientConfiguration +from ._utils.serialization import Deserializer, Serializer from .operations import OperationGroupOneOperations if TYPE_CHECKING: diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/Multiapi/multiapi/v0/_utils/__init__.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/Multiapi/multiapi/v0/_utils/__init__.py new file mode 100644 index 00000000000..0af9b28f660 --- /dev/null +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/Multiapi/multiapi/v0/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyFile/bodyfile/_serialization.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/Multiapi/multiapi/v0/_utils/serialization.py similarity index 100% rename from packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyFile/bodyfile/_serialization.py rename to packages/autorest.python/test/multiapi/Expected/AcceptanceTests/Multiapi/multiapi/v0/_utils/serialization.py diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/Multiapi/multiapi/v0/aio/_multiapi_service_client.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/Multiapi/multiapi/v0/aio/_multiapi_service_client.py index 3a7915ecf91..b6fe81cc19a 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/Multiapi/multiapi/v0/aio/_multiapi_service_client.py +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/Multiapi/multiapi/v0/aio/_multiapi_service_client.py @@ -18,7 +18,7 @@ from azure.mgmt.core.tools import get_arm_endpoints from .. import models as _models -from ..._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import MultiapiServiceClientConfiguration from .operations import OperationGroupOneOperations diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/Multiapi/multiapi/v0/aio/operations/_operation_group_one_operations.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/Multiapi/multiapi/v0/aio/operations/_operation_group_one_operations.py index 39bb51dadd5..75ce9a0d60a 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/Multiapi/multiapi/v0/aio/operations/_operation_group_one_operations.py +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/Multiapi/multiapi/v0/aio/operations/_operation_group_one_operations.py @@ -24,7 +24,7 @@ from azure.mgmt.core.exceptions import ARMErrorFormat from ... import models as _models -from ...._serialization import Deserializer, Serializer +from ..._utils.serialization import Deserializer, Serializer from ...operations._operation_group_one_operations import build_test_two_request from .._configuration import MultiapiServiceClientConfiguration diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/Multiapi/multiapi/v0/models/_models_py3.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/Multiapi/multiapi/v0/models/_models_py3.py index 89176e0e663..6e2a859e193 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/Multiapi/multiapi/v0/models/_models_py3.py +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/Multiapi/multiapi/v0/models/_models_py3.py @@ -8,7 +8,7 @@ from typing import Any, List, Optional, TYPE_CHECKING -from ... import _serialization +from .._utils import serialization as _serialization if TYPE_CHECKING: from .. import models as _models diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/Multiapi/multiapi/v0/operations/_operation_group_one_operations.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/Multiapi/multiapi/v0/operations/_operation_group_one_operations.py index a155895eba9..752319f4062 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/Multiapi/multiapi/v0/operations/_operation_group_one_operations.py +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/Multiapi/multiapi/v0/operations/_operation_group_one_operations.py @@ -24,8 +24,8 @@ from azure.mgmt.core.exceptions import ARMErrorFormat from .. import models as _models -from ..._serialization import Deserializer, Serializer from .._configuration import MultiapiServiceClientConfiguration +from .._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/Multiapi/multiapi/v1/_metadata.json b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/Multiapi/multiapi/v1/_metadata.json index a1718b732e9..281296057d2 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/Multiapi/multiapi/v1/_metadata.json +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/Multiapi/multiapi/v1/_metadata.json @@ -10,8 +10,8 @@ "azure_arm": true, "has_public_lro_operations": true, "client_side_validation": false, - "sync_imports": "{\"conditional\": {\"stdlib\": {\"typing\": [\"Any\", \"Optional\"]}}, \"regular\": {\"sdkcore\": {\"azure.mgmt.core\": [\"ARMPipelineClient\"], \"azure.core.pipeline\": [\"policies\"], \"azure.mgmt.core.policies\": [\"ARMAutoResourceProviderRegistrationPolicy\"], \"azure.core.settings\": [\"settings\"], \"azure.mgmt.core.tools\": [\"get_arm_endpoints\"], \"azure.profiles\": [\"KnownProfiles\", \"ProfileDefinition\"], \"azure.profiles.multiapiclient\": [\"MultiApiClientMixin\"]}, \"stdlib\": {\"typing\": [\"Optional\", \"cast\"], \"typing_extensions\": [\"Self\"]}, \"local\": {\"._configuration\": [\"MultiapiServiceClientConfiguration\"], \".._serialization\": [\"Deserializer\", \"Serializer\"], \"._operations_mixin\": [\"MultiapiServiceClientOperationsMixin\"]}}, \"typing\": {\"sdkcore\": {\"azure.core.credentials\": [\"TokenCredential\"]}}}", - "async_imports": "{\"conditional\": {\"stdlib\": {\"typing\": [\"Any\", \"Optional\"]}}, \"regular\": {\"sdkcore\": {\"azure.mgmt.core\": [\"AsyncARMPipelineClient\"], \"azure.core.pipeline\": [\"policies\"], \"azure.mgmt.core.policies\": [\"AsyncARMAutoResourceProviderRegistrationPolicy\"], \"azure.core.settings\": [\"settings\"], \"azure.mgmt.core.tools\": [\"get_arm_endpoints\"], \"azure.profiles\": [\"KnownProfiles\", \"ProfileDefinition\"], \"azure.profiles.multiapiclient\": [\"MultiApiClientMixin\"]}, \"stdlib\": {\"typing\": [\"Optional\", \"cast\"], \"typing_extensions\": [\"Self\"]}, \"local\": {\"._configuration\": [\"MultiapiServiceClientConfiguration\"], \"..._serialization\": [\"Deserializer\", \"Serializer\"], \"._operations_mixin\": [\"MultiapiServiceClientOperationsMixin\"]}}, \"typing\": {\"sdkcore\": {\"azure.core.credentials_async\": [\"AsyncTokenCredential\"]}}}" + "sync_imports": "{\"conditional\": {\"stdlib\": {\"typing\": [\"Any\", \"Optional\"]}}, \"regular\": {\"sdkcore\": {\"azure.mgmt.core\": [\"ARMPipelineClient\"], \"azure.core.pipeline\": [\"policies\"], \"azure.mgmt.core.policies\": [\"ARMAutoResourceProviderRegistrationPolicy\"], \"azure.core.settings\": [\"settings\"], \"azure.mgmt.core.tools\": [\"get_arm_endpoints\"], \"azure.profiles\": [\"KnownProfiles\", \"ProfileDefinition\"], \"azure.profiles.multiapiclient\": [\"MultiApiClientMixin\"]}, \"stdlib\": {\"typing\": [\"Optional\", \"cast\"], \"typing_extensions\": [\"Self\"]}, \"local\": {\"._configuration\": [\"MultiapiServiceClientConfiguration\"], \"._utils.serialization\": [\"Deserializer\", \"Serializer\"], \"._operations_mixin\": [\"MultiapiServiceClientOperationsMixin\"]}}, \"typing\": {\"sdkcore\": {\"azure.core.credentials\": [\"TokenCredential\"]}}}", + "async_imports": "{\"conditional\": {\"stdlib\": {\"typing\": [\"Any\", \"Optional\"]}}, \"regular\": {\"sdkcore\": {\"azure.mgmt.core\": [\"AsyncARMPipelineClient\"], \"azure.core.pipeline\": [\"policies\"], \"azure.mgmt.core.policies\": [\"AsyncARMAutoResourceProviderRegistrationPolicy\"], \"azure.core.settings\": [\"settings\"], \"azure.mgmt.core.tools\": [\"get_arm_endpoints\"], \"azure.profiles\": [\"KnownProfiles\", \"ProfileDefinition\"], \"azure.profiles.multiapiclient\": [\"MultiApiClientMixin\"]}, \"stdlib\": {\"typing\": [\"Optional\", \"cast\"], \"typing_extensions\": [\"Self\"]}, \"local\": {\"._configuration\": [\"MultiapiServiceClientConfiguration\"], \".._utils.serialization\": [\"Deserializer\", \"Serializer\"], \"._operations_mixin\": [\"MultiapiServiceClientOperationsMixin\"]}}, \"typing\": {\"sdkcore\": {\"azure.core.credentials_async\": [\"AsyncTokenCredential\"]}}}" }, "global_parameters": { "sync": { diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/Multiapi/multiapi/v1/_multiapi_service_client.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/Multiapi/multiapi/v1/_multiapi_service_client.py index 50b4f20a94c..a6f6f24b0ed 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/Multiapi/multiapi/v1/_multiapi_service_client.py +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/Multiapi/multiapi/v1/_multiapi_service_client.py @@ -18,8 +18,8 @@ from azure.mgmt.core.tools import get_arm_endpoints from . import models as _models -from .._serialization import Deserializer, Serializer from ._configuration import MultiapiServiceClientConfiguration +from ._utils.serialization import Deserializer, Serializer from .operations import MultiapiServiceClientOperationsMixin, OperationGroupOneOperations if TYPE_CHECKING: diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/Multiapi/multiapi/v1/_utils/__init__.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/Multiapi/multiapi/v1/_utils/__init__.py new file mode 100644 index 00000000000..0af9b28f660 --- /dev/null +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/Multiapi/multiapi/v1/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyFormData/bodyformdata/_serialization.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/Multiapi/multiapi/v1/_utils/serialization.py similarity index 100% rename from packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyFormData/bodyformdata/_serialization.py rename to packages/autorest.python/test/multiapi/Expected/AcceptanceTests/Multiapi/multiapi/v1/_utils/serialization.py diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/Multiapi/multiapi/v1/_utils/utils.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/Multiapi/multiapi/v1/_utils/utils.py new file mode 100644 index 00000000000..39b612f39a9 --- /dev/null +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/Multiapi/multiapi/v1/_utils/utils.py @@ -0,0 +1,25 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from abc import ABC +from typing import Generic, TYPE_CHECKING, TypeVar + +if TYPE_CHECKING: + from .serialization import Deserializer, Serializer + + +TClient = TypeVar("TClient") +TConfig = TypeVar("TConfig") + + +class ClientMixinABC(ABC, Generic[TClient, TConfig]): + """DO NOT use this class. It is for internal typing use only.""" + + _client: TClient + _config: TConfig + _serialize: "Serializer" + _deserialize: "Deserializer" diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/Multiapi/multiapi/v1/_vendor.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/Multiapi/multiapi/v1/_vendor.py deleted file mode 100644 index 70517e0b7af..00000000000 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/Multiapi/multiapi/v1/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) AutoRest Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import MultiapiServiceClientConfiguration - -if TYPE_CHECKING: - from azure.core import PipelineClient - - from .._serialization import Deserializer, Serializer - - -class MultiapiServiceClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "PipelineClient" - _config: MultiapiServiceClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/Multiapi/multiapi/v1/aio/_multiapi_service_client.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/Multiapi/multiapi/v1/aio/_multiapi_service_client.py index 7a4f9ced0aa..754adfa89d6 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/Multiapi/multiapi/v1/aio/_multiapi_service_client.py +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/Multiapi/multiapi/v1/aio/_multiapi_service_client.py @@ -18,7 +18,7 @@ from azure.mgmt.core.tools import get_arm_endpoints from .. import models as _models -from ..._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import MultiapiServiceClientConfiguration from .operations import MultiapiServiceClientOperationsMixin, OperationGroupOneOperations diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/Multiapi/multiapi/v1/aio/_vendor.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/Multiapi/multiapi/v1/aio/_vendor.py deleted file mode 100644 index 9c6fd05bb21..00000000000 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/Multiapi/multiapi/v1/aio/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) AutoRest Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import MultiapiServiceClientConfiguration - -if TYPE_CHECKING: - from azure.core import AsyncPipelineClient - - from ..._serialization import Deserializer, Serializer - - -class MultiapiServiceClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "AsyncPipelineClient" - _config: MultiapiServiceClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/Multiapi/multiapi/v1/aio/operations/_multiapi_service_client_operations.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/Multiapi/multiapi/v1/aio/operations/_multiapi_service_client_operations.py index 96de5df5497..fc745fc9751 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/Multiapi/multiapi/v1/aio/operations/_multiapi_service_client_operations.py +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/Multiapi/multiapi/v1/aio/operations/_multiapi_service_client_operations.py @@ -11,6 +11,7 @@ from typing import Any, AsyncIterable, AsyncIterator, Callable, Dict, IO, Optional, TypeVar, Union, cast, overload import urllib.parse +from azure.core import AsyncPipelineClient from azure.core.async_paging import AsyncItemPaged, AsyncList from azure.core.exceptions import ( ClientAuthenticationError, @@ -32,19 +33,20 @@ from azure.mgmt.core.polling.async_arm_polling import AsyncARMPolling from ... import models as _models +from ..._utils.utils import ClientMixinABC from ...operations._multiapi_service_client_operations import ( build_test_different_calls_request, build_test_lro_and_paging_request, build_test_lro_request, build_test_one_request, ) -from .._vendor import MultiapiServiceClientMixinABC +from .._configuration import MultiapiServiceClientConfiguration T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, AsyncHttpResponse], T, Dict[str, Any]], Any]] -class MultiapiServiceClientOperationsMixin(MultiapiServiceClientMixinABC): +class MultiapiServiceClientOperationsMixin(ClientMixinABC[AsyncPipelineClient, MultiapiServiceClientConfiguration]): def _api_version(self, op_name: str) -> str: # pylint: disable=unused-argument try: return self._config.api_version diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/Multiapi/multiapi/v1/aio/operations/_operation_group_one_operations.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/Multiapi/multiapi/v1/aio/operations/_operation_group_one_operations.py index 648a9431cf1..6ef6155be1d 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/Multiapi/multiapi/v1/aio/operations/_operation_group_one_operations.py +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/Multiapi/multiapi/v1/aio/operations/_operation_group_one_operations.py @@ -24,7 +24,7 @@ from azure.mgmt.core.exceptions import ARMErrorFormat from ... import models as _models -from ...._serialization import Deserializer, Serializer +from ..._utils.serialization import Deserializer, Serializer from ...operations._operation_group_one_operations import build_test_two_request from .._configuration import MultiapiServiceClientConfiguration diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/Multiapi/multiapi/v1/models/_models_py3.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/Multiapi/multiapi/v1/models/_models_py3.py index 996681e3e2c..d0122abf511 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/Multiapi/multiapi/v1/models/_models_py3.py +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/Multiapi/multiapi/v1/models/_models_py3.py @@ -8,7 +8,7 @@ from typing import Any, List, Optional, TYPE_CHECKING -from ... import _serialization +from .._utils import serialization as _serialization if TYPE_CHECKING: from .. import models as _models diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/Multiapi/multiapi/v1/operations/_multiapi_service_client_operations.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/Multiapi/multiapi/v1/operations/_multiapi_service_client_operations.py index 3be44415f80..894347174ec 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/Multiapi/multiapi/v1/operations/_multiapi_service_client_operations.py +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/Multiapi/multiapi/v1/operations/_multiapi_service_client_operations.py @@ -10,6 +10,7 @@ from typing import Any, Callable, Dict, IO, Iterable, Iterator, Optional, TypeVar, Union, cast, overload import urllib.parse +from azure.core import PipelineClient from azure.core.exceptions import ( ClientAuthenticationError, HttpResponseError, @@ -30,8 +31,9 @@ from azure.mgmt.core.polling.arm_polling import ARMPolling from .. import models as _models -from ..._serialization import Serializer -from .._vendor import MultiapiServiceClientMixinABC +from .._configuration import MultiapiServiceClientConfiguration +from .._utils.serialization import Serializer +from .._utils.utils import ClientMixinABC T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] @@ -121,7 +123,7 @@ def build_test_different_calls_request(*, greeting_in_english: str, **kwargs: An return HttpRequest(method="GET", url=_url, params=_params, headers=_headers, **kwargs) -class MultiapiServiceClientOperationsMixin(MultiapiServiceClientMixinABC): +class MultiapiServiceClientOperationsMixin(ClientMixinABC[PipelineClient, MultiapiServiceClientConfiguration]): def _api_version(self, op_name: str) -> str: # pylint: disable=unused-argument try: return self._config.api_version diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/Multiapi/multiapi/v1/operations/_operation_group_one_operations.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/Multiapi/multiapi/v1/operations/_operation_group_one_operations.py index 02ce8feb250..994d9ef6467 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/Multiapi/multiapi/v1/operations/_operation_group_one_operations.py +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/Multiapi/multiapi/v1/operations/_operation_group_one_operations.py @@ -24,8 +24,8 @@ from azure.mgmt.core.exceptions import ARMErrorFormat from .. import models as _models -from ..._serialization import Deserializer, Serializer from .._configuration import MultiapiServiceClientConfiguration +from .._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/Multiapi/multiapi/v2/_metadata.json b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/Multiapi/multiapi/v2/_metadata.json index 2449421e000..3788bb71088 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/Multiapi/multiapi/v2/_metadata.json +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/Multiapi/multiapi/v2/_metadata.json @@ -10,8 +10,8 @@ "azure_arm": true, "has_public_lro_operations": false, "client_side_validation": false, - "sync_imports": "{\"conditional\": {\"stdlib\": {\"typing\": [\"Any\", \"Optional\"]}}, \"regular\": {\"sdkcore\": {\"azure.mgmt.core\": [\"ARMPipelineClient\"], \"azure.core.pipeline\": [\"policies\"], \"azure.mgmt.core.policies\": [\"ARMAutoResourceProviderRegistrationPolicy\"], \"azure.core.settings\": [\"settings\"], \"azure.mgmt.core.tools\": [\"get_arm_endpoints\"], \"azure.profiles\": [\"KnownProfiles\", \"ProfileDefinition\"], \"azure.profiles.multiapiclient\": [\"MultiApiClientMixin\"]}, \"stdlib\": {\"typing\": [\"Optional\", \"cast\"], \"typing_extensions\": [\"Self\"]}, \"local\": {\"._configuration\": [\"MultiapiServiceClientConfiguration\"], \".._serialization\": [\"Deserializer\", \"Serializer\"], \"._operations_mixin\": [\"MultiapiServiceClientOperationsMixin\"]}}, \"typing\": {\"sdkcore\": {\"azure.core.credentials\": [\"TokenCredential\"]}}}", - "async_imports": "{\"conditional\": {\"stdlib\": {\"typing\": [\"Any\", \"Optional\"]}}, \"regular\": {\"sdkcore\": {\"azure.mgmt.core\": [\"AsyncARMPipelineClient\"], \"azure.core.pipeline\": [\"policies\"], \"azure.mgmt.core.policies\": [\"AsyncARMAutoResourceProviderRegistrationPolicy\"], \"azure.core.settings\": [\"settings\"], \"azure.mgmt.core.tools\": [\"get_arm_endpoints\"], \"azure.profiles\": [\"KnownProfiles\", \"ProfileDefinition\"], \"azure.profiles.multiapiclient\": [\"MultiApiClientMixin\"]}, \"stdlib\": {\"typing\": [\"Optional\", \"cast\"], \"typing_extensions\": [\"Self\"]}, \"local\": {\"._configuration\": [\"MultiapiServiceClientConfiguration\"], \"..._serialization\": [\"Deserializer\", \"Serializer\"], \"._operations_mixin\": [\"MultiapiServiceClientOperationsMixin\"]}}, \"typing\": {\"sdkcore\": {\"azure.core.credentials_async\": [\"AsyncTokenCredential\"]}}}" + "sync_imports": "{\"conditional\": {\"stdlib\": {\"typing\": [\"Any\", \"Optional\"]}}, \"regular\": {\"sdkcore\": {\"azure.mgmt.core\": [\"ARMPipelineClient\"], \"azure.core.pipeline\": [\"policies\"], \"azure.mgmt.core.policies\": [\"ARMAutoResourceProviderRegistrationPolicy\"], \"azure.core.settings\": [\"settings\"], \"azure.mgmt.core.tools\": [\"get_arm_endpoints\"], \"azure.profiles\": [\"KnownProfiles\", \"ProfileDefinition\"], \"azure.profiles.multiapiclient\": [\"MultiApiClientMixin\"]}, \"stdlib\": {\"typing\": [\"Optional\", \"cast\"], \"typing_extensions\": [\"Self\"]}, \"local\": {\"._configuration\": [\"MultiapiServiceClientConfiguration\"], \"._utils.serialization\": [\"Deserializer\", \"Serializer\"], \"._operations_mixin\": [\"MultiapiServiceClientOperationsMixin\"]}}, \"typing\": {\"sdkcore\": {\"azure.core.credentials\": [\"TokenCredential\"]}}}", + "async_imports": "{\"conditional\": {\"stdlib\": {\"typing\": [\"Any\", \"Optional\"]}}, \"regular\": {\"sdkcore\": {\"azure.mgmt.core\": [\"AsyncARMPipelineClient\"], \"azure.core.pipeline\": [\"policies\"], \"azure.mgmt.core.policies\": [\"AsyncARMAutoResourceProviderRegistrationPolicy\"], \"azure.core.settings\": [\"settings\"], \"azure.mgmt.core.tools\": [\"get_arm_endpoints\"], \"azure.profiles\": [\"KnownProfiles\", \"ProfileDefinition\"], \"azure.profiles.multiapiclient\": [\"MultiApiClientMixin\"]}, \"stdlib\": {\"typing\": [\"Optional\", \"cast\"], \"typing_extensions\": [\"Self\"]}, \"local\": {\"._configuration\": [\"MultiapiServiceClientConfiguration\"], \".._utils.serialization\": [\"Deserializer\", \"Serializer\"], \"._operations_mixin\": [\"MultiapiServiceClientOperationsMixin\"]}}, \"typing\": {\"sdkcore\": {\"azure.core.credentials_async\": [\"AsyncTokenCredential\"]}}}" }, "global_parameters": { "sync": { diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/Multiapi/multiapi/v2/_multiapi_service_client.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/Multiapi/multiapi/v2/_multiapi_service_client.py index 044a145bb95..142934cc6b3 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/Multiapi/multiapi/v2/_multiapi_service_client.py +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/Multiapi/multiapi/v2/_multiapi_service_client.py @@ -18,8 +18,8 @@ from azure.mgmt.core.tools import get_arm_endpoints from . import models as _models -from .._serialization import Deserializer, Serializer from ._configuration import MultiapiServiceClientConfiguration +from ._utils.serialization import Deserializer, Serializer from .operations import MultiapiServiceClientOperationsMixin, OperationGroupOneOperations, OperationGroupTwoOperations if TYPE_CHECKING: diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/Multiapi/multiapi/v2/_utils/__init__.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/Multiapi/multiapi/v2/_utils/__init__.py new file mode 100644 index 00000000000..0af9b28f660 --- /dev/null +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/Multiapi/multiapi/v2/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyFormUrlEncodedData/bodyformurlencodeddata/_serialization.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/Multiapi/multiapi/v2/_utils/serialization.py similarity index 100% rename from packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyFormUrlEncodedData/bodyformurlencodeddata/_serialization.py rename to packages/autorest.python/test/multiapi/Expected/AcceptanceTests/Multiapi/multiapi/v2/_utils/serialization.py diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/Multiapi/multiapi/v2/_utils/utils.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/Multiapi/multiapi/v2/_utils/utils.py new file mode 100644 index 00000000000..39b612f39a9 --- /dev/null +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/Multiapi/multiapi/v2/_utils/utils.py @@ -0,0 +1,25 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from abc import ABC +from typing import Generic, TYPE_CHECKING, TypeVar + +if TYPE_CHECKING: + from .serialization import Deserializer, Serializer + + +TClient = TypeVar("TClient") +TConfig = TypeVar("TConfig") + + +class ClientMixinABC(ABC, Generic[TClient, TConfig]): + """DO NOT use this class. It is for internal typing use only.""" + + _client: TClient + _config: TConfig + _serialize: "Serializer" + _deserialize: "Deserializer" diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/Multiapi/multiapi/v2/_vendor.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/Multiapi/multiapi/v2/_vendor.py deleted file mode 100644 index 70517e0b7af..00000000000 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/Multiapi/multiapi/v2/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) AutoRest Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import MultiapiServiceClientConfiguration - -if TYPE_CHECKING: - from azure.core import PipelineClient - - from .._serialization import Deserializer, Serializer - - -class MultiapiServiceClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "PipelineClient" - _config: MultiapiServiceClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/Multiapi/multiapi/v2/aio/_multiapi_service_client.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/Multiapi/multiapi/v2/aio/_multiapi_service_client.py index ba82ebcb32f..e78417b586a 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/Multiapi/multiapi/v2/aio/_multiapi_service_client.py +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/Multiapi/multiapi/v2/aio/_multiapi_service_client.py @@ -18,7 +18,7 @@ from azure.mgmt.core.tools import get_arm_endpoints from .. import models as _models -from ..._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import MultiapiServiceClientConfiguration from .operations import MultiapiServiceClientOperationsMixin, OperationGroupOneOperations, OperationGroupTwoOperations diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/Multiapi/multiapi/v2/aio/_vendor.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/Multiapi/multiapi/v2/aio/_vendor.py deleted file mode 100644 index 9c6fd05bb21..00000000000 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/Multiapi/multiapi/v2/aio/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) AutoRest Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import MultiapiServiceClientConfiguration - -if TYPE_CHECKING: - from azure.core import AsyncPipelineClient - - from ..._serialization import Deserializer, Serializer - - -class MultiapiServiceClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "AsyncPipelineClient" - _config: MultiapiServiceClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/Multiapi/multiapi/v2/aio/operations/_multiapi_service_client_operations.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/Multiapi/multiapi/v2/aio/operations/_multiapi_service_client_operations.py index f14fed7e5dc..d4cb1c5e4c6 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/Multiapi/multiapi/v2/aio/operations/_multiapi_service_client_operations.py +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/Multiapi/multiapi/v2/aio/operations/_multiapi_service_client_operations.py @@ -9,6 +9,7 @@ from collections.abc import MutableMapping from typing import Any, Callable, Dict, Optional, TypeVar +from azure.core import AsyncPipelineClient from azure.core.exceptions import ( ClientAuthenticationError, HttpResponseError, @@ -24,14 +25,15 @@ from azure.mgmt.core.exceptions import ARMErrorFormat from ... import models as _models +from ..._utils.utils import ClientMixinABC from ...operations._multiapi_service_client_operations import build_test_different_calls_request, build_test_one_request -from .._vendor import MultiapiServiceClientMixinABC +from .._configuration import MultiapiServiceClientConfiguration T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, AsyncHttpResponse], T, Dict[str, Any]], Any]] -class MultiapiServiceClientOperationsMixin(MultiapiServiceClientMixinABC): +class MultiapiServiceClientOperationsMixin(ClientMixinABC[AsyncPipelineClient, MultiapiServiceClientConfiguration]): def _api_version(self, op_name: str) -> str: # pylint: disable=unused-argument try: return self._config.api_version diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/Multiapi/multiapi/v2/aio/operations/_operation_group_one_operations.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/Multiapi/multiapi/v2/aio/operations/_operation_group_one_operations.py index aafe03cbf7f..84c3d3841b7 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/Multiapi/multiapi/v2/aio/operations/_operation_group_one_operations.py +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/Multiapi/multiapi/v2/aio/operations/_operation_group_one_operations.py @@ -25,7 +25,7 @@ from azure.mgmt.core.exceptions import ARMErrorFormat from ... import models as _models -from ...._serialization import Deserializer, Serializer +from ..._utils.serialization import Deserializer, Serializer from ...operations._operation_group_one_operations import build_test_three_request, build_test_two_request from .._configuration import MultiapiServiceClientConfiguration diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/Multiapi/multiapi/v2/aio/operations/_operation_group_two_operations.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/Multiapi/multiapi/v2/aio/operations/_operation_group_two_operations.py index 9ca0f6003ad..179599b9f42 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/Multiapi/multiapi/v2/aio/operations/_operation_group_two_operations.py +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/Multiapi/multiapi/v2/aio/operations/_operation_group_two_operations.py @@ -24,7 +24,7 @@ from azure.mgmt.core.exceptions import ARMErrorFormat from ... import models as _models -from ...._serialization import Deserializer, Serializer +from ..._utils.serialization import Deserializer, Serializer from ...operations._operation_group_two_operations import build_test_four_request from .._configuration import MultiapiServiceClientConfiguration diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/Multiapi/multiapi/v2/models/_models_py3.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/Multiapi/multiapi/v2/models/_models_py3.py index 46990252065..a00726a3da2 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/Multiapi/multiapi/v2/models/_models_py3.py +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/Multiapi/multiapi/v2/models/_models_py3.py @@ -8,7 +8,7 @@ from typing import Any, Optional -from ... import _serialization +from .._utils import serialization as _serialization class Error(_serialization.Model): diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/Multiapi/multiapi/v2/operations/_multiapi_service_client_operations.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/Multiapi/multiapi/v2/operations/_multiapi_service_client_operations.py index 5c9b887ea66..cb90c107eb4 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/Multiapi/multiapi/v2/operations/_multiapi_service_client_operations.py +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/Multiapi/multiapi/v2/operations/_multiapi_service_client_operations.py @@ -8,6 +8,7 @@ from collections.abc import MutableMapping from typing import Any, Callable, Dict, Optional, TypeVar +from azure.core import PipelineClient from azure.core.exceptions import ( ClientAuthenticationError, HttpResponseError, @@ -23,8 +24,9 @@ from azure.mgmt.core.exceptions import ARMErrorFormat from .. import models as _models -from ..._serialization import Serializer -from .._vendor import MultiapiServiceClientMixinABC +from .._configuration import MultiapiServiceClientConfiguration +from .._utils.serialization import Serializer +from .._utils.utils import ClientMixinABC T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] @@ -79,7 +81,7 @@ def build_test_different_calls_request( return HttpRequest(method="GET", url=_url, params=_params, headers=_headers, **kwargs) -class MultiapiServiceClientOperationsMixin(MultiapiServiceClientMixinABC): +class MultiapiServiceClientOperationsMixin(ClientMixinABC[PipelineClient, MultiapiServiceClientConfiguration]): def _api_version(self, op_name: str) -> str: # pylint: disable=unused-argument try: return self._config.api_version diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/Multiapi/multiapi/v2/operations/_operation_group_one_operations.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/Multiapi/multiapi/v2/operations/_operation_group_one_operations.py index 5fde85754df..2415cb93059 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/Multiapi/multiapi/v2/operations/_operation_group_one_operations.py +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/Multiapi/multiapi/v2/operations/_operation_group_one_operations.py @@ -25,8 +25,8 @@ from azure.mgmt.core.exceptions import ARMErrorFormat from .. import models as _models -from ..._serialization import Deserializer, Serializer from .._configuration import MultiapiServiceClientConfiguration +from .._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/Multiapi/multiapi/v2/operations/_operation_group_two_operations.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/Multiapi/multiapi/v2/operations/_operation_group_two_operations.py index 786a055b959..24cc9a85301 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/Multiapi/multiapi/v2/operations/_operation_group_two_operations.py +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/Multiapi/multiapi/v2/operations/_operation_group_two_operations.py @@ -24,8 +24,8 @@ from azure.mgmt.core.exceptions import ARMErrorFormat from .. import models as _models -from ..._serialization import Deserializer, Serializer from .._configuration import MultiapiServiceClientConfiguration +from .._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/Multiapi/multiapi/v3/_metadata.json b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/Multiapi/multiapi/v3/_metadata.json index 6a48def2173..d7e23a53fdf 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/Multiapi/multiapi/v3/_metadata.json +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/Multiapi/multiapi/v3/_metadata.json @@ -10,8 +10,8 @@ "azure_arm": true, "has_public_lro_operations": false, "client_side_validation": false, - "sync_imports": "{\"conditional\": {\"stdlib\": {\"typing\": [\"Any\", \"Optional\"]}}, \"regular\": {\"sdkcore\": {\"azure.mgmt.core\": [\"ARMPipelineClient\"], \"azure.core.pipeline\": [\"policies\"], \"azure.mgmt.core.policies\": [\"ARMAutoResourceProviderRegistrationPolicy\"], \"azure.core.settings\": [\"settings\"], \"azure.mgmt.core.tools\": [\"get_arm_endpoints\"], \"azure.profiles\": [\"KnownProfiles\", \"ProfileDefinition\"], \"azure.profiles.multiapiclient\": [\"MultiApiClientMixin\"]}, \"stdlib\": {\"typing\": [\"Optional\", \"cast\"], \"typing_extensions\": [\"Self\"]}, \"local\": {\"._configuration\": [\"MultiapiServiceClientConfiguration\"], \".._serialization\": [\"Deserializer\", \"Serializer\"], \"._operations_mixin\": [\"MultiapiServiceClientOperationsMixin\"]}}, \"typing\": {\"sdkcore\": {\"azure.core.credentials\": [\"TokenCredential\"]}}}", - "async_imports": "{\"conditional\": {\"stdlib\": {\"typing\": [\"Any\", \"Optional\"]}}, \"regular\": {\"sdkcore\": {\"azure.mgmt.core\": [\"AsyncARMPipelineClient\"], \"azure.core.pipeline\": [\"policies\"], \"azure.mgmt.core.policies\": [\"AsyncARMAutoResourceProviderRegistrationPolicy\"], \"azure.core.settings\": [\"settings\"], \"azure.mgmt.core.tools\": [\"get_arm_endpoints\"], \"azure.profiles\": [\"KnownProfiles\", \"ProfileDefinition\"], \"azure.profiles.multiapiclient\": [\"MultiApiClientMixin\"]}, \"stdlib\": {\"typing\": [\"Optional\", \"cast\"], \"typing_extensions\": [\"Self\"]}, \"local\": {\"._configuration\": [\"MultiapiServiceClientConfiguration\"], \"..._serialization\": [\"Deserializer\", \"Serializer\"], \"._operations_mixin\": [\"MultiapiServiceClientOperationsMixin\"]}}, \"typing\": {\"sdkcore\": {\"azure.core.credentials_async\": [\"AsyncTokenCredential\"]}}}" + "sync_imports": "{\"conditional\": {\"stdlib\": {\"typing\": [\"Any\", \"Optional\"]}}, \"regular\": {\"sdkcore\": {\"azure.mgmt.core\": [\"ARMPipelineClient\"], \"azure.core.pipeline\": [\"policies\"], \"azure.mgmt.core.policies\": [\"ARMAutoResourceProviderRegistrationPolicy\"], \"azure.core.settings\": [\"settings\"], \"azure.mgmt.core.tools\": [\"get_arm_endpoints\"], \"azure.profiles\": [\"KnownProfiles\", \"ProfileDefinition\"], \"azure.profiles.multiapiclient\": [\"MultiApiClientMixin\"]}, \"stdlib\": {\"typing\": [\"Optional\", \"cast\"], \"typing_extensions\": [\"Self\"]}, \"local\": {\"._configuration\": [\"MultiapiServiceClientConfiguration\"], \"._utils.serialization\": [\"Deserializer\", \"Serializer\"], \"._operations_mixin\": [\"MultiapiServiceClientOperationsMixin\"]}}, \"typing\": {\"sdkcore\": {\"azure.core.credentials\": [\"TokenCredential\"]}}}", + "async_imports": "{\"conditional\": {\"stdlib\": {\"typing\": [\"Any\", \"Optional\"]}}, \"regular\": {\"sdkcore\": {\"azure.mgmt.core\": [\"AsyncARMPipelineClient\"], \"azure.core.pipeline\": [\"policies\"], \"azure.mgmt.core.policies\": [\"AsyncARMAutoResourceProviderRegistrationPolicy\"], \"azure.core.settings\": [\"settings\"], \"azure.mgmt.core.tools\": [\"get_arm_endpoints\"], \"azure.profiles\": [\"KnownProfiles\", \"ProfileDefinition\"], \"azure.profiles.multiapiclient\": [\"MultiApiClientMixin\"]}, \"stdlib\": {\"typing\": [\"Optional\", \"cast\"], \"typing_extensions\": [\"Self\"]}, \"local\": {\"._configuration\": [\"MultiapiServiceClientConfiguration\"], \".._utils.serialization\": [\"Deserializer\", \"Serializer\"], \"._operations_mixin\": [\"MultiapiServiceClientOperationsMixin\"]}}, \"typing\": {\"sdkcore\": {\"azure.core.credentials_async\": [\"AsyncTokenCredential\"]}}}" }, "global_parameters": { "sync": { diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/Multiapi/multiapi/v3/_multiapi_service_client.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/Multiapi/multiapi/v3/_multiapi_service_client.py index fcc912b2f9b..74c9d7919cb 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/Multiapi/multiapi/v3/_multiapi_service_client.py +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/Multiapi/multiapi/v3/_multiapi_service_client.py @@ -18,8 +18,8 @@ from azure.mgmt.core.tools import get_arm_endpoints from . import models as _models -from .._serialization import Deserializer, Serializer from ._configuration import MultiapiServiceClientConfiguration +from ._utils.serialization import Deserializer, Serializer from .operations import MultiapiServiceClientOperationsMixin, OperationGroupOneOperations, OperationGroupTwoOperations if TYPE_CHECKING: diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/Multiapi/multiapi/v3/_utils/__init__.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/Multiapi/multiapi/v3/_utils/__init__.py new file mode 100644 index 00000000000..0af9b28f660 --- /dev/null +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/Multiapi/multiapi/v3/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyInteger/bodyinteger/_serialization.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/Multiapi/multiapi/v3/_utils/serialization.py similarity index 100% rename from packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyInteger/bodyinteger/_serialization.py rename to packages/autorest.python/test/multiapi/Expected/AcceptanceTests/Multiapi/multiapi/v3/_utils/serialization.py diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/Multiapi/multiapi/v3/_utils/utils.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/Multiapi/multiapi/v3/_utils/utils.py new file mode 100644 index 00000000000..39b612f39a9 --- /dev/null +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/Multiapi/multiapi/v3/_utils/utils.py @@ -0,0 +1,25 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from abc import ABC +from typing import Generic, TYPE_CHECKING, TypeVar + +if TYPE_CHECKING: + from .serialization import Deserializer, Serializer + + +TClient = TypeVar("TClient") +TConfig = TypeVar("TConfig") + + +class ClientMixinABC(ABC, Generic[TClient, TConfig]): + """DO NOT use this class. It is for internal typing use only.""" + + _client: TClient + _config: TConfig + _serialize: "Serializer" + _deserialize: "Deserializer" diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/Multiapi/multiapi/v3/_vendor.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/Multiapi/multiapi/v3/_vendor.py deleted file mode 100644 index 70517e0b7af..00000000000 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/Multiapi/multiapi/v3/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) AutoRest Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import MultiapiServiceClientConfiguration - -if TYPE_CHECKING: - from azure.core import PipelineClient - - from .._serialization import Deserializer, Serializer - - -class MultiapiServiceClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "PipelineClient" - _config: MultiapiServiceClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/Multiapi/multiapi/v3/aio/_multiapi_service_client.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/Multiapi/multiapi/v3/aio/_multiapi_service_client.py index 91b9a2229c9..4fadb700d4e 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/Multiapi/multiapi/v3/aio/_multiapi_service_client.py +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/Multiapi/multiapi/v3/aio/_multiapi_service_client.py @@ -18,7 +18,7 @@ from azure.mgmt.core.tools import get_arm_endpoints from .. import models as _models -from ..._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import MultiapiServiceClientConfiguration from .operations import MultiapiServiceClientOperationsMixin, OperationGroupOneOperations, OperationGroupTwoOperations diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/Multiapi/multiapi/v3/aio/_vendor.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/Multiapi/multiapi/v3/aio/_vendor.py deleted file mode 100644 index 9c6fd05bb21..00000000000 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/Multiapi/multiapi/v3/aio/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) AutoRest Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import MultiapiServiceClientConfiguration - -if TYPE_CHECKING: - from azure.core import AsyncPipelineClient - - from ..._serialization import Deserializer, Serializer - - -class MultiapiServiceClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "AsyncPipelineClient" - _config: MultiapiServiceClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/Multiapi/multiapi/v3/aio/operations/_multiapi_service_client_operations.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/Multiapi/multiapi/v3/aio/operations/_multiapi_service_client_operations.py index 45f0a6bd216..49b2c2f33d5 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/Multiapi/multiapi/v3/aio/operations/_multiapi_service_client_operations.py +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/Multiapi/multiapi/v3/aio/operations/_multiapi_service_client_operations.py @@ -10,6 +10,7 @@ from typing import Any, AsyncIterable, Callable, Dict, Optional, TypeVar import urllib.parse +from azure.core import AsyncPipelineClient from azure.core.async_paging import AsyncItemPaged, AsyncList from azure.core.exceptions import ( ClientAuthenticationError, @@ -27,17 +28,18 @@ from azure.mgmt.core.exceptions import ARMErrorFormat from ... import models as _models +from ..._utils.utils import ClientMixinABC from ...operations._multiapi_service_client_operations import ( build_test_different_calls_request, build_test_paging_request, ) -from .._vendor import MultiapiServiceClientMixinABC +from .._configuration import MultiapiServiceClientConfiguration T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, AsyncHttpResponse], T, Dict[str, Any]], Any]] -class MultiapiServiceClientOperationsMixin(MultiapiServiceClientMixinABC): +class MultiapiServiceClientOperationsMixin(ClientMixinABC[AsyncPipelineClient, MultiapiServiceClientConfiguration]): def _api_version(self, op_name: str) -> str: # pylint: disable=unused-argument try: return self._config.api_version diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/Multiapi/multiapi/v3/aio/operations/_operation_group_one_operations.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/Multiapi/multiapi/v3/aio/operations/_operation_group_one_operations.py index 1c91c3114d3..5876185e122 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/Multiapi/multiapi/v3/aio/operations/_operation_group_one_operations.py +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/Multiapi/multiapi/v3/aio/operations/_operation_group_one_operations.py @@ -28,7 +28,7 @@ from azure.mgmt.core.exceptions import ARMErrorFormat from ... import models as _models -from ...._serialization import Deserializer, Serializer +from ..._utils.serialization import Deserializer, Serializer from ...operations._operation_group_one_operations import ( build_test_operation_group_paging_request, build_test_two_request, diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/Multiapi/multiapi/v3/aio/operations/_operation_group_two_operations.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/Multiapi/multiapi/v3/aio/operations/_operation_group_two_operations.py index 1594dfe39d7..b107fe873a8 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/Multiapi/multiapi/v3/aio/operations/_operation_group_two_operations.py +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/Multiapi/multiapi/v3/aio/operations/_operation_group_two_operations.py @@ -25,7 +25,7 @@ from azure.mgmt.core.exceptions import ARMErrorFormat from ... import models as _models -from ...._serialization import Deserializer, Serializer +from ..._utils.serialization import Deserializer, Serializer from ...operations._operation_group_two_operations import build_test_five_request, build_test_four_request from .._configuration import MultiapiServiceClientConfiguration diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/Multiapi/multiapi/v3/models/_models_py3.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/Multiapi/multiapi/v3/models/_models_py3.py index 49a4432418f..8b85d248505 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/Multiapi/multiapi/v3/models/_models_py3.py +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/Multiapi/multiapi/v3/models/_models_py3.py @@ -8,7 +8,7 @@ from typing import Any, List, Optional, TYPE_CHECKING -from ... import _serialization +from .._utils import serialization as _serialization if TYPE_CHECKING: from .. import models as _models diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/Multiapi/multiapi/v3/operations/_multiapi_service_client_operations.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/Multiapi/multiapi/v3/operations/_multiapi_service_client_operations.py index b5a1ba0931e..0278a3c7230 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/Multiapi/multiapi/v3/operations/_multiapi_service_client_operations.py +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/Multiapi/multiapi/v3/operations/_multiapi_service_client_operations.py @@ -9,6 +9,7 @@ from typing import Any, Callable, Dict, Iterable, Optional, TypeVar import urllib.parse +from azure.core import PipelineClient from azure.core.exceptions import ( ClientAuthenticationError, HttpResponseError, @@ -25,8 +26,9 @@ from azure.mgmt.core.exceptions import ARMErrorFormat from .. import models as _models -from ..._serialization import Serializer -from .._vendor import MultiapiServiceClientMixinABC +from .._configuration import MultiapiServiceClientConfiguration +from .._utils.serialization import Serializer +from .._utils.utils import ClientMixinABC T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] @@ -79,7 +81,7 @@ def build_test_different_calls_request( return HttpRequest(method="GET", url=_url, params=_params, headers=_headers, **kwargs) -class MultiapiServiceClientOperationsMixin(MultiapiServiceClientMixinABC): +class MultiapiServiceClientOperationsMixin(ClientMixinABC[PipelineClient, MultiapiServiceClientConfiguration]): def _api_version(self, op_name: str) -> str: # pylint: disable=unused-argument try: return self._config.api_version diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/Multiapi/multiapi/v3/operations/_operation_group_one_operations.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/Multiapi/multiapi/v3/operations/_operation_group_one_operations.py index 6321aa45a78..ed7b38ad2d4 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/Multiapi/multiapi/v3/operations/_operation_group_one_operations.py +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/Multiapi/multiapi/v3/operations/_operation_group_one_operations.py @@ -27,8 +27,8 @@ from azure.mgmt.core.exceptions import ARMErrorFormat from .. import models as _models -from ..._serialization import Deserializer, Serializer from .._configuration import MultiapiServiceClientConfiguration +from .._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/Multiapi/multiapi/v3/operations/_operation_group_two_operations.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/Multiapi/multiapi/v3/operations/_operation_group_two_operations.py index 05ecb2e9a10..ec6e0462aca 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/Multiapi/multiapi/v3/operations/_operation_group_two_operations.py +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/Multiapi/multiapi/v3/operations/_operation_group_two_operations.py @@ -25,8 +25,8 @@ from azure.mgmt.core.exceptions import ARMErrorFormat from .. import models as _models -from ..._serialization import Deserializer, Serializer from .._configuration import MultiapiServiceClientConfiguration +from .._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCredentialDefaultPolicy/multiapicredentialdefaultpolicy/_multiapi_service_client.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCredentialDefaultPolicy/multiapicredentialdefaultpolicy/_multiapi_service_client.py index b9defc6b9d1..2d3be48dd20 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCredentialDefaultPolicy/multiapicredentialdefaultpolicy/_multiapi_service_client.py +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCredentialDefaultPolicy/multiapicredentialdefaultpolicy/_multiapi_service_client.py @@ -21,7 +21,7 @@ from ._configuration import MultiapiServiceClientConfiguration from ._operations_mixin import MultiapiServiceClientOperationsMixin -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer class _SDKClient(object): def __init__(self, *args, **kwargs): diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCredentialDefaultPolicy/multiapicredentialdefaultpolicy/_operations_mixin.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCredentialDefaultPolicy/multiapicredentialdefaultpolicy/_operations_mixin.py index 1983c385afc..8cf864d356a 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCredentialDefaultPolicy/multiapicredentialdefaultpolicy/_operations_mixin.py +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCredentialDefaultPolicy/multiapicredentialdefaultpolicy/_operations_mixin.py @@ -8,7 +8,7 @@ # Changes may cause incorrect behavior and will be lost if the code is # regenerated. # -------------------------------------------------------------------------- -from ._serialization import Serializer, Deserializer +from ._utils.serialization import Serializer, Deserializer from io import IOBase from typing import Any, IO, Iterable, Iterator, Optional, Union diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCredentialDefaultPolicy/multiapicredentialdefaultpolicy/_utils/__init__.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCredentialDefaultPolicy/multiapicredentialdefaultpolicy/_utils/__init__.py new file mode 100644 index 00000000000..59333308532 --- /dev/null +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCredentialDefaultPolicy/multiapicredentialdefaultpolicy/_utils/__init__.py @@ -0,0 +1,10 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is +# regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCredentialDefaultPolicy/multiapicredentialdefaultpolicy/_utils/serialization.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCredentialDefaultPolicy/multiapicredentialdefaultpolicy/_utils/serialization.py new file mode 100644 index 00000000000..05bcd7d403a --- /dev/null +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCredentialDefaultPolicy/multiapicredentialdefaultpolicy/_utils/serialization.py @@ -0,0 +1,2025 @@ +# coding=utf-8 + +# pyright: reportUnnecessaryTypeIgnoreComment=false + +from base64 import b64decode, b64encode +import calendar +import datetime +import decimal +import email +from enum import Enum +import json +import logging +import re +import sys +import codecs +from typing import ( + Dict, + Any, + cast, + Optional, + Union, + AnyStr, + IO, + Mapping, + Callable, + MutableMapping, + List, +) + +try: + from urllib import quote # type: ignore +except ImportError: + from urllib.parse import quote +import xml.etree.ElementTree as ET + +import isodate # type: ignore +from typing_extensions import Self + +from azure.core.exceptions import DeserializationError, SerializationError +from azure.core.serialization import NULL as CoreNull + +_BOM = codecs.BOM_UTF8.decode(encoding="utf-8") + +JSON = MutableMapping[str, Any] + + +class RawDeserializer: + + # Accept "text" because we're open minded people... + JSON_REGEXP = re.compile(r"^(application|text)/([a-z+.]+\+)?json$") + + # Name used in context + CONTEXT_NAME = "deserialized_data" + + @classmethod + def deserialize_from_text(cls, data: Optional[Union[AnyStr, IO]], content_type: Optional[str] = None) -> Any: + """Decode data according to content-type. + + Accept a stream of data as well, but will be load at once in memory for now. + + If no content-type, will return the string version (not bytes, not stream) + + :param data: Input, could be bytes or stream (will be decoded with UTF8) or text + :type data: str or bytes or IO + :param str content_type: The content type. + :return: The deserialized data. + :rtype: object + """ + if hasattr(data, "read"): + # Assume a stream + data = cast(IO, data).read() + + if isinstance(data, bytes): + data_as_str = data.decode(encoding="utf-8-sig") + else: + # Explain to mypy the correct type. + data_as_str = cast(str, data) + + # Remove Byte Order Mark if present in string + data_as_str = data_as_str.lstrip(_BOM) + + if content_type is None: + return data + + if cls.JSON_REGEXP.match(content_type): + try: + return json.loads(data_as_str) + except ValueError as err: + raise DeserializationError("JSON is invalid: {}".format(err), err) from err + elif "xml" in (content_type or []): + try: + + try: + if isinstance(data, unicode): # type: ignore + # If I'm Python 2.7 and unicode XML will scream if I try a "fromstring" on unicode string + data_as_str = data_as_str.encode(encoding="utf-8") # type: ignore + except NameError: + pass + + return ET.fromstring(data_as_str) # nosec + except ET.ParseError as err: + # It might be because the server has an issue, and returned JSON with + # content-type XML.... + # So let's try a JSON load, and if it's still broken + # let's flow the initial exception + def _json_attemp(data): + try: + return True, json.loads(data) + except ValueError: + return False, None # Don't care about this one + + success, json_result = _json_attemp(data) + if success: + return json_result + # If i'm here, it's not JSON, it's not XML, let's scream + # and raise the last context in this block (the XML exception) + # The function hack is because Py2.7 messes up with exception + # context otherwise. + _LOGGER.critical("Wasn't XML not JSON, failing") + raise DeserializationError("XML is invalid") from err + elif content_type.startswith("text/"): + return data_as_str + raise DeserializationError("Cannot deserialize content-type: {}".format(content_type)) + + @classmethod + def deserialize_from_http_generics(cls, body_bytes: Optional[Union[AnyStr, IO]], headers: Mapping) -> Any: + """Deserialize from HTTP response. + + Use bytes and headers to NOT use any requests/aiohttp or whatever + specific implementation. + Headers will tested for "content-type" + + :param bytes body_bytes: The body of the response. + :param dict headers: The headers of the response. + :returns: The deserialized data. + :rtype: object + """ + # Try to use content-type from headers if available + content_type = None + if "content-type" in headers: + content_type = headers["content-type"].split(";")[0].strip().lower() + # Ouch, this server did not declare what it sent... + # Let's guess it's JSON... + # Also, since Autorest was considering that an empty body was a valid JSON, + # need that test as well.... + else: + content_type = "application/json" + + if body_bytes: + return cls.deserialize_from_text(body_bytes, content_type) + return None + + +_LOGGER = logging.getLogger(__name__) + +try: + _long_type = long # type: ignore +except NameError: + _long_type = int + +TZ_UTC = datetime.timezone.utc + +_FLATTEN = re.compile(r"(? None: + self.additional_properties: Optional[Dict[str, Any]] = {} + for k in kwargs: # pylint: disable=consider-using-dict-items + if k not in self._attribute_map: + _LOGGER.warning("%s is not a known attribute of class %s and will be ignored", k, self.__class__) + elif k in self._validation and self._validation[k].get("readonly", False): + _LOGGER.warning("Readonly attribute %s will be ignored in class %s", k, self.__class__) + else: + setattr(self, k, kwargs[k]) + + def __eq__(self, other: Any) -> bool: + """Compare objects by comparing all attributes. + + :param object other: The object to compare + :returns: True if objects are equal + :rtype: bool + """ + if isinstance(other, self.__class__): + return self.__dict__ == other.__dict__ + return False + + def __ne__(self, other: Any) -> bool: + """Compare objects by comparing all attributes. + + :param object other: The object to compare + :returns: True if objects are not equal + :rtype: bool + """ + return not self.__eq__(other) + + def __str__(self) -> str: + return str(self.__dict__) + + @classmethod + def enable_additional_properties_sending(cls) -> None: + cls._attribute_map["additional_properties"] = {"key": "", "type": "{object}"} + + @classmethod + def is_xml_model(cls) -> bool: + try: + cls._xml_map # type: ignore + except AttributeError: + return False + return True + + @classmethod + def _create_xml_node(cls): + """Create XML node. + + :returns: The XML node + :rtype: xml.etree.ElementTree.Element + """ + try: + xml_map = cls._xml_map # type: ignore + except AttributeError: + xml_map = {} + + return _create_xml_node(xml_map.get("name", cls.__name__), xml_map.get("prefix", None), xml_map.get("ns", None)) + + def serialize(self, keep_readonly: bool = False, **kwargs: Any) -> JSON: + """Return the JSON that would be sent to server from this model. + + This is an alias to `as_dict(full_restapi_key_transformer, keep_readonly=False)`. + + If you want XML serialization, you can pass the kwargs is_xml=True. + + :param bool keep_readonly: If you want to serialize the readonly attributes + :returns: A dict JSON compatible object + :rtype: dict + """ + serializer = Serializer(self._infer_class_models()) + return serializer._serialize( # type: ignore # pylint: disable=protected-access + self, keep_readonly=keep_readonly, **kwargs + ) + + def as_dict( + self, + keep_readonly: bool = True, + key_transformer: Callable[[str, Dict[str, Any], Any], Any] = attribute_transformer, + **kwargs: Any + ) -> JSON: + """Return a dict that can be serialized using json.dump. + + Advanced usage might optionally use a callback as parameter: + + .. code::python + + def my_key_transformer(key, attr_desc, value): + return key + + Key is the attribute name used in Python. Attr_desc + is a dict of metadata. Currently contains 'type' with the + msrest type and 'key' with the RestAPI encoded key. + Value is the current value in this object. + + The string returned will be used to serialize the key. + If the return type is a list, this is considered hierarchical + result dict. + + See the three examples in this file: + + - attribute_transformer + - full_restapi_key_transformer + - last_restapi_key_transformer + + If you want XML serialization, you can pass the kwargs is_xml=True. + + :param bool keep_readonly: If you want to serialize the readonly attributes + :param function key_transformer: A key transformer function. + :returns: A dict JSON compatible object + :rtype: dict + """ + serializer = Serializer(self._infer_class_models()) + return serializer._serialize( # type: ignore # pylint: disable=protected-access + self, key_transformer=key_transformer, keep_readonly=keep_readonly, **kwargs + ) + + @classmethod + def _infer_class_models(cls): + try: + str_models = cls.__module__.rsplit(".", 1)[0] + models = sys.modules[str_models] + client_models = {k: v for k, v in models.__dict__.items() if isinstance(v, type)} + if cls.__name__ not in client_models: + raise ValueError("Not Autorest generated code") + except Exception: # pylint: disable=broad-exception-caught + # Assume it's not Autorest generated (tests?). Add ourselves as dependencies. + client_models = {cls.__name__: cls} + return client_models + + @classmethod + def deserialize(cls, data: Any, content_type: Optional[str] = None) -> Self: + """Parse a str using the RestAPI syntax and return a model. + + :param str data: A str using RestAPI structure. JSON by default. + :param str content_type: JSON by default, set application/xml if XML. + :returns: An instance of this model + :raises DeserializationError: if something went wrong + :rtype: Self + """ + deserializer = Deserializer(cls._infer_class_models()) + return deserializer(cls.__name__, data, content_type=content_type) # type: ignore + + @classmethod + def from_dict( + cls, + data: Any, + key_extractors: Optional[Callable[[str, Dict[str, Any], Any], Any]] = None, + content_type: Optional[str] = None, + ) -> Self: + """Parse a dict using given key extractor return a model. + + By default consider key + extractors (rest_key_case_insensitive_extractor, attribute_key_case_insensitive_extractor + and last_rest_key_case_insensitive_extractor) + + :param dict data: A dict using RestAPI structure + :param function key_extractors: A key extractor function. + :param str content_type: JSON by default, set application/xml if XML. + :returns: An instance of this model + :raises DeserializationError: if something went wrong + :rtype: Self + """ + deserializer = Deserializer(cls._infer_class_models()) + deserializer.key_extractors = ( # type: ignore + [ # type: ignore + attribute_key_case_insensitive_extractor, + rest_key_case_insensitive_extractor, + last_rest_key_case_insensitive_extractor, + ] + if key_extractors is None + else key_extractors + ) + return deserializer(cls.__name__, data, content_type=content_type) # type: ignore + + @classmethod + def _flatten_subtype(cls, key, objects): + if "_subtype_map" not in cls.__dict__: + return {} + result = dict(cls._subtype_map[key]) + for valuetype in cls._subtype_map[key].values(): + result.update(objects[valuetype]._flatten_subtype(key, objects)) # pylint: disable=protected-access + return result + + @classmethod + def _classify(cls, response, objects): + """Check the class _subtype_map for any child classes. + We want to ignore any inherited _subtype_maps. + + :param dict response: The initial data + :param dict objects: The class objects + :returns: The class to be used + :rtype: class + """ + for subtype_key in cls.__dict__.get("_subtype_map", {}).keys(): + subtype_value = None + + if not isinstance(response, ET.Element): + rest_api_response_key = cls._get_rest_key_parts(subtype_key)[-1] + subtype_value = response.get(rest_api_response_key, None) or response.get(subtype_key, None) + else: + subtype_value = xml_key_extractor(subtype_key, cls._attribute_map[subtype_key], response) + if subtype_value: + # Try to match base class. Can be class name only + # (bug to fix in Autorest to support x-ms-discriminator-name) + if cls.__name__ == subtype_value: + return cls + flatten_mapping_type = cls._flatten_subtype(subtype_key, objects) + try: + return objects[flatten_mapping_type[subtype_value]] # type: ignore + except KeyError: + _LOGGER.warning( + "Subtype value %s has no mapping, use base class %s.", + subtype_value, + cls.__name__, + ) + break + else: + _LOGGER.warning("Discriminator %s is absent or null, use base class %s.", subtype_key, cls.__name__) + break + return cls + + @classmethod + def _get_rest_key_parts(cls, attr_key): + """Get the RestAPI key of this attr, split it and decode part + :param str attr_key: Attribute key must be in attribute_map. + :returns: A list of RestAPI part + :rtype: list + """ + rest_split_key = _FLATTEN.split(cls._attribute_map[attr_key]["key"]) + return [_decode_attribute_map_key(key_part) for key_part in rest_split_key] + + +def _decode_attribute_map_key(key): + """This decode a key in an _attribute_map to the actual key we want to look at + inside the received data. + + :param str key: A key string from the generated code + :returns: The decoded key + :rtype: str + """ + return key.replace("\\.", ".") + + +class Serializer: # pylint: disable=too-many-public-methods + """Request object model serializer.""" + + basic_types = {str: "str", int: "int", bool: "bool", float: "float"} + + _xml_basic_types_serializers = {"bool": lambda x: str(x).lower()} + days = {0: "Mon", 1: "Tue", 2: "Wed", 3: "Thu", 4: "Fri", 5: "Sat", 6: "Sun"} + months = { + 1: "Jan", + 2: "Feb", + 3: "Mar", + 4: "Apr", + 5: "May", + 6: "Jun", + 7: "Jul", + 8: "Aug", + 9: "Sep", + 10: "Oct", + 11: "Nov", + 12: "Dec", + } + validation = { + "min_length": lambda x, y: len(x) < y, + "max_length": lambda x, y: len(x) > y, + "minimum": lambda x, y: x < y, + "maximum": lambda x, y: x > y, + "minimum_ex": lambda x, y: x <= y, + "maximum_ex": lambda x, y: x >= y, + "min_items": lambda x, y: len(x) < y, + "max_items": lambda x, y: len(x) > y, + "pattern": lambda x, y: not re.match(y, x, re.UNICODE), + "unique": lambda x, y: len(x) != len(set(x)), + "multiple": lambda x, y: x % y != 0, + } + + def __init__(self, classes: Optional[Mapping[str, type]] = None) -> None: + self.serialize_type = { + "iso-8601": Serializer.serialize_iso, + "rfc-1123": Serializer.serialize_rfc, + "unix-time": Serializer.serialize_unix, + "duration": Serializer.serialize_duration, + "date": Serializer.serialize_date, + "time": Serializer.serialize_time, + "decimal": Serializer.serialize_decimal, + "long": Serializer.serialize_long, + "bytearray": Serializer.serialize_bytearray, + "base64": Serializer.serialize_base64, + "object": self.serialize_object, + "[]": self.serialize_iter, + "{}": self.serialize_dict, + } + self.dependencies: Dict[str, type] = dict(classes) if classes else {} + self.key_transformer = full_restapi_key_transformer + self.client_side_validation = True + + def _serialize( # pylint: disable=too-many-nested-blocks, too-many-branches, too-many-statements, too-many-locals + self, target_obj, data_type=None, **kwargs + ): + """Serialize data into a string according to type. + + :param object target_obj: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str, dict + :raises SerializationError: if serialization fails. + :returns: The serialized data. + """ + key_transformer = kwargs.get("key_transformer", self.key_transformer) + keep_readonly = kwargs.get("keep_readonly", False) + if target_obj is None: + return None + + attr_name = None + class_name = target_obj.__class__.__name__ + + if data_type: + return self.serialize_data(target_obj, data_type, **kwargs) + + if not hasattr(target_obj, "_attribute_map"): + data_type = type(target_obj).__name__ + if data_type in self.basic_types.values(): + return self.serialize_data(target_obj, data_type, **kwargs) + + # Force "is_xml" kwargs if we detect a XML model + try: + is_xml_model_serialization = kwargs["is_xml"] + except KeyError: + is_xml_model_serialization = kwargs.setdefault("is_xml", target_obj.is_xml_model()) + + serialized = {} + if is_xml_model_serialization: + serialized = target_obj._create_xml_node() # pylint: disable=protected-access + try: + attributes = target_obj._attribute_map # pylint: disable=protected-access + for attr, attr_desc in attributes.items(): + attr_name = attr + if not keep_readonly and target_obj._validation.get( # pylint: disable=protected-access + attr_name, {} + ).get("readonly", False): + continue + + if attr_name == "additional_properties" and attr_desc["key"] == "": + if target_obj.additional_properties is not None: + serialized.update(target_obj.additional_properties) + continue + try: + + orig_attr = getattr(target_obj, attr) + if is_xml_model_serialization: + pass # Don't provide "transformer" for XML for now. Keep "orig_attr" + else: # JSON + keys, orig_attr = key_transformer(attr, attr_desc.copy(), orig_attr) + keys = keys if isinstance(keys, list) else [keys] + + kwargs["serialization_ctxt"] = attr_desc + new_attr = self.serialize_data(orig_attr, attr_desc["type"], **kwargs) + + if is_xml_model_serialization: + xml_desc = attr_desc.get("xml", {}) + xml_name = xml_desc.get("name", attr_desc["key"]) + xml_prefix = xml_desc.get("prefix", None) + xml_ns = xml_desc.get("ns", None) + if xml_desc.get("attr", False): + if xml_ns: + ET.register_namespace(xml_prefix, xml_ns) + xml_name = "{{{}}}{}".format(xml_ns, xml_name) + serialized.set(xml_name, new_attr) # type: ignore + continue + if xml_desc.get("text", False): + serialized.text = new_attr # type: ignore + continue + if isinstance(new_attr, list): + serialized.extend(new_attr) # type: ignore + elif isinstance(new_attr, ET.Element): + # If the down XML has no XML/Name, + # we MUST replace the tag with the local tag. But keeping the namespaces. + if "name" not in getattr(orig_attr, "_xml_map", {}): + splitted_tag = new_attr.tag.split("}") + if len(splitted_tag) == 2: # Namespace + new_attr.tag = "}".join([splitted_tag[0], xml_name]) + else: + new_attr.tag = xml_name + serialized.append(new_attr) # type: ignore + else: # That's a basic type + # Integrate namespace if necessary + local_node = _create_xml_node(xml_name, xml_prefix, xml_ns) + local_node.text = str(new_attr) + serialized.append(local_node) # type: ignore + else: # JSON + for k in reversed(keys): # type: ignore + new_attr = {k: new_attr} + + _new_attr = new_attr + _serialized = serialized + for k in keys: # type: ignore + if k not in _serialized: + _serialized.update(_new_attr) # type: ignore + _new_attr = _new_attr[k] # type: ignore + _serialized = _serialized[k] + except ValueError as err: + if isinstance(err, SerializationError): + raise + + except (AttributeError, KeyError, TypeError) as err: + msg = "Attribute {} in object {} cannot be serialized.\n{}".format(attr_name, class_name, str(target_obj)) + raise SerializationError(msg) from err + return serialized + + def body(self, data, data_type, **kwargs): + """Serialize data intended for a request body. + + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: dict + :raises SerializationError: if serialization fails. + :raises ValueError: if data is None + :returns: The serialized request body + """ + + # Just in case this is a dict + internal_data_type_str = data_type.strip("[]{}") + internal_data_type = self.dependencies.get(internal_data_type_str, None) + try: + is_xml_model_serialization = kwargs["is_xml"] + except KeyError: + if internal_data_type and issubclass(internal_data_type, Model): + is_xml_model_serialization = kwargs.setdefault("is_xml", internal_data_type.is_xml_model()) + else: + is_xml_model_serialization = False + if internal_data_type and not isinstance(internal_data_type, Enum): + try: + deserializer = Deserializer(self.dependencies) + # Since it's on serialization, it's almost sure that format is not JSON REST + # We're not able to deal with additional properties for now. + deserializer.additional_properties_detection = False + if is_xml_model_serialization: + deserializer.key_extractors = [ # type: ignore + attribute_key_case_insensitive_extractor, + ] + else: + deserializer.key_extractors = [ + rest_key_case_insensitive_extractor, + attribute_key_case_insensitive_extractor, + last_rest_key_case_insensitive_extractor, + ] + data = deserializer._deserialize(data_type, data) # pylint: disable=protected-access + except DeserializationError as err: + raise SerializationError("Unable to build a model: " + str(err)) from err + + return self._serialize(data, data_type, **kwargs) + + def url(self, name, data, data_type, **kwargs): + """Serialize data intended for a URL path. + + :param str name: The name of the URL path parameter. + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str + :returns: The serialized URL path + :raises TypeError: if serialization fails. + :raises ValueError: if data is None + """ + try: + output = self.serialize_data(data, data_type, **kwargs) + if data_type == "bool": + output = json.dumps(output) + + if kwargs.get("skip_quote") is True: + output = str(output) + output = output.replace("{", quote("{")).replace("}", quote("}")) + else: + output = quote(str(output), safe="") + except SerializationError as exc: + raise TypeError("{} must be type {}.".format(name, data_type)) from exc + return output + + def query(self, name, data, data_type, **kwargs): + """Serialize data intended for a URL query. + + :param str name: The name of the query parameter. + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str, list + :raises TypeError: if serialization fails. + :raises ValueError: if data is None + :returns: The serialized query parameter + """ + try: + # Treat the list aside, since we don't want to encode the div separator + if data_type.startswith("["): + internal_data_type = data_type[1:-1] + do_quote = not kwargs.get("skip_quote", False) + return self.serialize_iter(data, internal_data_type, do_quote=do_quote, **kwargs) + + # Not a list, regular serialization + output = self.serialize_data(data, data_type, **kwargs) + if data_type == "bool": + output = json.dumps(output) + if kwargs.get("skip_quote") is True: + output = str(output) + else: + output = quote(str(output), safe="") + except SerializationError as exc: + raise TypeError("{} must be type {}.".format(name, data_type)) from exc + return str(output) + + def header(self, name, data, data_type, **kwargs): + """Serialize data intended for a request header. + + :param str name: The name of the header. + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str + :raises TypeError: if serialization fails. + :raises ValueError: if data is None + :returns: The serialized header + """ + try: + if data_type in ["[str]"]: + data = ["" if d is None else d for d in data] + + output = self.serialize_data(data, data_type, **kwargs) + if data_type == "bool": + output = json.dumps(output) + except SerializationError as exc: + raise TypeError("{} must be type {}.".format(name, data_type)) from exc + return str(output) + + def serialize_data(self, data, data_type, **kwargs): + """Serialize generic data according to supplied data type. + + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :raises AttributeError: if required data is None. + :raises ValueError: if data is None + :raises SerializationError: if serialization fails. + :returns: The serialized data. + :rtype: str, int, float, bool, dict, list + """ + if data is None: + raise ValueError("No value for given attribute") + + try: + if data is CoreNull: + return None + if data_type in self.basic_types.values(): + return self.serialize_basic(data, data_type, **kwargs) + + if data_type in self.serialize_type: + return self.serialize_type[data_type](data, **kwargs) + + # If dependencies is empty, try with current data class + # It has to be a subclass of Enum anyway + enum_type = self.dependencies.get(data_type, data.__class__) + if issubclass(enum_type, Enum): + return Serializer.serialize_enum(data, enum_obj=enum_type) + + iter_type = data_type[0] + data_type[-1] + if iter_type in self.serialize_type: + return self.serialize_type[iter_type](data, data_type[1:-1], **kwargs) + + except (ValueError, TypeError) as err: + msg = "Unable to serialize value: {!r} as type: {!r}." + raise SerializationError(msg.format(data, data_type)) from err + return self._serialize(data, **kwargs) + + @classmethod + def _get_custom_serializers(cls, data_type, **kwargs): # pylint: disable=inconsistent-return-statements + custom_serializer = kwargs.get("basic_types_serializers", {}).get(data_type) + if custom_serializer: + return custom_serializer + if kwargs.get("is_xml", False): + return cls._xml_basic_types_serializers.get(data_type) + + @classmethod + def serialize_basic(cls, data, data_type, **kwargs): + """Serialize basic builting data type. + Serializes objects to str, int, float or bool. + + Possible kwargs: + - basic_types_serializers dict[str, callable] : If set, use the callable as serializer + - is_xml bool : If set, use xml_basic_types_serializers + + :param obj data: Object to be serialized. + :param str data_type: Type of object in the iterable. + :rtype: str, int, float, bool + :return: serialized object + """ + custom_serializer = cls._get_custom_serializers(data_type, **kwargs) + if custom_serializer: + return custom_serializer(data) + if data_type == "str": + return cls.serialize_unicode(data) + return eval(data_type)(data) # nosec # pylint: disable=eval-used + + @classmethod + def serialize_unicode(cls, data): + """Special handling for serializing unicode strings in Py2. + Encode to UTF-8 if unicode, otherwise handle as a str. + + :param str data: Object to be serialized. + :rtype: str + :return: serialized object + """ + try: # If I received an enum, return its value + return data.value + except AttributeError: + pass + + try: + if isinstance(data, unicode): # type: ignore + # Don't change it, JSON and XML ElementTree are totally able + # to serialize correctly u'' strings + return data + except NameError: + return str(data) + return str(data) + + def serialize_iter(self, data, iter_type, div=None, **kwargs): + """Serialize iterable. + + Supported kwargs: + - serialization_ctxt dict : The current entry of _attribute_map, or same format. + serialization_ctxt['type'] should be same as data_type. + - is_xml bool : If set, serialize as XML + + :param list data: Object to be serialized. + :param str iter_type: Type of object in the iterable. + :param str div: If set, this str will be used to combine the elements + in the iterable into a combined string. Default is 'None'. + Defaults to False. + :rtype: list, str + :return: serialized iterable + """ + if isinstance(data, str): + raise SerializationError("Refuse str type as a valid iter type.") + + serialization_ctxt = kwargs.get("serialization_ctxt", {}) + is_xml = kwargs.get("is_xml", False) + + serialized = [] + for d in data: + try: + serialized.append(self.serialize_data(d, iter_type, **kwargs)) + except ValueError as err: + if isinstance(err, SerializationError): + raise + serialized.append(None) + + if kwargs.get("do_quote", False): + serialized = ["" if s is None else quote(str(s), safe="") for s in serialized] + + if div: + serialized = ["" if s is None else str(s) for s in serialized] + serialized = div.join(serialized) + + if "xml" in serialization_ctxt or is_xml: + # XML serialization is more complicated + xml_desc = serialization_ctxt.get("xml", {}) + xml_name = xml_desc.get("name") + if not xml_name: + xml_name = serialization_ctxt["key"] + + # Create a wrap node if necessary (use the fact that Element and list have "append") + is_wrapped = xml_desc.get("wrapped", False) + node_name = xml_desc.get("itemsName", xml_name) + if is_wrapped: + final_result = _create_xml_node(xml_name, xml_desc.get("prefix", None), xml_desc.get("ns", None)) + else: + final_result = [] + # All list elements to "local_node" + for el in serialized: + if isinstance(el, ET.Element): + el_node = el + else: + el_node = _create_xml_node(node_name, xml_desc.get("prefix", None), xml_desc.get("ns", None)) + if el is not None: # Otherwise it writes "None" :-p + el_node.text = str(el) + final_result.append(el_node) + return final_result + return serialized + + def serialize_dict(self, attr, dict_type, **kwargs): + """Serialize a dictionary of objects. + + :param dict attr: Object to be serialized. + :param str dict_type: Type of object in the dictionary. + :rtype: dict + :return: serialized dictionary + """ + serialization_ctxt = kwargs.get("serialization_ctxt", {}) + serialized = {} + for key, value in attr.items(): + try: + serialized[self.serialize_unicode(key)] = self.serialize_data(value, dict_type, **kwargs) + except ValueError as err: + if isinstance(err, SerializationError): + raise + serialized[self.serialize_unicode(key)] = None + + if "xml" in serialization_ctxt: + # XML serialization is more complicated + xml_desc = serialization_ctxt["xml"] + xml_name = xml_desc["name"] + + final_result = _create_xml_node(xml_name, xml_desc.get("prefix", None), xml_desc.get("ns", None)) + for key, value in serialized.items(): + ET.SubElement(final_result, key).text = value + return final_result + + return serialized + + def serialize_object(self, attr, **kwargs): # pylint: disable=too-many-return-statements + """Serialize a generic object. + This will be handled as a dictionary. If object passed in is not + a basic type (str, int, float, dict, list) it will simply be + cast to str. + + :param dict attr: Object to be serialized. + :rtype: dict or str + :return: serialized object + """ + if attr is None: + return None + if isinstance(attr, ET.Element): + return attr + obj_type = type(attr) + if obj_type in self.basic_types: + return self.serialize_basic(attr, self.basic_types[obj_type], **kwargs) + if obj_type is _long_type: + return self.serialize_long(attr) + if obj_type is str: + return self.serialize_unicode(attr) + if obj_type is datetime.datetime: + return self.serialize_iso(attr) + if obj_type is datetime.date: + return self.serialize_date(attr) + if obj_type is datetime.time: + return self.serialize_time(attr) + if obj_type is datetime.timedelta: + return self.serialize_duration(attr) + if obj_type is decimal.Decimal: + return self.serialize_decimal(attr) + + # If it's a model or I know this dependency, serialize as a Model + if obj_type in self.dependencies.values() or isinstance(attr, Model): + return self._serialize(attr) + + if obj_type == dict: + serialized = {} + for key, value in attr.items(): + try: + serialized[self.serialize_unicode(key)] = self.serialize_object(value, **kwargs) + except ValueError: + serialized[self.serialize_unicode(key)] = None + return serialized + + if obj_type == list: + serialized = [] + for obj in attr: + try: + serialized.append(self.serialize_object(obj, **kwargs)) + except ValueError: + pass + return serialized + return str(attr) + + @staticmethod + def serialize_enum(attr, enum_obj=None): + try: + result = attr.value + except AttributeError: + result = attr + try: + enum_obj(result) # type: ignore + return result + except ValueError as exc: + for enum_value in enum_obj: # type: ignore + if enum_value.value.lower() == str(attr).lower(): + return enum_value.value + error = "{!r} is not valid value for enum {!r}" + raise SerializationError(error.format(attr, enum_obj)) from exc + + @staticmethod + def serialize_bytearray(attr, **kwargs): # pylint: disable=unused-argument + """Serialize bytearray into base-64 string. + + :param str attr: Object to be serialized. + :rtype: str + :return: serialized base64 + """ + return b64encode(attr).decode() + + @staticmethod + def serialize_base64(attr, **kwargs): # pylint: disable=unused-argument + """Serialize str into base-64 string. + + :param str attr: Object to be serialized. + :rtype: str + :return: serialized base64 + """ + encoded = b64encode(attr).decode("ascii") + return encoded.strip("=").replace("+", "-").replace("/", "_") + + @staticmethod + def serialize_decimal(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Decimal object to float. + + :param decimal attr: Object to be serialized. + :rtype: float + :return: serialized decimal + """ + return float(attr) + + @staticmethod + def serialize_long(attr, **kwargs): # pylint: disable=unused-argument + """Serialize long (Py2) or int (Py3). + + :param int attr: Object to be serialized. + :rtype: int/long + :return: serialized long + """ + return _long_type(attr) + + @staticmethod + def serialize_date(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Date object into ISO-8601 formatted string. + + :param Date attr: Object to be serialized. + :rtype: str + :return: serialized date + """ + if isinstance(attr, str): + attr = isodate.parse_date(attr) + t = "{:04}-{:02}-{:02}".format(attr.year, attr.month, attr.day) + return t + + @staticmethod + def serialize_time(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Time object into ISO-8601 formatted string. + + :param datetime.time attr: Object to be serialized. + :rtype: str + :return: serialized time + """ + if isinstance(attr, str): + attr = isodate.parse_time(attr) + t = "{:02}:{:02}:{:02}".format(attr.hour, attr.minute, attr.second) + if attr.microsecond: + t += ".{:02}".format(attr.microsecond) + return t + + @staticmethod + def serialize_duration(attr, **kwargs): # pylint: disable=unused-argument + """Serialize TimeDelta object into ISO-8601 formatted string. + + :param TimeDelta attr: Object to be serialized. + :rtype: str + :return: serialized duration + """ + if isinstance(attr, str): + attr = isodate.parse_duration(attr) + return isodate.duration_isoformat(attr) + + @staticmethod + def serialize_rfc(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Datetime object into RFC-1123 formatted string. + + :param Datetime attr: Object to be serialized. + :rtype: str + :raises TypeError: if format invalid. + :return: serialized rfc + """ + try: + if not attr.tzinfo: + _LOGGER.warning("Datetime with no tzinfo will be considered UTC.") + utc = attr.utctimetuple() + except AttributeError as exc: + raise TypeError("RFC1123 object must be valid Datetime object.") from exc + + return "{}, {:02} {} {:04} {:02}:{:02}:{:02} GMT".format( + Serializer.days[utc.tm_wday], + utc.tm_mday, + Serializer.months[utc.tm_mon], + utc.tm_year, + utc.tm_hour, + utc.tm_min, + utc.tm_sec, + ) + + @staticmethod + def serialize_iso(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Datetime object into ISO-8601 formatted string. + + :param Datetime attr: Object to be serialized. + :rtype: str + :raises SerializationError: if format invalid. + :return: serialized iso + """ + if isinstance(attr, str): + attr = isodate.parse_datetime(attr) + try: + if not attr.tzinfo: + _LOGGER.warning("Datetime with no tzinfo will be considered UTC.") + utc = attr.utctimetuple() + if utc.tm_year > 9999 or utc.tm_year < 1: + raise OverflowError("Hit max or min date") + + microseconds = str(attr.microsecond).rjust(6, "0").rstrip("0").ljust(3, "0") + if microseconds: + microseconds = "." + microseconds + date = "{:04}-{:02}-{:02}T{:02}:{:02}:{:02}".format( + utc.tm_year, utc.tm_mon, utc.tm_mday, utc.tm_hour, utc.tm_min, utc.tm_sec + ) + return date + microseconds + "Z" + except (ValueError, OverflowError) as err: + msg = "Unable to serialize datetime object." + raise SerializationError(msg) from err + except AttributeError as err: + msg = "ISO-8601 object must be valid Datetime object." + raise TypeError(msg) from err + + @staticmethod + def serialize_unix(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Datetime object into IntTime format. + This is represented as seconds. + + :param Datetime attr: Object to be serialized. + :rtype: int + :raises SerializationError: if format invalid + :return: serialied unix + """ + if isinstance(attr, int): + return attr + try: + if not attr.tzinfo: + _LOGGER.warning("Datetime with no tzinfo will be considered UTC.") + return int(calendar.timegm(attr.utctimetuple())) + except AttributeError as exc: + raise TypeError("Unix time object must be valid Datetime object.") from exc + + +def rest_key_extractor(attr, attr_desc, data): # pylint: disable=unused-argument + key = attr_desc["key"] + working_data = data + + while "." in key: + # Need the cast, as for some reasons "split" is typed as list[str | Any] + dict_keys = cast(List[str], _FLATTEN.split(key)) + if len(dict_keys) == 1: + key = _decode_attribute_map_key(dict_keys[0]) + break + working_key = _decode_attribute_map_key(dict_keys[0]) + working_data = working_data.get(working_key, data) + if working_data is None: + # If at any point while following flatten JSON path see None, it means + # that all properties under are None as well + return None + key = ".".join(dict_keys[1:]) + + return working_data.get(key) + + +def rest_key_case_insensitive_extractor( # pylint: disable=unused-argument, inconsistent-return-statements + attr, attr_desc, data +): + key = attr_desc["key"] + working_data = data + + while "." in key: + dict_keys = _FLATTEN.split(key) + if len(dict_keys) == 1: + key = _decode_attribute_map_key(dict_keys[0]) + break + working_key = _decode_attribute_map_key(dict_keys[0]) + working_data = attribute_key_case_insensitive_extractor(working_key, None, working_data) + if working_data is None: + # If at any point while following flatten JSON path see None, it means + # that all properties under are None as well + return None + key = ".".join(dict_keys[1:]) + + if working_data: + return attribute_key_case_insensitive_extractor(key, None, working_data) + + +def last_rest_key_extractor(attr, attr_desc, data): # pylint: disable=unused-argument + """Extract the attribute in "data" based on the last part of the JSON path key. + + :param str attr: The attribute to extract + :param dict attr_desc: The attribute description + :param dict data: The data to extract from + :rtype: object + :returns: The extracted attribute + """ + key = attr_desc["key"] + dict_keys = _FLATTEN.split(key) + return attribute_key_extractor(dict_keys[-1], None, data) + + +def last_rest_key_case_insensitive_extractor(attr, attr_desc, data): # pylint: disable=unused-argument + """Extract the attribute in "data" based on the last part of the JSON path key. + + This is the case insensitive version of "last_rest_key_extractor" + :param str attr: The attribute to extract + :param dict attr_desc: The attribute description + :param dict data: The data to extract from + :rtype: object + :returns: The extracted attribute + """ + key = attr_desc["key"] + dict_keys = _FLATTEN.split(key) + return attribute_key_case_insensitive_extractor(dict_keys[-1], None, data) + + +def attribute_key_extractor(attr, _, data): + return data.get(attr) + + +def attribute_key_case_insensitive_extractor(attr, _, data): + found_key = None + lower_attr = attr.lower() + for key in data: + if lower_attr == key.lower(): + found_key = key + break + + return data.get(found_key) + + +def _extract_name_from_internal_type(internal_type): + """Given an internal type XML description, extract correct XML name with namespace. + + :param dict internal_type: An model type + :rtype: tuple + :returns: A tuple XML name + namespace dict + """ + internal_type_xml_map = getattr(internal_type, "_xml_map", {}) + xml_name = internal_type_xml_map.get("name", internal_type.__name__) + xml_ns = internal_type_xml_map.get("ns", None) + if xml_ns: + xml_name = "{{{}}}{}".format(xml_ns, xml_name) + return xml_name + + +def xml_key_extractor(attr, attr_desc, data): # pylint: disable=unused-argument,too-many-return-statements + if isinstance(data, dict): + return None + + # Test if this model is XML ready first + if not isinstance(data, ET.Element): + return None + + xml_desc = attr_desc.get("xml", {}) + xml_name = xml_desc.get("name", attr_desc["key"]) + + # Look for a children + is_iter_type = attr_desc["type"].startswith("[") + is_wrapped = xml_desc.get("wrapped", False) + internal_type = attr_desc.get("internalType", None) + internal_type_xml_map = getattr(internal_type, "_xml_map", {}) + + # Integrate namespace if necessary + xml_ns = xml_desc.get("ns", internal_type_xml_map.get("ns", None)) + if xml_ns: + xml_name = "{{{}}}{}".format(xml_ns, xml_name) + + # If it's an attribute, that's simple + if xml_desc.get("attr", False): + return data.get(xml_name) + + # If it's x-ms-text, that's simple too + if xml_desc.get("text", False): + return data.text + + # Scenario where I take the local name: + # - Wrapped node + # - Internal type is an enum (considered basic types) + # - Internal type has no XML/Name node + if is_wrapped or (internal_type and (issubclass(internal_type, Enum) or "name" not in internal_type_xml_map)): + children = data.findall(xml_name) + # If internal type has a local name and it's not a list, I use that name + elif not is_iter_type and internal_type and "name" in internal_type_xml_map: + xml_name = _extract_name_from_internal_type(internal_type) + children = data.findall(xml_name) + # That's an array + else: + if internal_type: # Complex type, ignore itemsName and use the complex type name + items_name = _extract_name_from_internal_type(internal_type) + else: + items_name = xml_desc.get("itemsName", xml_name) + children = data.findall(items_name) + + if len(children) == 0: + if is_iter_type: + if is_wrapped: + return None # is_wrapped no node, we want None + return [] # not wrapped, assume empty list + return None # Assume it's not there, maybe an optional node. + + # If is_iter_type and not wrapped, return all found children + if is_iter_type: + if not is_wrapped: + return children + # Iter and wrapped, should have found one node only (the wrap one) + if len(children) != 1: + raise DeserializationError( + "Tried to deserialize an array not wrapped, and found several nodes '{}'. Maybe you should declare this array as wrapped?".format( + xml_name + ) + ) + return list(children[0]) # Might be empty list and that's ok. + + # Here it's not a itertype, we should have found one element only or empty + if len(children) > 1: + raise DeserializationError("Find several XML '{}' where it was not expected".format(xml_name)) + return children[0] + + +class Deserializer: + """Response object model deserializer. + + :param dict classes: Class type dictionary for deserializing complex types. + :ivar list key_extractors: Ordered list of extractors to be used by this deserializer. + """ + + basic_types = {str: "str", int: "int", bool: "bool", float: "float"} + + valid_date = re.compile(r"\d{4}[-]\d{2}[-]\d{2}T\d{2}:\d{2}:\d{2}\.?\d*Z?[-+]?[\d{2}]?:?[\d{2}]?") + + def __init__(self, classes: Optional[Mapping[str, type]] = None) -> None: + self.deserialize_type = { + "iso-8601": Deserializer.deserialize_iso, + "rfc-1123": Deserializer.deserialize_rfc, + "unix-time": Deserializer.deserialize_unix, + "duration": Deserializer.deserialize_duration, + "date": Deserializer.deserialize_date, + "time": Deserializer.deserialize_time, + "decimal": Deserializer.deserialize_decimal, + "long": Deserializer.deserialize_long, + "bytearray": Deserializer.deserialize_bytearray, + "base64": Deserializer.deserialize_base64, + "object": self.deserialize_object, + "[]": self.deserialize_iter, + "{}": self.deserialize_dict, + } + self.deserialize_expected_types = { + "duration": (isodate.Duration, datetime.timedelta), + "iso-8601": (datetime.datetime), + } + self.dependencies: Dict[str, type] = dict(classes) if classes else {} + self.key_extractors = [rest_key_extractor, xml_key_extractor] + # Additional properties only works if the "rest_key_extractor" is used to + # extract the keys. Making it to work whatever the key extractor is too much + # complicated, with no real scenario for now. + # So adding a flag to disable additional properties detection. This flag should be + # used if your expect the deserialization to NOT come from a JSON REST syntax. + # Otherwise, result are unexpected + self.additional_properties_detection = True + + def __call__(self, target_obj, response_data, content_type=None): + """Call the deserializer to process a REST response. + + :param str target_obj: Target data type to deserialize to. + :param requests.Response response_data: REST response object. + :param str content_type: Swagger "produces" if available. + :raises DeserializationError: if deserialization fails. + :return: Deserialized object. + :rtype: object + """ + data = self._unpack_content(response_data, content_type) + return self._deserialize(target_obj, data) + + def _deserialize(self, target_obj, data): # pylint: disable=inconsistent-return-statements + """Call the deserializer on a model. + + Data needs to be already deserialized as JSON or XML ElementTree + + :param str target_obj: Target data type to deserialize to. + :param object data: Object to deserialize. + :raises DeserializationError: if deserialization fails. + :return: Deserialized object. + :rtype: object + """ + # This is already a model, go recursive just in case + if hasattr(data, "_attribute_map"): + constants = [name for name, config in getattr(data, "_validation", {}).items() if config.get("constant")] + try: + for attr, mapconfig in data._attribute_map.items(): # pylint: disable=protected-access + if attr in constants: + continue + value = getattr(data, attr) + if value is None: + continue + local_type = mapconfig["type"] + internal_data_type = local_type.strip("[]{}") + if internal_data_type not in self.dependencies or isinstance(internal_data_type, Enum): + continue + setattr(data, attr, self._deserialize(local_type, value)) + return data + except AttributeError: + return + + response, class_name = self._classify_target(target_obj, data) + + if isinstance(response, str): + return self.deserialize_data(data, response) + if isinstance(response, type) and issubclass(response, Enum): + return self.deserialize_enum(data, response) + + if data is None or data is CoreNull: + return data + try: + attributes = response._attribute_map # type: ignore # pylint: disable=protected-access + d_attrs = {} + for attr, attr_desc in attributes.items(): + # Check empty string. If it's not empty, someone has a real "additionalProperties"... + if attr == "additional_properties" and attr_desc["key"] == "": + continue + raw_value = None + # Enhance attr_desc with some dynamic data + attr_desc = attr_desc.copy() # Do a copy, do not change the real one + internal_data_type = attr_desc["type"].strip("[]{}") + if internal_data_type in self.dependencies: + attr_desc["internalType"] = self.dependencies[internal_data_type] + + for key_extractor in self.key_extractors: + found_value = key_extractor(attr, attr_desc, data) + if found_value is not None: + if raw_value is not None and raw_value != found_value: + msg = ( + "Ignoring extracted value '%s' from %s for key '%s'" + " (duplicate extraction, follow extractors order)" + ) + _LOGGER.warning(msg, found_value, key_extractor, attr) + continue + raw_value = found_value + + value = self.deserialize_data(raw_value, attr_desc["type"]) + d_attrs[attr] = value + except (AttributeError, TypeError, KeyError) as err: + msg = "Unable to deserialize to object: " + class_name # type: ignore + raise DeserializationError(msg) from err + additional_properties = self._build_additional_properties(attributes, data) + return self._instantiate_model(response, d_attrs, additional_properties) + + def _build_additional_properties(self, attribute_map, data): + if not self.additional_properties_detection: + return None + if "additional_properties" in attribute_map and attribute_map.get("additional_properties", {}).get("key") != "": + # Check empty string. If it's not empty, someone has a real "additionalProperties" + return None + if isinstance(data, ET.Element): + data = {el.tag: el.text for el in data} + + known_keys = { + _decode_attribute_map_key(_FLATTEN.split(desc["key"])[0]) + for desc in attribute_map.values() + if desc["key"] != "" + } + present_keys = set(data.keys()) + missing_keys = present_keys - known_keys + return {key: data[key] for key in missing_keys} + + def _classify_target(self, target, data): + """Check to see whether the deserialization target object can + be classified into a subclass. + Once classification has been determined, initialize object. + + :param str target: The target object type to deserialize to. + :param str/dict data: The response data to deserialize. + :return: The classified target object and its class name. + :rtype: tuple + """ + if target is None: + return None, None + + if isinstance(target, str): + try: + target = self.dependencies[target] + except KeyError: + return target, target + + try: + target = target._classify(data, self.dependencies) # type: ignore # pylint: disable=protected-access + except AttributeError: + pass # Target is not a Model, no classify + return target, target.__class__.__name__ # type: ignore + + def failsafe_deserialize(self, target_obj, data, content_type=None): + """Ignores any errors encountered in deserialization, + and falls back to not deserializing the object. Recommended + for use in error deserialization, as we want to return the + HttpResponseError to users, and not have them deal with + a deserialization error. + + :param str target_obj: The target object type to deserialize to. + :param str/dict data: The response data to deserialize. + :param str content_type: Swagger "produces" if available. + :return: Deserialized object. + :rtype: object + """ + try: + return self(target_obj, data, content_type=content_type) + except: # pylint: disable=bare-except + _LOGGER.debug( + "Ran into a deserialization error. Ignoring since this is failsafe deserialization", exc_info=True + ) + return None + + @staticmethod + def _unpack_content(raw_data, content_type=None): + """Extract the correct structure for deserialization. + + If raw_data is a PipelineResponse, try to extract the result of RawDeserializer. + if we can't, raise. Your Pipeline should have a RawDeserializer. + + If not a pipeline response and raw_data is bytes or string, use content-type + to decode it. If no content-type, try JSON. + + If raw_data is something else, bypass all logic and return it directly. + + :param obj raw_data: Data to be processed. + :param str content_type: How to parse if raw_data is a string/bytes. + :raises JSONDecodeError: If JSON is requested and parsing is impossible. + :raises UnicodeDecodeError: If bytes is not UTF8 + :rtype: object + :return: Unpacked content. + """ + # Assume this is enough to detect a Pipeline Response without importing it + context = getattr(raw_data, "context", {}) + if context: + if RawDeserializer.CONTEXT_NAME in context: + return context[RawDeserializer.CONTEXT_NAME] + raise ValueError("This pipeline didn't have the RawDeserializer policy; can't deserialize") + + # Assume this is enough to recognize universal_http.ClientResponse without importing it + if hasattr(raw_data, "body"): + return RawDeserializer.deserialize_from_http_generics(raw_data.text(), raw_data.headers) + + # Assume this enough to recognize requests.Response without importing it. + if hasattr(raw_data, "_content_consumed"): + return RawDeserializer.deserialize_from_http_generics(raw_data.text, raw_data.headers) + + if isinstance(raw_data, (str, bytes)) or hasattr(raw_data, "read"): + return RawDeserializer.deserialize_from_text(raw_data, content_type) # type: ignore + return raw_data + + def _instantiate_model(self, response, attrs, additional_properties=None): + """Instantiate a response model passing in deserialized args. + + :param Response response: The response model class. + :param dict attrs: The deserialized response attributes. + :param dict additional_properties: Additional properties to be set. + :rtype: Response + :return: The instantiated response model. + """ + if callable(response): + subtype = getattr(response, "_subtype_map", {}) + try: + readonly = [ + k + for k, v in response._validation.items() # pylint: disable=protected-access # type: ignore + if v.get("readonly") + ] + const = [ + k + for k, v in response._validation.items() # pylint: disable=protected-access # type: ignore + if v.get("constant") + ] + kwargs = {k: v for k, v in attrs.items() if k not in subtype and k not in readonly + const} + response_obj = response(**kwargs) + for attr in readonly: + setattr(response_obj, attr, attrs.get(attr)) + if additional_properties: + response_obj.additional_properties = additional_properties # type: ignore + return response_obj + except TypeError as err: + msg = "Unable to deserialize {} into model {}. ".format(kwargs, response) # type: ignore + raise DeserializationError(msg + str(err)) from err + else: + try: + for attr, value in attrs.items(): + setattr(response, attr, value) + return response + except Exception as exp: + msg = "Unable to populate response model. " + msg += "Type: {}, Error: {}".format(type(response), exp) + raise DeserializationError(msg) from exp + + def deserialize_data(self, data, data_type): # pylint: disable=too-many-return-statements + """Process data for deserialization according to data type. + + :param str data: The response string to be deserialized. + :param str data_type: The type to deserialize to. + :raises DeserializationError: if deserialization fails. + :return: Deserialized object. + :rtype: object + """ + if data is None: + return data + + try: + if not data_type: + return data + if data_type in self.basic_types.values(): + return self.deserialize_basic(data, data_type) + if data_type in self.deserialize_type: + if isinstance(data, self.deserialize_expected_types.get(data_type, tuple())): + return data + + is_a_text_parsing_type = lambda x: x not in [ # pylint: disable=unnecessary-lambda-assignment + "object", + "[]", + r"{}", + ] + if isinstance(data, ET.Element) and is_a_text_parsing_type(data_type) and not data.text: + return None + data_val = self.deserialize_type[data_type](data) + return data_val + + iter_type = data_type[0] + data_type[-1] + if iter_type in self.deserialize_type: + return self.deserialize_type[iter_type](data, data_type[1:-1]) + + obj_type = self.dependencies[data_type] + if issubclass(obj_type, Enum): + if isinstance(data, ET.Element): + data = data.text + return self.deserialize_enum(data, obj_type) + + except (ValueError, TypeError, AttributeError) as err: + msg = "Unable to deserialize response data." + msg += " Data: {}, {}".format(data, data_type) + raise DeserializationError(msg) from err + return self._deserialize(obj_type, data) + + def deserialize_iter(self, attr, iter_type): + """Deserialize an iterable. + + :param list attr: Iterable to be deserialized. + :param str iter_type: The type of object in the iterable. + :return: Deserialized iterable. + :rtype: list + """ + if attr is None: + return None + if isinstance(attr, ET.Element): # If I receive an element here, get the children + attr = list(attr) + if not isinstance(attr, (list, set)): + raise DeserializationError("Cannot deserialize as [{}] an object of type {}".format(iter_type, type(attr))) + return [self.deserialize_data(a, iter_type) for a in attr] + + def deserialize_dict(self, attr, dict_type): + """Deserialize a dictionary. + + :param dict/list attr: Dictionary to be deserialized. Also accepts + a list of key, value pairs. + :param str dict_type: The object type of the items in the dictionary. + :return: Deserialized dictionary. + :rtype: dict + """ + if isinstance(attr, list): + return {x["key"]: self.deserialize_data(x["value"], dict_type) for x in attr} + + if isinstance(attr, ET.Element): + # Transform value into {"Key": "value"} + attr = {el.tag: el.text for el in attr} + return {k: self.deserialize_data(v, dict_type) for k, v in attr.items()} + + def deserialize_object(self, attr, **kwargs): # pylint: disable=too-many-return-statements + """Deserialize a generic object. + This will be handled as a dictionary. + + :param dict attr: Dictionary to be deserialized. + :return: Deserialized object. + :rtype: dict + :raises TypeError: if non-builtin datatype encountered. + """ + if attr is None: + return None + if isinstance(attr, ET.Element): + # Do no recurse on XML, just return the tree as-is + return attr + if isinstance(attr, str): + return self.deserialize_basic(attr, "str") + obj_type = type(attr) + if obj_type in self.basic_types: + return self.deserialize_basic(attr, self.basic_types[obj_type]) + if obj_type is _long_type: + return self.deserialize_long(attr) + + if obj_type == dict: + deserialized = {} + for key, value in attr.items(): + try: + deserialized[key] = self.deserialize_object(value, **kwargs) + except ValueError: + deserialized[key] = None + return deserialized + + if obj_type == list: + deserialized = [] + for obj in attr: + try: + deserialized.append(self.deserialize_object(obj, **kwargs)) + except ValueError: + pass + return deserialized + + error = "Cannot deserialize generic object with type: " + raise TypeError(error + str(obj_type)) + + def deserialize_basic(self, attr, data_type): # pylint: disable=too-many-return-statements + """Deserialize basic builtin data type from string. + Will attempt to convert to str, int, float and bool. + This function will also accept '1', '0', 'true' and 'false' as + valid bool values. + + :param str attr: response string to be deserialized. + :param str data_type: deserialization data type. + :return: Deserialized basic type. + :rtype: str, int, float or bool + :raises TypeError: if string format is not valid. + """ + # If we're here, data is supposed to be a basic type. + # If it's still an XML node, take the text + if isinstance(attr, ET.Element): + attr = attr.text + if not attr: + if data_type == "str": + # None or '', node is empty string. + return "" + # None or '', node with a strong type is None. + # Don't try to model "empty bool" or "empty int" + return None + + if data_type == "bool": + if attr in [True, False, 1, 0]: + return bool(attr) + if isinstance(attr, str): + if attr.lower() in ["true", "1"]: + return True + if attr.lower() in ["false", "0"]: + return False + raise TypeError("Invalid boolean value: {}".format(attr)) + + if data_type == "str": + return self.deserialize_unicode(attr) + return eval(data_type)(attr) # nosec # pylint: disable=eval-used + + @staticmethod + def deserialize_unicode(data): + """Preserve unicode objects in Python 2, otherwise return data + as a string. + + :param str data: response string to be deserialized. + :return: Deserialized string. + :rtype: str or unicode + """ + # We might be here because we have an enum modeled as string, + # and we try to deserialize a partial dict with enum inside + if isinstance(data, Enum): + return data + + # Consider this is real string + try: + if isinstance(data, unicode): # type: ignore + return data + except NameError: + return str(data) + return str(data) + + @staticmethod + def deserialize_enum(data, enum_obj): + """Deserialize string into enum object. + + If the string is not a valid enum value it will be returned as-is + and a warning will be logged. + + :param str data: Response string to be deserialized. If this value is + None or invalid it will be returned as-is. + :param Enum enum_obj: Enum object to deserialize to. + :return: Deserialized enum object. + :rtype: Enum + """ + if isinstance(data, enum_obj) or data is None: + return data + if isinstance(data, Enum): + data = data.value + if isinstance(data, int): + # Workaround. We might consider remove it in the future. + try: + return list(enum_obj.__members__.values())[data] + except IndexError as exc: + error = "{!r} is not a valid index for enum {!r}" + raise DeserializationError(error.format(data, enum_obj)) from exc + try: + return enum_obj(str(data)) + except ValueError: + for enum_value in enum_obj: + if enum_value.value.lower() == str(data).lower(): + return enum_value + # We don't fail anymore for unknown value, we deserialize as a string + _LOGGER.warning("Deserializer is not able to find %s as valid enum in %s", data, enum_obj) + return Deserializer.deserialize_unicode(data) + + @staticmethod + def deserialize_bytearray(attr): + """Deserialize string into bytearray. + + :param str attr: response string to be deserialized. + :return: Deserialized bytearray + :rtype: bytearray + :raises TypeError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + return bytearray(b64decode(attr)) # type: ignore + + @staticmethod + def deserialize_base64(attr): + """Deserialize base64 encoded string into string. + + :param str attr: response string to be deserialized. + :return: Deserialized base64 string + :rtype: bytearray + :raises TypeError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + padding = "=" * (3 - (len(attr) + 3) % 4) # type: ignore + attr = attr + padding # type: ignore + encoded = attr.replace("-", "+").replace("_", "/") + return b64decode(encoded) + + @staticmethod + def deserialize_decimal(attr): + """Deserialize string into Decimal object. + + :param str attr: response string to be deserialized. + :return: Deserialized decimal + :raises DeserializationError: if string format invalid. + :rtype: decimal + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + return decimal.Decimal(str(attr)) # type: ignore + except decimal.DecimalException as err: + msg = "Invalid decimal {}".format(attr) + raise DeserializationError(msg) from err + + @staticmethod + def deserialize_long(attr): + """Deserialize string into long (Py2) or int (Py3). + + :param str attr: response string to be deserialized. + :return: Deserialized int + :rtype: long or int + :raises ValueError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + return _long_type(attr) # type: ignore + + @staticmethod + def deserialize_duration(attr): + """Deserialize ISO-8601 formatted string into TimeDelta object. + + :param str attr: response string to be deserialized. + :return: Deserialized duration + :rtype: TimeDelta + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + duration = isodate.parse_duration(attr) + except (ValueError, OverflowError, AttributeError) as err: + msg = "Cannot deserialize duration object." + raise DeserializationError(msg) from err + return duration + + @staticmethod + def deserialize_date(attr): + """Deserialize ISO-8601 formatted string into Date object. + + :param str attr: response string to be deserialized. + :return: Deserialized date + :rtype: Date + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + if re.search(r"[^\W\d_]", attr, re.I + re.U): # type: ignore + raise DeserializationError("Date must have only digits and -. Received: %s" % attr) + # This must NOT use defaultmonth/defaultday. Using None ensure this raises an exception. + return isodate.parse_date(attr, defaultmonth=0, defaultday=0) + + @staticmethod + def deserialize_time(attr): + """Deserialize ISO-8601 formatted string into time object. + + :param str attr: response string to be deserialized. + :return: Deserialized time + :rtype: datetime.time + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + if re.search(r"[^\W\d_]", attr, re.I + re.U): # type: ignore + raise DeserializationError("Date must have only digits and -. Received: %s" % attr) + return isodate.parse_time(attr) + + @staticmethod + def deserialize_rfc(attr): + """Deserialize RFC-1123 formatted string into Datetime object. + + :param str attr: response string to be deserialized. + :return: Deserialized RFC datetime + :rtype: Datetime + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + parsed_date = email.utils.parsedate_tz(attr) # type: ignore + date_obj = datetime.datetime( + *parsed_date[:6], tzinfo=datetime.timezone(datetime.timedelta(minutes=(parsed_date[9] or 0) / 60)) + ) + if not date_obj.tzinfo: + date_obj = date_obj.astimezone(tz=TZ_UTC) + except ValueError as err: + msg = "Cannot deserialize to rfc datetime object." + raise DeserializationError(msg) from err + return date_obj + + @staticmethod + def deserialize_iso(attr): + """Deserialize ISO-8601 formatted string into Datetime object. + + :param str attr: response string to be deserialized. + :return: Deserialized ISO datetime + :rtype: Datetime + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + attr = attr.upper() # type: ignore + match = Deserializer.valid_date.match(attr) + if not match: + raise ValueError("Invalid datetime string: " + attr) + + check_decimal = attr.split(".") + if len(check_decimal) > 1: + decimal_str = "" + for digit in check_decimal[1]: + if digit.isdigit(): + decimal_str += digit + else: + break + if len(decimal_str) > 6: + attr = attr.replace(decimal_str, decimal_str[0:6]) + + date_obj = isodate.parse_datetime(attr) + test_utc = date_obj.utctimetuple() + if test_utc.tm_year > 9999 or test_utc.tm_year < 1: + raise OverflowError("Hit max or min date") + except (ValueError, OverflowError, AttributeError) as err: + msg = "Cannot deserialize datetime object." + raise DeserializationError(msg) from err + return date_obj + + @staticmethod + def deserialize_unix(attr): + """Serialize Datetime object into IntTime format. + This is represented as seconds. + + :param int attr: Object to be serialized. + :return: Deserialized datetime + :rtype: Datetime + :raises DeserializationError: if format invalid + """ + if isinstance(attr, ET.Element): + attr = int(attr.text) # type: ignore + try: + attr = int(attr) + date_obj = datetime.datetime.fromtimestamp(attr, TZ_UTC) + except ValueError as err: + msg = "Cannot deserialize to unix datetime object." + raise DeserializationError(msg) from err + return date_obj diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCredentialDefaultPolicy/multiapicredentialdefaultpolicy/aio/_multiapi_service_client.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCredentialDefaultPolicy/multiapicredentialdefaultpolicy/aio/_multiapi_service_client.py index be89cf52aa4..8b3d6d5cac4 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCredentialDefaultPolicy/multiapicredentialdefaultpolicy/aio/_multiapi_service_client.py +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCredentialDefaultPolicy/multiapicredentialdefaultpolicy/aio/_multiapi_service_client.py @@ -19,7 +19,7 @@ from azure.profiles import KnownProfiles, ProfileDefinition from azure.profiles.multiapiclient import MultiApiClientMixin -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import MultiapiServiceClientConfiguration from ._operations_mixin import MultiapiServiceClientOperationsMixin diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCredentialDefaultPolicy/multiapicredentialdefaultpolicy/aio/_operations_mixin.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCredentialDefaultPolicy/multiapicredentialdefaultpolicy/aio/_operations_mixin.py index 07be08cf8ae..a7b1292d534 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCredentialDefaultPolicy/multiapicredentialdefaultpolicy/aio/_operations_mixin.py +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCredentialDefaultPolicy/multiapicredentialdefaultpolicy/aio/_operations_mixin.py @@ -8,7 +8,7 @@ # Changes may cause incorrect behavior and will be lost if the code is # regenerated. # -------------------------------------------------------------------------- -from .._serialization import Serializer, Deserializer +from .._utils.serialization import Serializer, Deserializer from io import IOBase from typing import Any, AsyncIterable, AsyncIterator, IO, Optional, Union diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCredentialDefaultPolicy/multiapicredentialdefaultpolicy/v1/_metadata.json b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCredentialDefaultPolicy/multiapicredentialdefaultpolicy/v1/_metadata.json index d8820f5f99e..568d2b808cf 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCredentialDefaultPolicy/multiapicredentialdefaultpolicy/v1/_metadata.json +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCredentialDefaultPolicy/multiapicredentialdefaultpolicy/v1/_metadata.json @@ -10,8 +10,8 @@ "azure_arm": true, "has_public_lro_operations": true, "client_side_validation": false, - "sync_imports": "{\"conditional\": {\"stdlib\": {\"typing\": [\"Any\", \"Optional\"]}, \"sdkcore\": {\"azure.core.credentials\": [\"AzureKeyCredential\"]}}, \"regular\": {\"sdkcore\": {\"azure.mgmt.core\": [\"ARMPipelineClient\"], \"azure.core.pipeline\": [\"policies\"], \"azure.mgmt.core.policies\": [\"ARMAutoResourceProviderRegistrationPolicy\"], \"azure.profiles\": [\"KnownProfiles\", \"ProfileDefinition\"], \"azure.profiles.multiapiclient\": [\"MultiApiClientMixin\"]}, \"local\": {\"._configuration\": [\"MultiapiServiceClientConfiguration\"], \".._serialization\": [\"Deserializer\", \"Serializer\"], \"._operations_mixin\": [\"MultiapiServiceClientOperationsMixin\"]}, \"stdlib\": {\"typing_extensions\": [\"Self\"]}}}", - "async_imports": "{\"conditional\": {\"stdlib\": {\"typing\": [\"Any\", \"Optional\"]}, \"sdkcore\": {\"azure.core.credentials\": [\"AzureKeyCredential\"]}}, \"regular\": {\"sdkcore\": {\"azure.mgmt.core\": [\"AsyncARMPipelineClient\"], \"azure.core.pipeline\": [\"policies\"], \"azure.mgmt.core.policies\": [\"AsyncARMAutoResourceProviderRegistrationPolicy\"], \"azure.profiles\": [\"KnownProfiles\", \"ProfileDefinition\"], \"azure.profiles.multiapiclient\": [\"MultiApiClientMixin\"]}, \"local\": {\"._configuration\": [\"MultiapiServiceClientConfiguration\"], \"..._serialization\": [\"Deserializer\", \"Serializer\"], \"._operations_mixin\": [\"MultiapiServiceClientOperationsMixin\"]}, \"stdlib\": {\"typing_extensions\": [\"Self\"]}}}" + "sync_imports": "{\"conditional\": {\"stdlib\": {\"typing\": [\"Any\", \"Optional\"]}, \"sdkcore\": {\"azure.core.credentials\": [\"AzureKeyCredential\"]}}, \"regular\": {\"sdkcore\": {\"azure.mgmt.core\": [\"ARMPipelineClient\"], \"azure.core.pipeline\": [\"policies\"], \"azure.mgmt.core.policies\": [\"ARMAutoResourceProviderRegistrationPolicy\"], \"azure.profiles\": [\"KnownProfiles\", \"ProfileDefinition\"], \"azure.profiles.multiapiclient\": [\"MultiApiClientMixin\"]}, \"local\": {\"._configuration\": [\"MultiapiServiceClientConfiguration\"], \"._utils.serialization\": [\"Deserializer\", \"Serializer\"], \"._operations_mixin\": [\"MultiapiServiceClientOperationsMixin\"]}, \"stdlib\": {\"typing_extensions\": [\"Self\"]}}}", + "async_imports": "{\"conditional\": {\"stdlib\": {\"typing\": [\"Any\", \"Optional\"]}, \"sdkcore\": {\"azure.core.credentials\": [\"AzureKeyCredential\"]}}, \"regular\": {\"sdkcore\": {\"azure.mgmt.core\": [\"AsyncARMPipelineClient\"], \"azure.core.pipeline\": [\"policies\"], \"azure.mgmt.core.policies\": [\"AsyncARMAutoResourceProviderRegistrationPolicy\"], \"azure.profiles\": [\"KnownProfiles\", \"ProfileDefinition\"], \"azure.profiles.multiapiclient\": [\"MultiApiClientMixin\"]}, \"local\": {\"._configuration\": [\"MultiapiServiceClientConfiguration\"], \".._utils.serialization\": [\"Deserializer\", \"Serializer\"], \"._operations_mixin\": [\"MultiapiServiceClientOperationsMixin\"]}, \"stdlib\": {\"typing_extensions\": [\"Self\"]}}}" }, "global_parameters": { "sync": { diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCredentialDefaultPolicy/multiapicredentialdefaultpolicy/v1/_multiapi_service_client.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCredentialDefaultPolicy/multiapicredentialdefaultpolicy/v1/_multiapi_service_client.py index 6217d1d023e..24fa3d3ee6f 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCredentialDefaultPolicy/multiapicredentialdefaultpolicy/v1/_multiapi_service_client.py +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCredentialDefaultPolicy/multiapicredentialdefaultpolicy/v1/_multiapi_service_client.py @@ -17,8 +17,8 @@ from azure.mgmt.core.policies import ARMAutoResourceProviderRegistrationPolicy from . import models as _models -from .._serialization import Deserializer, Serializer from ._configuration import MultiapiServiceClientConfiguration +from ._utils.serialization import Deserializer, Serializer from .operations import MultiapiServiceClientOperationsMixin, OperationGroupOneOperations diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCredentialDefaultPolicy/multiapicredentialdefaultpolicy/v1/_utils/__init__.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCredentialDefaultPolicy/multiapicredentialdefaultpolicy/v1/_utils/__init__.py new file mode 100644 index 00000000000..0af9b28f660 --- /dev/null +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCredentialDefaultPolicy/multiapicredentialdefaultpolicy/v1/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyNumber/bodynumber/_serialization.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCredentialDefaultPolicy/multiapicredentialdefaultpolicy/v1/_utils/serialization.py similarity index 100% rename from packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyNumber/bodynumber/_serialization.py rename to packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCredentialDefaultPolicy/multiapicredentialdefaultpolicy/v1/_utils/serialization.py diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCredentialDefaultPolicy/multiapicredentialdefaultpolicy/v1/_utils/utils.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCredentialDefaultPolicy/multiapicredentialdefaultpolicy/v1/_utils/utils.py new file mode 100644 index 00000000000..39b612f39a9 --- /dev/null +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCredentialDefaultPolicy/multiapicredentialdefaultpolicy/v1/_utils/utils.py @@ -0,0 +1,25 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from abc import ABC +from typing import Generic, TYPE_CHECKING, TypeVar + +if TYPE_CHECKING: + from .serialization import Deserializer, Serializer + + +TClient = TypeVar("TClient") +TConfig = TypeVar("TConfig") + + +class ClientMixinABC(ABC, Generic[TClient, TConfig]): + """DO NOT use this class. It is for internal typing use only.""" + + _client: TClient + _config: TConfig + _serialize: "Serializer" + _deserialize: "Deserializer" diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCredentialDefaultPolicy/multiapicredentialdefaultpolicy/v1/_vendor.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCredentialDefaultPolicy/multiapicredentialdefaultpolicy/v1/_vendor.py deleted file mode 100644 index 70517e0b7af..00000000000 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCredentialDefaultPolicy/multiapicredentialdefaultpolicy/v1/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) AutoRest Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import MultiapiServiceClientConfiguration - -if TYPE_CHECKING: - from azure.core import PipelineClient - - from .._serialization import Deserializer, Serializer - - -class MultiapiServiceClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "PipelineClient" - _config: MultiapiServiceClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCredentialDefaultPolicy/multiapicredentialdefaultpolicy/v1/aio/_multiapi_service_client.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCredentialDefaultPolicy/multiapicredentialdefaultpolicy/v1/aio/_multiapi_service_client.py index 27f3b1fc132..1ba42d45534 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCredentialDefaultPolicy/multiapicredentialdefaultpolicy/v1/aio/_multiapi_service_client.py +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCredentialDefaultPolicy/multiapicredentialdefaultpolicy/v1/aio/_multiapi_service_client.py @@ -17,7 +17,7 @@ from azure.mgmt.core.policies import AsyncARMAutoResourceProviderRegistrationPolicy from .. import models as _models -from ..._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import MultiapiServiceClientConfiguration from .operations import MultiapiServiceClientOperationsMixin, OperationGroupOneOperations diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCredentialDefaultPolicy/multiapicredentialdefaultpolicy/v1/aio/_vendor.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCredentialDefaultPolicy/multiapicredentialdefaultpolicy/v1/aio/_vendor.py deleted file mode 100644 index 9c6fd05bb21..00000000000 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCredentialDefaultPolicy/multiapicredentialdefaultpolicy/v1/aio/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) AutoRest Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import MultiapiServiceClientConfiguration - -if TYPE_CHECKING: - from azure.core import AsyncPipelineClient - - from ..._serialization import Deserializer, Serializer - - -class MultiapiServiceClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "AsyncPipelineClient" - _config: MultiapiServiceClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCredentialDefaultPolicy/multiapicredentialdefaultpolicy/v1/aio/operations/_multiapi_service_client_operations.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCredentialDefaultPolicy/multiapicredentialdefaultpolicy/v1/aio/operations/_multiapi_service_client_operations.py index 1c08f67ea89..b8277867d34 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCredentialDefaultPolicy/multiapicredentialdefaultpolicy/v1/aio/operations/_multiapi_service_client_operations.py +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCredentialDefaultPolicy/multiapicredentialdefaultpolicy/v1/aio/operations/_multiapi_service_client_operations.py @@ -11,6 +11,7 @@ from typing import Any, AsyncIterable, AsyncIterator, Callable, Dict, IO, Optional, TypeVar, Union, cast, overload import urllib.parse +from azure.core import AsyncPipelineClient from azure.core.async_paging import AsyncItemPaged, AsyncList from azure.core.exceptions import ( ClientAuthenticationError, @@ -32,19 +33,20 @@ from azure.mgmt.core.polling.async_arm_polling import AsyncARMPolling from ... import models as _models +from ..._utils.utils import ClientMixinABC from ...operations._multiapi_service_client_operations import ( build_test_different_calls_request, build_test_lro_and_paging_request, build_test_lro_request, build_test_one_request, ) -from .._vendor import MultiapiServiceClientMixinABC +from .._configuration import MultiapiServiceClientConfiguration T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, AsyncHttpResponse], T, Dict[str, Any]], Any]] -class MultiapiServiceClientOperationsMixin(MultiapiServiceClientMixinABC): +class MultiapiServiceClientOperationsMixin(ClientMixinABC[AsyncPipelineClient, MultiapiServiceClientConfiguration]): def _api_version(self, op_name: str) -> str: # pylint: disable=unused-argument try: return self._config.api_version diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCredentialDefaultPolicy/multiapicredentialdefaultpolicy/v1/aio/operations/_operation_group_one_operations.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCredentialDefaultPolicy/multiapicredentialdefaultpolicy/v1/aio/operations/_operation_group_one_operations.py index 982115f7983..d02864e2d8e 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCredentialDefaultPolicy/multiapicredentialdefaultpolicy/v1/aio/operations/_operation_group_one_operations.py +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCredentialDefaultPolicy/multiapicredentialdefaultpolicy/v1/aio/operations/_operation_group_one_operations.py @@ -24,7 +24,7 @@ from azure.mgmt.core.exceptions import ARMErrorFormat from ... import models as _models -from ...._serialization import Deserializer, Serializer +from ..._utils.serialization import Deserializer, Serializer from ...operations._operation_group_one_operations import build_test_two_request from .._configuration import MultiapiServiceClientConfiguration diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCredentialDefaultPolicy/multiapicredentialdefaultpolicy/v1/models/_models_py3.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCredentialDefaultPolicy/multiapicredentialdefaultpolicy/v1/models/_models_py3.py index 93d38043e62..95e9ce2e471 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCredentialDefaultPolicy/multiapicredentialdefaultpolicy/v1/models/_models_py3.py +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCredentialDefaultPolicy/multiapicredentialdefaultpolicy/v1/models/_models_py3.py @@ -8,7 +8,7 @@ from typing import Any, List, Optional, TYPE_CHECKING -from ... import _serialization +from .._utils import serialization as _serialization if TYPE_CHECKING: from .. import models as _models diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCredentialDefaultPolicy/multiapicredentialdefaultpolicy/v1/operations/_multiapi_service_client_operations.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCredentialDefaultPolicy/multiapicredentialdefaultpolicy/v1/operations/_multiapi_service_client_operations.py index 4fb83684a3f..ba30759261a 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCredentialDefaultPolicy/multiapicredentialdefaultpolicy/v1/operations/_multiapi_service_client_operations.py +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCredentialDefaultPolicy/multiapicredentialdefaultpolicy/v1/operations/_multiapi_service_client_operations.py @@ -10,6 +10,7 @@ from typing import Any, Callable, Dict, IO, Iterable, Iterator, Optional, TypeVar, Union, cast, overload import urllib.parse +from azure.core import PipelineClient from azure.core.exceptions import ( ClientAuthenticationError, HttpResponseError, @@ -30,8 +31,9 @@ from azure.mgmt.core.polling.arm_polling import ARMPolling from .. import models as _models -from ..._serialization import Serializer -from .._vendor import MultiapiServiceClientMixinABC +from .._configuration import MultiapiServiceClientConfiguration +from .._utils.serialization import Serializer +from .._utils.utils import ClientMixinABC T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] @@ -121,7 +123,7 @@ def build_test_different_calls_request(*, greeting_in_english: str, **kwargs: An return HttpRequest(method="GET", url=_url, params=_params, headers=_headers, **kwargs) -class MultiapiServiceClientOperationsMixin(MultiapiServiceClientMixinABC): +class MultiapiServiceClientOperationsMixin(ClientMixinABC[PipelineClient, MultiapiServiceClientConfiguration]): def _api_version(self, op_name: str) -> str: # pylint: disable=unused-argument try: return self._config.api_version diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCredentialDefaultPolicy/multiapicredentialdefaultpolicy/v1/operations/_operation_group_one_operations.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCredentialDefaultPolicy/multiapicredentialdefaultpolicy/v1/operations/_operation_group_one_operations.py index 3899241d69a..bbeee8aa51b 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCredentialDefaultPolicy/multiapicredentialdefaultpolicy/v1/operations/_operation_group_one_operations.py +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCredentialDefaultPolicy/multiapicredentialdefaultpolicy/v1/operations/_operation_group_one_operations.py @@ -24,8 +24,8 @@ from azure.mgmt.core.exceptions import ARMErrorFormat from .. import models as _models -from ..._serialization import Deserializer, Serializer from .._configuration import MultiapiServiceClientConfiguration +from .._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCredentialDefaultPolicy/multiapicredentialdefaultpolicy/v2/_metadata.json b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCredentialDefaultPolicy/multiapicredentialdefaultpolicy/v2/_metadata.json index b4a9129536b..6dc8a1c3fe6 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCredentialDefaultPolicy/multiapicredentialdefaultpolicy/v2/_metadata.json +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCredentialDefaultPolicy/multiapicredentialdefaultpolicy/v2/_metadata.json @@ -10,8 +10,8 @@ "azure_arm": true, "has_public_lro_operations": false, "client_side_validation": false, - "sync_imports": "{\"conditional\": {\"stdlib\": {\"typing\": [\"Any\", \"Optional\"]}, \"sdkcore\": {\"azure.core.credentials\": [\"AzureKeyCredential\"]}}, \"regular\": {\"sdkcore\": {\"azure.mgmt.core\": [\"ARMPipelineClient\"], \"azure.core.pipeline\": [\"policies\"], \"azure.mgmt.core.policies\": [\"ARMAutoResourceProviderRegistrationPolicy\"], \"azure.profiles\": [\"KnownProfiles\", \"ProfileDefinition\"], \"azure.profiles.multiapiclient\": [\"MultiApiClientMixin\"]}, \"local\": {\"._configuration\": [\"MultiapiServiceClientConfiguration\"], \".._serialization\": [\"Deserializer\", \"Serializer\"], \"._operations_mixin\": [\"MultiapiServiceClientOperationsMixin\"]}, \"stdlib\": {\"typing_extensions\": [\"Self\"]}}}", - "async_imports": "{\"conditional\": {\"stdlib\": {\"typing\": [\"Any\", \"Optional\"]}, \"sdkcore\": {\"azure.core.credentials\": [\"AzureKeyCredential\"]}}, \"regular\": {\"sdkcore\": {\"azure.mgmt.core\": [\"AsyncARMPipelineClient\"], \"azure.core.pipeline\": [\"policies\"], \"azure.mgmt.core.policies\": [\"AsyncARMAutoResourceProviderRegistrationPolicy\"], \"azure.profiles\": [\"KnownProfiles\", \"ProfileDefinition\"], \"azure.profiles.multiapiclient\": [\"MultiApiClientMixin\"]}, \"local\": {\"._configuration\": [\"MultiapiServiceClientConfiguration\"], \"..._serialization\": [\"Deserializer\", \"Serializer\"], \"._operations_mixin\": [\"MultiapiServiceClientOperationsMixin\"]}, \"stdlib\": {\"typing_extensions\": [\"Self\"]}}}" + "sync_imports": "{\"conditional\": {\"stdlib\": {\"typing\": [\"Any\", \"Optional\"]}, \"sdkcore\": {\"azure.core.credentials\": [\"AzureKeyCredential\"]}}, \"regular\": {\"sdkcore\": {\"azure.mgmt.core\": [\"ARMPipelineClient\"], \"azure.core.pipeline\": [\"policies\"], \"azure.mgmt.core.policies\": [\"ARMAutoResourceProviderRegistrationPolicy\"], \"azure.profiles\": [\"KnownProfiles\", \"ProfileDefinition\"], \"azure.profiles.multiapiclient\": [\"MultiApiClientMixin\"]}, \"local\": {\"._configuration\": [\"MultiapiServiceClientConfiguration\"], \"._utils.serialization\": [\"Deserializer\", \"Serializer\"], \"._operations_mixin\": [\"MultiapiServiceClientOperationsMixin\"]}, \"stdlib\": {\"typing_extensions\": [\"Self\"]}}}", + "async_imports": "{\"conditional\": {\"stdlib\": {\"typing\": [\"Any\", \"Optional\"]}, \"sdkcore\": {\"azure.core.credentials\": [\"AzureKeyCredential\"]}}, \"regular\": {\"sdkcore\": {\"azure.mgmt.core\": [\"AsyncARMPipelineClient\"], \"azure.core.pipeline\": [\"policies\"], \"azure.mgmt.core.policies\": [\"AsyncARMAutoResourceProviderRegistrationPolicy\"], \"azure.profiles\": [\"KnownProfiles\", \"ProfileDefinition\"], \"azure.profiles.multiapiclient\": [\"MultiApiClientMixin\"]}, \"local\": {\"._configuration\": [\"MultiapiServiceClientConfiguration\"], \".._utils.serialization\": [\"Deserializer\", \"Serializer\"], \"._operations_mixin\": [\"MultiapiServiceClientOperationsMixin\"]}, \"stdlib\": {\"typing_extensions\": [\"Self\"]}}}" }, "global_parameters": { "sync": { diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCredentialDefaultPolicy/multiapicredentialdefaultpolicy/v2/_multiapi_service_client.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCredentialDefaultPolicy/multiapicredentialdefaultpolicy/v2/_multiapi_service_client.py index 5941d511dc1..20ff4546cde 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCredentialDefaultPolicy/multiapicredentialdefaultpolicy/v2/_multiapi_service_client.py +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCredentialDefaultPolicy/multiapicredentialdefaultpolicy/v2/_multiapi_service_client.py @@ -17,8 +17,8 @@ from azure.mgmt.core.policies import ARMAutoResourceProviderRegistrationPolicy from . import models as _models -from .._serialization import Deserializer, Serializer from ._configuration import MultiapiServiceClientConfiguration +from ._utils.serialization import Deserializer, Serializer from .operations import MultiapiServiceClientOperationsMixin, OperationGroupOneOperations, OperationGroupTwoOperations diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCredentialDefaultPolicy/multiapicredentialdefaultpolicy/v2/_utils/__init__.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCredentialDefaultPolicy/multiapicredentialdefaultpolicy/v2/_utils/__init__.py new file mode 100644 index 00000000000..0af9b28f660 --- /dev/null +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCredentialDefaultPolicy/multiapicredentialdefaultpolicy/v2/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyString/bodystring/_serialization.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCredentialDefaultPolicy/multiapicredentialdefaultpolicy/v2/_utils/serialization.py similarity index 100% rename from packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyString/bodystring/_serialization.py rename to packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCredentialDefaultPolicy/multiapicredentialdefaultpolicy/v2/_utils/serialization.py diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCredentialDefaultPolicy/multiapicredentialdefaultpolicy/v2/_utils/utils.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCredentialDefaultPolicy/multiapicredentialdefaultpolicy/v2/_utils/utils.py new file mode 100644 index 00000000000..39b612f39a9 --- /dev/null +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCredentialDefaultPolicy/multiapicredentialdefaultpolicy/v2/_utils/utils.py @@ -0,0 +1,25 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from abc import ABC +from typing import Generic, TYPE_CHECKING, TypeVar + +if TYPE_CHECKING: + from .serialization import Deserializer, Serializer + + +TClient = TypeVar("TClient") +TConfig = TypeVar("TConfig") + + +class ClientMixinABC(ABC, Generic[TClient, TConfig]): + """DO NOT use this class. It is for internal typing use only.""" + + _client: TClient + _config: TConfig + _serialize: "Serializer" + _deserialize: "Deserializer" diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCredentialDefaultPolicy/multiapicredentialdefaultpolicy/v2/_vendor.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCredentialDefaultPolicy/multiapicredentialdefaultpolicy/v2/_vendor.py deleted file mode 100644 index 70517e0b7af..00000000000 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCredentialDefaultPolicy/multiapicredentialdefaultpolicy/v2/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) AutoRest Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import MultiapiServiceClientConfiguration - -if TYPE_CHECKING: - from azure.core import PipelineClient - - from .._serialization import Deserializer, Serializer - - -class MultiapiServiceClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "PipelineClient" - _config: MultiapiServiceClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCredentialDefaultPolicy/multiapicredentialdefaultpolicy/v2/aio/_multiapi_service_client.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCredentialDefaultPolicy/multiapicredentialdefaultpolicy/v2/aio/_multiapi_service_client.py index c013e00b3d7..0035ffcbe99 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCredentialDefaultPolicy/multiapicredentialdefaultpolicy/v2/aio/_multiapi_service_client.py +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCredentialDefaultPolicy/multiapicredentialdefaultpolicy/v2/aio/_multiapi_service_client.py @@ -17,7 +17,7 @@ from azure.mgmt.core.policies import AsyncARMAutoResourceProviderRegistrationPolicy from .. import models as _models -from ..._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import MultiapiServiceClientConfiguration from .operations import MultiapiServiceClientOperationsMixin, OperationGroupOneOperations, OperationGroupTwoOperations diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCredentialDefaultPolicy/multiapicredentialdefaultpolicy/v2/aio/_vendor.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCredentialDefaultPolicy/multiapicredentialdefaultpolicy/v2/aio/_vendor.py deleted file mode 100644 index 9c6fd05bb21..00000000000 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCredentialDefaultPolicy/multiapicredentialdefaultpolicy/v2/aio/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) AutoRest Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import MultiapiServiceClientConfiguration - -if TYPE_CHECKING: - from azure.core import AsyncPipelineClient - - from ..._serialization import Deserializer, Serializer - - -class MultiapiServiceClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "AsyncPipelineClient" - _config: MultiapiServiceClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCredentialDefaultPolicy/multiapicredentialdefaultpolicy/v2/aio/operations/_multiapi_service_client_operations.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCredentialDefaultPolicy/multiapicredentialdefaultpolicy/v2/aio/operations/_multiapi_service_client_operations.py index 4bd78f08fc8..d9fa0a892ee 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCredentialDefaultPolicy/multiapicredentialdefaultpolicy/v2/aio/operations/_multiapi_service_client_operations.py +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCredentialDefaultPolicy/multiapicredentialdefaultpolicy/v2/aio/operations/_multiapi_service_client_operations.py @@ -9,6 +9,7 @@ from collections.abc import MutableMapping from typing import Any, Callable, Dict, Optional, TypeVar +from azure.core import AsyncPipelineClient from azure.core.exceptions import ( ClientAuthenticationError, HttpResponseError, @@ -24,14 +25,15 @@ from azure.mgmt.core.exceptions import ARMErrorFormat from ... import models as _models +from ..._utils.utils import ClientMixinABC from ...operations._multiapi_service_client_operations import build_test_different_calls_request, build_test_one_request -from .._vendor import MultiapiServiceClientMixinABC +from .._configuration import MultiapiServiceClientConfiguration T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, AsyncHttpResponse], T, Dict[str, Any]], Any]] -class MultiapiServiceClientOperationsMixin(MultiapiServiceClientMixinABC): +class MultiapiServiceClientOperationsMixin(ClientMixinABC[AsyncPipelineClient, MultiapiServiceClientConfiguration]): def _api_version(self, op_name: str) -> str: # pylint: disable=unused-argument try: return self._config.api_version diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCredentialDefaultPolicy/multiapicredentialdefaultpolicy/v2/aio/operations/_operation_group_one_operations.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCredentialDefaultPolicy/multiapicredentialdefaultpolicy/v2/aio/operations/_operation_group_one_operations.py index 37ff3bdfd99..89976bf3ea7 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCredentialDefaultPolicy/multiapicredentialdefaultpolicy/v2/aio/operations/_operation_group_one_operations.py +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCredentialDefaultPolicy/multiapicredentialdefaultpolicy/v2/aio/operations/_operation_group_one_operations.py @@ -25,7 +25,7 @@ from azure.mgmt.core.exceptions import ARMErrorFormat from ... import models as _models -from ...._serialization import Deserializer, Serializer +from ..._utils.serialization import Deserializer, Serializer from ...operations._operation_group_one_operations import build_test_three_request, build_test_two_request from .._configuration import MultiapiServiceClientConfiguration diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCredentialDefaultPolicy/multiapicredentialdefaultpolicy/v2/aio/operations/_operation_group_two_operations.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCredentialDefaultPolicy/multiapicredentialdefaultpolicy/v2/aio/operations/_operation_group_two_operations.py index f0b585fde4c..f86912ce017 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCredentialDefaultPolicy/multiapicredentialdefaultpolicy/v2/aio/operations/_operation_group_two_operations.py +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCredentialDefaultPolicy/multiapicredentialdefaultpolicy/v2/aio/operations/_operation_group_two_operations.py @@ -24,7 +24,7 @@ from azure.mgmt.core.exceptions import ARMErrorFormat from ... import models as _models -from ...._serialization import Deserializer, Serializer +from ..._utils.serialization import Deserializer, Serializer from ...operations._operation_group_two_operations import build_test_four_request from .._configuration import MultiapiServiceClientConfiguration diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCredentialDefaultPolicy/multiapicredentialdefaultpolicy/v2/models/_models_py3.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCredentialDefaultPolicy/multiapicredentialdefaultpolicy/v2/models/_models_py3.py index 46990252065..a00726a3da2 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCredentialDefaultPolicy/multiapicredentialdefaultpolicy/v2/models/_models_py3.py +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCredentialDefaultPolicy/multiapicredentialdefaultpolicy/v2/models/_models_py3.py @@ -8,7 +8,7 @@ from typing import Any, Optional -from ... import _serialization +from .._utils import serialization as _serialization class Error(_serialization.Model): diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCredentialDefaultPolicy/multiapicredentialdefaultpolicy/v2/operations/_multiapi_service_client_operations.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCredentialDefaultPolicy/multiapicredentialdefaultpolicy/v2/operations/_multiapi_service_client_operations.py index ffd25baabb2..95ea5bf0b9b 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCredentialDefaultPolicy/multiapicredentialdefaultpolicy/v2/operations/_multiapi_service_client_operations.py +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCredentialDefaultPolicy/multiapicredentialdefaultpolicy/v2/operations/_multiapi_service_client_operations.py @@ -8,6 +8,7 @@ from collections.abc import MutableMapping from typing import Any, Callable, Dict, Optional, TypeVar +from azure.core import PipelineClient from azure.core.exceptions import ( ClientAuthenticationError, HttpResponseError, @@ -23,8 +24,9 @@ from azure.mgmt.core.exceptions import ARMErrorFormat from .. import models as _models -from ..._serialization import Serializer -from .._vendor import MultiapiServiceClientMixinABC +from .._configuration import MultiapiServiceClientConfiguration +from .._utils.serialization import Serializer +from .._utils.utils import ClientMixinABC T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] @@ -79,7 +81,7 @@ def build_test_different_calls_request( return HttpRequest(method="GET", url=_url, params=_params, headers=_headers, **kwargs) -class MultiapiServiceClientOperationsMixin(MultiapiServiceClientMixinABC): +class MultiapiServiceClientOperationsMixin(ClientMixinABC[PipelineClient, MultiapiServiceClientConfiguration]): def _api_version(self, op_name: str) -> str: # pylint: disable=unused-argument try: return self._config.api_version diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCredentialDefaultPolicy/multiapicredentialdefaultpolicy/v2/operations/_operation_group_one_operations.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCredentialDefaultPolicy/multiapicredentialdefaultpolicy/v2/operations/_operation_group_one_operations.py index e344ec646c5..11a6d1d0551 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCredentialDefaultPolicy/multiapicredentialdefaultpolicy/v2/operations/_operation_group_one_operations.py +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCredentialDefaultPolicy/multiapicredentialdefaultpolicy/v2/operations/_operation_group_one_operations.py @@ -25,8 +25,8 @@ from azure.mgmt.core.exceptions import ARMErrorFormat from .. import models as _models -from ..._serialization import Deserializer, Serializer from .._configuration import MultiapiServiceClientConfiguration +from .._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCredentialDefaultPolicy/multiapicredentialdefaultpolicy/v2/operations/_operation_group_two_operations.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCredentialDefaultPolicy/multiapicredentialdefaultpolicy/v2/operations/_operation_group_two_operations.py index c1f0d6b7ea9..2a31e6e7714 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCredentialDefaultPolicy/multiapicredentialdefaultpolicy/v2/operations/_operation_group_two_operations.py +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCredentialDefaultPolicy/multiapicredentialdefaultpolicy/v2/operations/_operation_group_two_operations.py @@ -24,8 +24,8 @@ from azure.mgmt.core.exceptions import ARMErrorFormat from .. import models as _models -from ..._serialization import Deserializer, Serializer from .._configuration import MultiapiServiceClientConfiguration +from .._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCredentialDefaultPolicy/multiapicredentialdefaultpolicy/v3/_metadata.json b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCredentialDefaultPolicy/multiapicredentialdefaultpolicy/v3/_metadata.json index 436ac1a965e..24d50359f6c 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCredentialDefaultPolicy/multiapicredentialdefaultpolicy/v3/_metadata.json +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCredentialDefaultPolicy/multiapicredentialdefaultpolicy/v3/_metadata.json @@ -10,8 +10,8 @@ "azure_arm": true, "has_public_lro_operations": false, "client_side_validation": false, - "sync_imports": "{\"conditional\": {\"stdlib\": {\"typing\": [\"Any\", \"Optional\"]}, \"sdkcore\": {\"azure.core.credentials\": [\"AzureKeyCredential\"]}}, \"regular\": {\"sdkcore\": {\"azure.mgmt.core\": [\"ARMPipelineClient\"], \"azure.core.pipeline\": [\"policies\"], \"azure.mgmt.core.policies\": [\"ARMAutoResourceProviderRegistrationPolicy\"], \"azure.profiles\": [\"KnownProfiles\", \"ProfileDefinition\"], \"azure.profiles.multiapiclient\": [\"MultiApiClientMixin\"]}, \"local\": {\"._configuration\": [\"MultiapiServiceClientConfiguration\"], \".._serialization\": [\"Deserializer\", \"Serializer\"], \"._operations_mixin\": [\"MultiapiServiceClientOperationsMixin\"]}, \"stdlib\": {\"typing_extensions\": [\"Self\"]}}}", - "async_imports": "{\"conditional\": {\"stdlib\": {\"typing\": [\"Any\", \"Optional\"]}, \"sdkcore\": {\"azure.core.credentials\": [\"AzureKeyCredential\"]}}, \"regular\": {\"sdkcore\": {\"azure.mgmt.core\": [\"AsyncARMPipelineClient\"], \"azure.core.pipeline\": [\"policies\"], \"azure.mgmt.core.policies\": [\"AsyncARMAutoResourceProviderRegistrationPolicy\"], \"azure.profiles\": [\"KnownProfiles\", \"ProfileDefinition\"], \"azure.profiles.multiapiclient\": [\"MultiApiClientMixin\"]}, \"local\": {\"._configuration\": [\"MultiapiServiceClientConfiguration\"], \"..._serialization\": [\"Deserializer\", \"Serializer\"], \"._operations_mixin\": [\"MultiapiServiceClientOperationsMixin\"]}, \"stdlib\": {\"typing_extensions\": [\"Self\"]}}}" + "sync_imports": "{\"conditional\": {\"stdlib\": {\"typing\": [\"Any\", \"Optional\"]}, \"sdkcore\": {\"azure.core.credentials\": [\"AzureKeyCredential\"]}}, \"regular\": {\"sdkcore\": {\"azure.mgmt.core\": [\"ARMPipelineClient\"], \"azure.core.pipeline\": [\"policies\"], \"azure.mgmt.core.policies\": [\"ARMAutoResourceProviderRegistrationPolicy\"], \"azure.profiles\": [\"KnownProfiles\", \"ProfileDefinition\"], \"azure.profiles.multiapiclient\": [\"MultiApiClientMixin\"]}, \"local\": {\"._configuration\": [\"MultiapiServiceClientConfiguration\"], \"._utils.serialization\": [\"Deserializer\", \"Serializer\"], \"._operations_mixin\": [\"MultiapiServiceClientOperationsMixin\"]}, \"stdlib\": {\"typing_extensions\": [\"Self\"]}}}", + "async_imports": "{\"conditional\": {\"stdlib\": {\"typing\": [\"Any\", \"Optional\"]}, \"sdkcore\": {\"azure.core.credentials\": [\"AzureKeyCredential\"]}}, \"regular\": {\"sdkcore\": {\"azure.mgmt.core\": [\"AsyncARMPipelineClient\"], \"azure.core.pipeline\": [\"policies\"], \"azure.mgmt.core.policies\": [\"AsyncARMAutoResourceProviderRegistrationPolicy\"], \"azure.profiles\": [\"KnownProfiles\", \"ProfileDefinition\"], \"azure.profiles.multiapiclient\": [\"MultiApiClientMixin\"]}, \"local\": {\"._configuration\": [\"MultiapiServiceClientConfiguration\"], \".._utils.serialization\": [\"Deserializer\", \"Serializer\"], \"._operations_mixin\": [\"MultiapiServiceClientOperationsMixin\"]}, \"stdlib\": {\"typing_extensions\": [\"Self\"]}}}" }, "global_parameters": { "sync": { diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCredentialDefaultPolicy/multiapicredentialdefaultpolicy/v3/_multiapi_service_client.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCredentialDefaultPolicy/multiapicredentialdefaultpolicy/v3/_multiapi_service_client.py index 0a694774d16..86571e3a8ae 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCredentialDefaultPolicy/multiapicredentialdefaultpolicy/v3/_multiapi_service_client.py +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCredentialDefaultPolicy/multiapicredentialdefaultpolicy/v3/_multiapi_service_client.py @@ -17,8 +17,8 @@ from azure.mgmt.core.policies import ARMAutoResourceProviderRegistrationPolicy from . import models as _models -from .._serialization import Deserializer, Serializer from ._configuration import MultiapiServiceClientConfiguration +from ._utils.serialization import Deserializer, Serializer from .operations import MultiapiServiceClientOperationsMixin, OperationGroupOneOperations, OperationGroupTwoOperations diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCredentialDefaultPolicy/multiapicredentialdefaultpolicy/v3/_utils/__init__.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCredentialDefaultPolicy/multiapicredentialdefaultpolicy/v3/_utils/__init__.py new file mode 100644 index 00000000000..0af9b28f660 --- /dev/null +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCredentialDefaultPolicy/multiapicredentialdefaultpolicy/v3/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyTime/bodytime/_serialization.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCredentialDefaultPolicy/multiapicredentialdefaultpolicy/v3/_utils/serialization.py similarity index 100% rename from packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyTime/bodytime/_serialization.py rename to packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCredentialDefaultPolicy/multiapicredentialdefaultpolicy/v3/_utils/serialization.py diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCredentialDefaultPolicy/multiapicredentialdefaultpolicy/v3/_utils/utils.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCredentialDefaultPolicy/multiapicredentialdefaultpolicy/v3/_utils/utils.py new file mode 100644 index 00000000000..39b612f39a9 --- /dev/null +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCredentialDefaultPolicy/multiapicredentialdefaultpolicy/v3/_utils/utils.py @@ -0,0 +1,25 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from abc import ABC +from typing import Generic, TYPE_CHECKING, TypeVar + +if TYPE_CHECKING: + from .serialization import Deserializer, Serializer + + +TClient = TypeVar("TClient") +TConfig = TypeVar("TConfig") + + +class ClientMixinABC(ABC, Generic[TClient, TConfig]): + """DO NOT use this class. It is for internal typing use only.""" + + _client: TClient + _config: TConfig + _serialize: "Serializer" + _deserialize: "Deserializer" diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCredentialDefaultPolicy/multiapicredentialdefaultpolicy/v3/_vendor.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCredentialDefaultPolicy/multiapicredentialdefaultpolicy/v3/_vendor.py deleted file mode 100644 index 70517e0b7af..00000000000 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCredentialDefaultPolicy/multiapicredentialdefaultpolicy/v3/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) AutoRest Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import MultiapiServiceClientConfiguration - -if TYPE_CHECKING: - from azure.core import PipelineClient - - from .._serialization import Deserializer, Serializer - - -class MultiapiServiceClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "PipelineClient" - _config: MultiapiServiceClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCredentialDefaultPolicy/multiapicredentialdefaultpolicy/v3/aio/_multiapi_service_client.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCredentialDefaultPolicy/multiapicredentialdefaultpolicy/v3/aio/_multiapi_service_client.py index 065824559be..dc3dd6aa5b6 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCredentialDefaultPolicy/multiapicredentialdefaultpolicy/v3/aio/_multiapi_service_client.py +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCredentialDefaultPolicy/multiapicredentialdefaultpolicy/v3/aio/_multiapi_service_client.py @@ -17,7 +17,7 @@ from azure.mgmt.core.policies import AsyncARMAutoResourceProviderRegistrationPolicy from .. import models as _models -from ..._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import MultiapiServiceClientConfiguration from .operations import MultiapiServiceClientOperationsMixin, OperationGroupOneOperations, OperationGroupTwoOperations diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCredentialDefaultPolicy/multiapicredentialdefaultpolicy/v3/aio/_vendor.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCredentialDefaultPolicy/multiapicredentialdefaultpolicy/v3/aio/_vendor.py deleted file mode 100644 index 9c6fd05bb21..00000000000 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCredentialDefaultPolicy/multiapicredentialdefaultpolicy/v3/aio/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) AutoRest Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import MultiapiServiceClientConfiguration - -if TYPE_CHECKING: - from azure.core import AsyncPipelineClient - - from ..._serialization import Deserializer, Serializer - - -class MultiapiServiceClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "AsyncPipelineClient" - _config: MultiapiServiceClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCredentialDefaultPolicy/multiapicredentialdefaultpolicy/v3/aio/operations/_multiapi_service_client_operations.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCredentialDefaultPolicy/multiapicredentialdefaultpolicy/v3/aio/operations/_multiapi_service_client_operations.py index 523e9f2b2a5..5c878f73c76 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCredentialDefaultPolicy/multiapicredentialdefaultpolicy/v3/aio/operations/_multiapi_service_client_operations.py +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCredentialDefaultPolicy/multiapicredentialdefaultpolicy/v3/aio/operations/_multiapi_service_client_operations.py @@ -10,6 +10,7 @@ from typing import Any, AsyncIterable, Callable, Dict, Optional, TypeVar import urllib.parse +from azure.core import AsyncPipelineClient from azure.core.async_paging import AsyncItemPaged, AsyncList from azure.core.exceptions import ( ClientAuthenticationError, @@ -27,17 +28,18 @@ from azure.mgmt.core.exceptions import ARMErrorFormat from ... import models as _models +from ..._utils.utils import ClientMixinABC from ...operations._multiapi_service_client_operations import ( build_test_different_calls_request, build_test_paging_request, ) -from .._vendor import MultiapiServiceClientMixinABC +from .._configuration import MultiapiServiceClientConfiguration T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, AsyncHttpResponse], T, Dict[str, Any]], Any]] -class MultiapiServiceClientOperationsMixin(MultiapiServiceClientMixinABC): +class MultiapiServiceClientOperationsMixin(ClientMixinABC[AsyncPipelineClient, MultiapiServiceClientConfiguration]): def _api_version(self, op_name: str) -> str: # pylint: disable=unused-argument try: return self._config.api_version diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCredentialDefaultPolicy/multiapicredentialdefaultpolicy/v3/aio/operations/_operation_group_one_operations.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCredentialDefaultPolicy/multiapicredentialdefaultpolicy/v3/aio/operations/_operation_group_one_operations.py index efcf7dcde30..936785d2198 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCredentialDefaultPolicy/multiapicredentialdefaultpolicy/v3/aio/operations/_operation_group_one_operations.py +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCredentialDefaultPolicy/multiapicredentialdefaultpolicy/v3/aio/operations/_operation_group_one_operations.py @@ -28,7 +28,7 @@ from azure.mgmt.core.exceptions import ARMErrorFormat from ... import models as _models -from ...._serialization import Deserializer, Serializer +from ..._utils.serialization import Deserializer, Serializer from ...operations._operation_group_one_operations import ( build_test_operation_group_paging_request, build_test_two_request, diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCredentialDefaultPolicy/multiapicredentialdefaultpolicy/v3/aio/operations/_operation_group_two_operations.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCredentialDefaultPolicy/multiapicredentialdefaultpolicy/v3/aio/operations/_operation_group_two_operations.py index 1e8db5cd2e4..242761a2b61 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCredentialDefaultPolicy/multiapicredentialdefaultpolicy/v3/aio/operations/_operation_group_two_operations.py +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCredentialDefaultPolicy/multiapicredentialdefaultpolicy/v3/aio/operations/_operation_group_two_operations.py @@ -25,7 +25,7 @@ from azure.mgmt.core.exceptions import ARMErrorFormat from ... import models as _models -from ...._serialization import Deserializer, Serializer +from ..._utils.serialization import Deserializer, Serializer from ...operations._operation_group_two_operations import build_test_five_request, build_test_four_request from .._configuration import MultiapiServiceClientConfiguration diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCredentialDefaultPolicy/multiapicredentialdefaultpolicy/v3/models/_models_py3.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCredentialDefaultPolicy/multiapicredentialdefaultpolicy/v3/models/_models_py3.py index 79a8e667ab8..28c7bea759a 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCredentialDefaultPolicy/multiapicredentialdefaultpolicy/v3/models/_models_py3.py +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCredentialDefaultPolicy/multiapicredentialdefaultpolicy/v3/models/_models_py3.py @@ -8,7 +8,7 @@ from typing import Any, List, Optional, TYPE_CHECKING -from ... import _serialization +from .._utils import serialization as _serialization if TYPE_CHECKING: from .. import models as _models diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCredentialDefaultPolicy/multiapicredentialdefaultpolicy/v3/operations/_multiapi_service_client_operations.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCredentialDefaultPolicy/multiapicredentialdefaultpolicy/v3/operations/_multiapi_service_client_operations.py index a69138b65a4..cfc92758661 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCredentialDefaultPolicy/multiapicredentialdefaultpolicy/v3/operations/_multiapi_service_client_operations.py +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCredentialDefaultPolicy/multiapicredentialdefaultpolicy/v3/operations/_multiapi_service_client_operations.py @@ -9,6 +9,7 @@ from typing import Any, Callable, Dict, Iterable, Optional, TypeVar import urllib.parse +from azure.core import PipelineClient from azure.core.exceptions import ( ClientAuthenticationError, HttpResponseError, @@ -25,8 +26,9 @@ from azure.mgmt.core.exceptions import ARMErrorFormat from .. import models as _models -from ..._serialization import Serializer -from .._vendor import MultiapiServiceClientMixinABC +from .._configuration import MultiapiServiceClientConfiguration +from .._utils.serialization import Serializer +from .._utils.utils import ClientMixinABC T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] @@ -79,7 +81,7 @@ def build_test_different_calls_request( return HttpRequest(method="GET", url=_url, params=_params, headers=_headers, **kwargs) -class MultiapiServiceClientOperationsMixin(MultiapiServiceClientMixinABC): +class MultiapiServiceClientOperationsMixin(ClientMixinABC[PipelineClient, MultiapiServiceClientConfiguration]): def _api_version(self, op_name: str) -> str: # pylint: disable=unused-argument try: return self._config.api_version diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCredentialDefaultPolicy/multiapicredentialdefaultpolicy/v3/operations/_operation_group_one_operations.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCredentialDefaultPolicy/multiapicredentialdefaultpolicy/v3/operations/_operation_group_one_operations.py index 566a58e5150..7f1d53e86cd 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCredentialDefaultPolicy/multiapicredentialdefaultpolicy/v3/operations/_operation_group_one_operations.py +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCredentialDefaultPolicy/multiapicredentialdefaultpolicy/v3/operations/_operation_group_one_operations.py @@ -27,8 +27,8 @@ from azure.mgmt.core.exceptions import ARMErrorFormat from .. import models as _models -from ..._serialization import Deserializer, Serializer from .._configuration import MultiapiServiceClientConfiguration +from .._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCredentialDefaultPolicy/multiapicredentialdefaultpolicy/v3/operations/_operation_group_two_operations.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCredentialDefaultPolicy/multiapicredentialdefaultpolicy/v3/operations/_operation_group_two_operations.py index a268a785aa5..7b8ccd53f8f 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCredentialDefaultPolicy/multiapicredentialdefaultpolicy/v3/operations/_operation_group_two_operations.py +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCredentialDefaultPolicy/multiapicredentialdefaultpolicy/v3/operations/_operation_group_two_operations.py @@ -25,8 +25,8 @@ from azure.mgmt.core.exceptions import ARMErrorFormat from .. import models as _models -from ..._serialization import Deserializer, Serializer from .._configuration import MultiapiServiceClientConfiguration +from .._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCustomBaseUrl/multiapicustombaseurl/_multiapi_custom_base_url_service_client.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCustomBaseUrl/multiapicustombaseurl/_multiapi_custom_base_url_service_client.py index d519aa1a6a3..8756f40bfad 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCustomBaseUrl/multiapicustombaseurl/_multiapi_custom_base_url_service_client.py +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCustomBaseUrl/multiapicustombaseurl/_multiapi_custom_base_url_service_client.py @@ -19,7 +19,7 @@ from ._configuration import MultiapiCustomBaseUrlServiceClientConfiguration from ._operations_mixin import MultiapiCustomBaseUrlServiceClientOperationsMixin -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer if TYPE_CHECKING: # pylint: disable=unused-import,ungrouped-imports diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCustomBaseUrl/multiapicustombaseurl/_operations_mixin.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCustomBaseUrl/multiapicustombaseurl/_operations_mixin.py index 5ae5052297e..ce783cdf68f 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCustomBaseUrl/multiapicustombaseurl/_operations_mixin.py +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCustomBaseUrl/multiapicustombaseurl/_operations_mixin.py @@ -8,7 +8,7 @@ # Changes may cause incorrect behavior and will be lost if the code is # regenerated. # -------------------------------------------------------------------------- -from ._serialization import Serializer, Deserializer +from ._utils.serialization import Serializer, Deserializer from typing import Any from . import models as _models diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCustomBaseUrl/multiapicustombaseurl/_utils/__init__.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCustomBaseUrl/multiapicustombaseurl/_utils/__init__.py new file mode 100644 index 00000000000..59333308532 --- /dev/null +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCustomBaseUrl/multiapicustombaseurl/_utils/__init__.py @@ -0,0 +1,10 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is +# regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCustomBaseUrl/multiapicustombaseurl/_utils/serialization.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCustomBaseUrl/multiapicustombaseurl/_utils/serialization.py new file mode 100644 index 00000000000..05bcd7d403a --- /dev/null +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCustomBaseUrl/multiapicustombaseurl/_utils/serialization.py @@ -0,0 +1,2025 @@ +# coding=utf-8 + +# pyright: reportUnnecessaryTypeIgnoreComment=false + +from base64 import b64decode, b64encode +import calendar +import datetime +import decimal +import email +from enum import Enum +import json +import logging +import re +import sys +import codecs +from typing import ( + Dict, + Any, + cast, + Optional, + Union, + AnyStr, + IO, + Mapping, + Callable, + MutableMapping, + List, +) + +try: + from urllib import quote # type: ignore +except ImportError: + from urllib.parse import quote +import xml.etree.ElementTree as ET + +import isodate # type: ignore +from typing_extensions import Self + +from azure.core.exceptions import DeserializationError, SerializationError +from azure.core.serialization import NULL as CoreNull + +_BOM = codecs.BOM_UTF8.decode(encoding="utf-8") + +JSON = MutableMapping[str, Any] + + +class RawDeserializer: + + # Accept "text" because we're open minded people... + JSON_REGEXP = re.compile(r"^(application|text)/([a-z+.]+\+)?json$") + + # Name used in context + CONTEXT_NAME = "deserialized_data" + + @classmethod + def deserialize_from_text(cls, data: Optional[Union[AnyStr, IO]], content_type: Optional[str] = None) -> Any: + """Decode data according to content-type. + + Accept a stream of data as well, but will be load at once in memory for now. + + If no content-type, will return the string version (not bytes, not stream) + + :param data: Input, could be bytes or stream (will be decoded with UTF8) or text + :type data: str or bytes or IO + :param str content_type: The content type. + :return: The deserialized data. + :rtype: object + """ + if hasattr(data, "read"): + # Assume a stream + data = cast(IO, data).read() + + if isinstance(data, bytes): + data_as_str = data.decode(encoding="utf-8-sig") + else: + # Explain to mypy the correct type. + data_as_str = cast(str, data) + + # Remove Byte Order Mark if present in string + data_as_str = data_as_str.lstrip(_BOM) + + if content_type is None: + return data + + if cls.JSON_REGEXP.match(content_type): + try: + return json.loads(data_as_str) + except ValueError as err: + raise DeserializationError("JSON is invalid: {}".format(err), err) from err + elif "xml" in (content_type or []): + try: + + try: + if isinstance(data, unicode): # type: ignore + # If I'm Python 2.7 and unicode XML will scream if I try a "fromstring" on unicode string + data_as_str = data_as_str.encode(encoding="utf-8") # type: ignore + except NameError: + pass + + return ET.fromstring(data_as_str) # nosec + except ET.ParseError as err: + # It might be because the server has an issue, and returned JSON with + # content-type XML.... + # So let's try a JSON load, and if it's still broken + # let's flow the initial exception + def _json_attemp(data): + try: + return True, json.loads(data) + except ValueError: + return False, None # Don't care about this one + + success, json_result = _json_attemp(data) + if success: + return json_result + # If i'm here, it's not JSON, it's not XML, let's scream + # and raise the last context in this block (the XML exception) + # The function hack is because Py2.7 messes up with exception + # context otherwise. + _LOGGER.critical("Wasn't XML not JSON, failing") + raise DeserializationError("XML is invalid") from err + elif content_type.startswith("text/"): + return data_as_str + raise DeserializationError("Cannot deserialize content-type: {}".format(content_type)) + + @classmethod + def deserialize_from_http_generics(cls, body_bytes: Optional[Union[AnyStr, IO]], headers: Mapping) -> Any: + """Deserialize from HTTP response. + + Use bytes and headers to NOT use any requests/aiohttp or whatever + specific implementation. + Headers will tested for "content-type" + + :param bytes body_bytes: The body of the response. + :param dict headers: The headers of the response. + :returns: The deserialized data. + :rtype: object + """ + # Try to use content-type from headers if available + content_type = None + if "content-type" in headers: + content_type = headers["content-type"].split(";")[0].strip().lower() + # Ouch, this server did not declare what it sent... + # Let's guess it's JSON... + # Also, since Autorest was considering that an empty body was a valid JSON, + # need that test as well.... + else: + content_type = "application/json" + + if body_bytes: + return cls.deserialize_from_text(body_bytes, content_type) + return None + + +_LOGGER = logging.getLogger(__name__) + +try: + _long_type = long # type: ignore +except NameError: + _long_type = int + +TZ_UTC = datetime.timezone.utc + +_FLATTEN = re.compile(r"(? None: + self.additional_properties: Optional[Dict[str, Any]] = {} + for k in kwargs: # pylint: disable=consider-using-dict-items + if k not in self._attribute_map: + _LOGGER.warning("%s is not a known attribute of class %s and will be ignored", k, self.__class__) + elif k in self._validation and self._validation[k].get("readonly", False): + _LOGGER.warning("Readonly attribute %s will be ignored in class %s", k, self.__class__) + else: + setattr(self, k, kwargs[k]) + + def __eq__(self, other: Any) -> bool: + """Compare objects by comparing all attributes. + + :param object other: The object to compare + :returns: True if objects are equal + :rtype: bool + """ + if isinstance(other, self.__class__): + return self.__dict__ == other.__dict__ + return False + + def __ne__(self, other: Any) -> bool: + """Compare objects by comparing all attributes. + + :param object other: The object to compare + :returns: True if objects are not equal + :rtype: bool + """ + return not self.__eq__(other) + + def __str__(self) -> str: + return str(self.__dict__) + + @classmethod + def enable_additional_properties_sending(cls) -> None: + cls._attribute_map["additional_properties"] = {"key": "", "type": "{object}"} + + @classmethod + def is_xml_model(cls) -> bool: + try: + cls._xml_map # type: ignore + except AttributeError: + return False + return True + + @classmethod + def _create_xml_node(cls): + """Create XML node. + + :returns: The XML node + :rtype: xml.etree.ElementTree.Element + """ + try: + xml_map = cls._xml_map # type: ignore + except AttributeError: + xml_map = {} + + return _create_xml_node(xml_map.get("name", cls.__name__), xml_map.get("prefix", None), xml_map.get("ns", None)) + + def serialize(self, keep_readonly: bool = False, **kwargs: Any) -> JSON: + """Return the JSON that would be sent to server from this model. + + This is an alias to `as_dict(full_restapi_key_transformer, keep_readonly=False)`. + + If you want XML serialization, you can pass the kwargs is_xml=True. + + :param bool keep_readonly: If you want to serialize the readonly attributes + :returns: A dict JSON compatible object + :rtype: dict + """ + serializer = Serializer(self._infer_class_models()) + return serializer._serialize( # type: ignore # pylint: disable=protected-access + self, keep_readonly=keep_readonly, **kwargs + ) + + def as_dict( + self, + keep_readonly: bool = True, + key_transformer: Callable[[str, Dict[str, Any], Any], Any] = attribute_transformer, + **kwargs: Any + ) -> JSON: + """Return a dict that can be serialized using json.dump. + + Advanced usage might optionally use a callback as parameter: + + .. code::python + + def my_key_transformer(key, attr_desc, value): + return key + + Key is the attribute name used in Python. Attr_desc + is a dict of metadata. Currently contains 'type' with the + msrest type and 'key' with the RestAPI encoded key. + Value is the current value in this object. + + The string returned will be used to serialize the key. + If the return type is a list, this is considered hierarchical + result dict. + + See the three examples in this file: + + - attribute_transformer + - full_restapi_key_transformer + - last_restapi_key_transformer + + If you want XML serialization, you can pass the kwargs is_xml=True. + + :param bool keep_readonly: If you want to serialize the readonly attributes + :param function key_transformer: A key transformer function. + :returns: A dict JSON compatible object + :rtype: dict + """ + serializer = Serializer(self._infer_class_models()) + return serializer._serialize( # type: ignore # pylint: disable=protected-access + self, key_transformer=key_transformer, keep_readonly=keep_readonly, **kwargs + ) + + @classmethod + def _infer_class_models(cls): + try: + str_models = cls.__module__.rsplit(".", 1)[0] + models = sys.modules[str_models] + client_models = {k: v for k, v in models.__dict__.items() if isinstance(v, type)} + if cls.__name__ not in client_models: + raise ValueError("Not Autorest generated code") + except Exception: # pylint: disable=broad-exception-caught + # Assume it's not Autorest generated (tests?). Add ourselves as dependencies. + client_models = {cls.__name__: cls} + return client_models + + @classmethod + def deserialize(cls, data: Any, content_type: Optional[str] = None) -> Self: + """Parse a str using the RestAPI syntax and return a model. + + :param str data: A str using RestAPI structure. JSON by default. + :param str content_type: JSON by default, set application/xml if XML. + :returns: An instance of this model + :raises DeserializationError: if something went wrong + :rtype: Self + """ + deserializer = Deserializer(cls._infer_class_models()) + return deserializer(cls.__name__, data, content_type=content_type) # type: ignore + + @classmethod + def from_dict( + cls, + data: Any, + key_extractors: Optional[Callable[[str, Dict[str, Any], Any], Any]] = None, + content_type: Optional[str] = None, + ) -> Self: + """Parse a dict using given key extractor return a model. + + By default consider key + extractors (rest_key_case_insensitive_extractor, attribute_key_case_insensitive_extractor + and last_rest_key_case_insensitive_extractor) + + :param dict data: A dict using RestAPI structure + :param function key_extractors: A key extractor function. + :param str content_type: JSON by default, set application/xml if XML. + :returns: An instance of this model + :raises DeserializationError: if something went wrong + :rtype: Self + """ + deserializer = Deserializer(cls._infer_class_models()) + deserializer.key_extractors = ( # type: ignore + [ # type: ignore + attribute_key_case_insensitive_extractor, + rest_key_case_insensitive_extractor, + last_rest_key_case_insensitive_extractor, + ] + if key_extractors is None + else key_extractors + ) + return deserializer(cls.__name__, data, content_type=content_type) # type: ignore + + @classmethod + def _flatten_subtype(cls, key, objects): + if "_subtype_map" not in cls.__dict__: + return {} + result = dict(cls._subtype_map[key]) + for valuetype in cls._subtype_map[key].values(): + result.update(objects[valuetype]._flatten_subtype(key, objects)) # pylint: disable=protected-access + return result + + @classmethod + def _classify(cls, response, objects): + """Check the class _subtype_map for any child classes. + We want to ignore any inherited _subtype_maps. + + :param dict response: The initial data + :param dict objects: The class objects + :returns: The class to be used + :rtype: class + """ + for subtype_key in cls.__dict__.get("_subtype_map", {}).keys(): + subtype_value = None + + if not isinstance(response, ET.Element): + rest_api_response_key = cls._get_rest_key_parts(subtype_key)[-1] + subtype_value = response.get(rest_api_response_key, None) or response.get(subtype_key, None) + else: + subtype_value = xml_key_extractor(subtype_key, cls._attribute_map[subtype_key], response) + if subtype_value: + # Try to match base class. Can be class name only + # (bug to fix in Autorest to support x-ms-discriminator-name) + if cls.__name__ == subtype_value: + return cls + flatten_mapping_type = cls._flatten_subtype(subtype_key, objects) + try: + return objects[flatten_mapping_type[subtype_value]] # type: ignore + except KeyError: + _LOGGER.warning( + "Subtype value %s has no mapping, use base class %s.", + subtype_value, + cls.__name__, + ) + break + else: + _LOGGER.warning("Discriminator %s is absent or null, use base class %s.", subtype_key, cls.__name__) + break + return cls + + @classmethod + def _get_rest_key_parts(cls, attr_key): + """Get the RestAPI key of this attr, split it and decode part + :param str attr_key: Attribute key must be in attribute_map. + :returns: A list of RestAPI part + :rtype: list + """ + rest_split_key = _FLATTEN.split(cls._attribute_map[attr_key]["key"]) + return [_decode_attribute_map_key(key_part) for key_part in rest_split_key] + + +def _decode_attribute_map_key(key): + """This decode a key in an _attribute_map to the actual key we want to look at + inside the received data. + + :param str key: A key string from the generated code + :returns: The decoded key + :rtype: str + """ + return key.replace("\\.", ".") + + +class Serializer: # pylint: disable=too-many-public-methods + """Request object model serializer.""" + + basic_types = {str: "str", int: "int", bool: "bool", float: "float"} + + _xml_basic_types_serializers = {"bool": lambda x: str(x).lower()} + days = {0: "Mon", 1: "Tue", 2: "Wed", 3: "Thu", 4: "Fri", 5: "Sat", 6: "Sun"} + months = { + 1: "Jan", + 2: "Feb", + 3: "Mar", + 4: "Apr", + 5: "May", + 6: "Jun", + 7: "Jul", + 8: "Aug", + 9: "Sep", + 10: "Oct", + 11: "Nov", + 12: "Dec", + } + validation = { + "min_length": lambda x, y: len(x) < y, + "max_length": lambda x, y: len(x) > y, + "minimum": lambda x, y: x < y, + "maximum": lambda x, y: x > y, + "minimum_ex": lambda x, y: x <= y, + "maximum_ex": lambda x, y: x >= y, + "min_items": lambda x, y: len(x) < y, + "max_items": lambda x, y: len(x) > y, + "pattern": lambda x, y: not re.match(y, x, re.UNICODE), + "unique": lambda x, y: len(x) != len(set(x)), + "multiple": lambda x, y: x % y != 0, + } + + def __init__(self, classes: Optional[Mapping[str, type]] = None) -> None: + self.serialize_type = { + "iso-8601": Serializer.serialize_iso, + "rfc-1123": Serializer.serialize_rfc, + "unix-time": Serializer.serialize_unix, + "duration": Serializer.serialize_duration, + "date": Serializer.serialize_date, + "time": Serializer.serialize_time, + "decimal": Serializer.serialize_decimal, + "long": Serializer.serialize_long, + "bytearray": Serializer.serialize_bytearray, + "base64": Serializer.serialize_base64, + "object": self.serialize_object, + "[]": self.serialize_iter, + "{}": self.serialize_dict, + } + self.dependencies: Dict[str, type] = dict(classes) if classes else {} + self.key_transformer = full_restapi_key_transformer + self.client_side_validation = True + + def _serialize( # pylint: disable=too-many-nested-blocks, too-many-branches, too-many-statements, too-many-locals + self, target_obj, data_type=None, **kwargs + ): + """Serialize data into a string according to type. + + :param object target_obj: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str, dict + :raises SerializationError: if serialization fails. + :returns: The serialized data. + """ + key_transformer = kwargs.get("key_transformer", self.key_transformer) + keep_readonly = kwargs.get("keep_readonly", False) + if target_obj is None: + return None + + attr_name = None + class_name = target_obj.__class__.__name__ + + if data_type: + return self.serialize_data(target_obj, data_type, **kwargs) + + if not hasattr(target_obj, "_attribute_map"): + data_type = type(target_obj).__name__ + if data_type in self.basic_types.values(): + return self.serialize_data(target_obj, data_type, **kwargs) + + # Force "is_xml" kwargs if we detect a XML model + try: + is_xml_model_serialization = kwargs["is_xml"] + except KeyError: + is_xml_model_serialization = kwargs.setdefault("is_xml", target_obj.is_xml_model()) + + serialized = {} + if is_xml_model_serialization: + serialized = target_obj._create_xml_node() # pylint: disable=protected-access + try: + attributes = target_obj._attribute_map # pylint: disable=protected-access + for attr, attr_desc in attributes.items(): + attr_name = attr + if not keep_readonly and target_obj._validation.get( # pylint: disable=protected-access + attr_name, {} + ).get("readonly", False): + continue + + if attr_name == "additional_properties" and attr_desc["key"] == "": + if target_obj.additional_properties is not None: + serialized.update(target_obj.additional_properties) + continue + try: + + orig_attr = getattr(target_obj, attr) + if is_xml_model_serialization: + pass # Don't provide "transformer" for XML for now. Keep "orig_attr" + else: # JSON + keys, orig_attr = key_transformer(attr, attr_desc.copy(), orig_attr) + keys = keys if isinstance(keys, list) else [keys] + + kwargs["serialization_ctxt"] = attr_desc + new_attr = self.serialize_data(orig_attr, attr_desc["type"], **kwargs) + + if is_xml_model_serialization: + xml_desc = attr_desc.get("xml", {}) + xml_name = xml_desc.get("name", attr_desc["key"]) + xml_prefix = xml_desc.get("prefix", None) + xml_ns = xml_desc.get("ns", None) + if xml_desc.get("attr", False): + if xml_ns: + ET.register_namespace(xml_prefix, xml_ns) + xml_name = "{{{}}}{}".format(xml_ns, xml_name) + serialized.set(xml_name, new_attr) # type: ignore + continue + if xml_desc.get("text", False): + serialized.text = new_attr # type: ignore + continue + if isinstance(new_attr, list): + serialized.extend(new_attr) # type: ignore + elif isinstance(new_attr, ET.Element): + # If the down XML has no XML/Name, + # we MUST replace the tag with the local tag. But keeping the namespaces. + if "name" not in getattr(orig_attr, "_xml_map", {}): + splitted_tag = new_attr.tag.split("}") + if len(splitted_tag) == 2: # Namespace + new_attr.tag = "}".join([splitted_tag[0], xml_name]) + else: + new_attr.tag = xml_name + serialized.append(new_attr) # type: ignore + else: # That's a basic type + # Integrate namespace if necessary + local_node = _create_xml_node(xml_name, xml_prefix, xml_ns) + local_node.text = str(new_attr) + serialized.append(local_node) # type: ignore + else: # JSON + for k in reversed(keys): # type: ignore + new_attr = {k: new_attr} + + _new_attr = new_attr + _serialized = serialized + for k in keys: # type: ignore + if k not in _serialized: + _serialized.update(_new_attr) # type: ignore + _new_attr = _new_attr[k] # type: ignore + _serialized = _serialized[k] + except ValueError as err: + if isinstance(err, SerializationError): + raise + + except (AttributeError, KeyError, TypeError) as err: + msg = "Attribute {} in object {} cannot be serialized.\n{}".format(attr_name, class_name, str(target_obj)) + raise SerializationError(msg) from err + return serialized + + def body(self, data, data_type, **kwargs): + """Serialize data intended for a request body. + + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: dict + :raises SerializationError: if serialization fails. + :raises ValueError: if data is None + :returns: The serialized request body + """ + + # Just in case this is a dict + internal_data_type_str = data_type.strip("[]{}") + internal_data_type = self.dependencies.get(internal_data_type_str, None) + try: + is_xml_model_serialization = kwargs["is_xml"] + except KeyError: + if internal_data_type and issubclass(internal_data_type, Model): + is_xml_model_serialization = kwargs.setdefault("is_xml", internal_data_type.is_xml_model()) + else: + is_xml_model_serialization = False + if internal_data_type and not isinstance(internal_data_type, Enum): + try: + deserializer = Deserializer(self.dependencies) + # Since it's on serialization, it's almost sure that format is not JSON REST + # We're not able to deal with additional properties for now. + deserializer.additional_properties_detection = False + if is_xml_model_serialization: + deserializer.key_extractors = [ # type: ignore + attribute_key_case_insensitive_extractor, + ] + else: + deserializer.key_extractors = [ + rest_key_case_insensitive_extractor, + attribute_key_case_insensitive_extractor, + last_rest_key_case_insensitive_extractor, + ] + data = deserializer._deserialize(data_type, data) # pylint: disable=protected-access + except DeserializationError as err: + raise SerializationError("Unable to build a model: " + str(err)) from err + + return self._serialize(data, data_type, **kwargs) + + def url(self, name, data, data_type, **kwargs): + """Serialize data intended for a URL path. + + :param str name: The name of the URL path parameter. + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str + :returns: The serialized URL path + :raises TypeError: if serialization fails. + :raises ValueError: if data is None + """ + try: + output = self.serialize_data(data, data_type, **kwargs) + if data_type == "bool": + output = json.dumps(output) + + if kwargs.get("skip_quote") is True: + output = str(output) + output = output.replace("{", quote("{")).replace("}", quote("}")) + else: + output = quote(str(output), safe="") + except SerializationError as exc: + raise TypeError("{} must be type {}.".format(name, data_type)) from exc + return output + + def query(self, name, data, data_type, **kwargs): + """Serialize data intended for a URL query. + + :param str name: The name of the query parameter. + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str, list + :raises TypeError: if serialization fails. + :raises ValueError: if data is None + :returns: The serialized query parameter + """ + try: + # Treat the list aside, since we don't want to encode the div separator + if data_type.startswith("["): + internal_data_type = data_type[1:-1] + do_quote = not kwargs.get("skip_quote", False) + return self.serialize_iter(data, internal_data_type, do_quote=do_quote, **kwargs) + + # Not a list, regular serialization + output = self.serialize_data(data, data_type, **kwargs) + if data_type == "bool": + output = json.dumps(output) + if kwargs.get("skip_quote") is True: + output = str(output) + else: + output = quote(str(output), safe="") + except SerializationError as exc: + raise TypeError("{} must be type {}.".format(name, data_type)) from exc + return str(output) + + def header(self, name, data, data_type, **kwargs): + """Serialize data intended for a request header. + + :param str name: The name of the header. + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str + :raises TypeError: if serialization fails. + :raises ValueError: if data is None + :returns: The serialized header + """ + try: + if data_type in ["[str]"]: + data = ["" if d is None else d for d in data] + + output = self.serialize_data(data, data_type, **kwargs) + if data_type == "bool": + output = json.dumps(output) + except SerializationError as exc: + raise TypeError("{} must be type {}.".format(name, data_type)) from exc + return str(output) + + def serialize_data(self, data, data_type, **kwargs): + """Serialize generic data according to supplied data type. + + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :raises AttributeError: if required data is None. + :raises ValueError: if data is None + :raises SerializationError: if serialization fails. + :returns: The serialized data. + :rtype: str, int, float, bool, dict, list + """ + if data is None: + raise ValueError("No value for given attribute") + + try: + if data is CoreNull: + return None + if data_type in self.basic_types.values(): + return self.serialize_basic(data, data_type, **kwargs) + + if data_type in self.serialize_type: + return self.serialize_type[data_type](data, **kwargs) + + # If dependencies is empty, try with current data class + # It has to be a subclass of Enum anyway + enum_type = self.dependencies.get(data_type, data.__class__) + if issubclass(enum_type, Enum): + return Serializer.serialize_enum(data, enum_obj=enum_type) + + iter_type = data_type[0] + data_type[-1] + if iter_type in self.serialize_type: + return self.serialize_type[iter_type](data, data_type[1:-1], **kwargs) + + except (ValueError, TypeError) as err: + msg = "Unable to serialize value: {!r} as type: {!r}." + raise SerializationError(msg.format(data, data_type)) from err + return self._serialize(data, **kwargs) + + @classmethod + def _get_custom_serializers(cls, data_type, **kwargs): # pylint: disable=inconsistent-return-statements + custom_serializer = kwargs.get("basic_types_serializers", {}).get(data_type) + if custom_serializer: + return custom_serializer + if kwargs.get("is_xml", False): + return cls._xml_basic_types_serializers.get(data_type) + + @classmethod + def serialize_basic(cls, data, data_type, **kwargs): + """Serialize basic builting data type. + Serializes objects to str, int, float or bool. + + Possible kwargs: + - basic_types_serializers dict[str, callable] : If set, use the callable as serializer + - is_xml bool : If set, use xml_basic_types_serializers + + :param obj data: Object to be serialized. + :param str data_type: Type of object in the iterable. + :rtype: str, int, float, bool + :return: serialized object + """ + custom_serializer = cls._get_custom_serializers(data_type, **kwargs) + if custom_serializer: + return custom_serializer(data) + if data_type == "str": + return cls.serialize_unicode(data) + return eval(data_type)(data) # nosec # pylint: disable=eval-used + + @classmethod + def serialize_unicode(cls, data): + """Special handling for serializing unicode strings in Py2. + Encode to UTF-8 if unicode, otherwise handle as a str. + + :param str data: Object to be serialized. + :rtype: str + :return: serialized object + """ + try: # If I received an enum, return its value + return data.value + except AttributeError: + pass + + try: + if isinstance(data, unicode): # type: ignore + # Don't change it, JSON and XML ElementTree are totally able + # to serialize correctly u'' strings + return data + except NameError: + return str(data) + return str(data) + + def serialize_iter(self, data, iter_type, div=None, **kwargs): + """Serialize iterable. + + Supported kwargs: + - serialization_ctxt dict : The current entry of _attribute_map, or same format. + serialization_ctxt['type'] should be same as data_type. + - is_xml bool : If set, serialize as XML + + :param list data: Object to be serialized. + :param str iter_type: Type of object in the iterable. + :param str div: If set, this str will be used to combine the elements + in the iterable into a combined string. Default is 'None'. + Defaults to False. + :rtype: list, str + :return: serialized iterable + """ + if isinstance(data, str): + raise SerializationError("Refuse str type as a valid iter type.") + + serialization_ctxt = kwargs.get("serialization_ctxt", {}) + is_xml = kwargs.get("is_xml", False) + + serialized = [] + for d in data: + try: + serialized.append(self.serialize_data(d, iter_type, **kwargs)) + except ValueError as err: + if isinstance(err, SerializationError): + raise + serialized.append(None) + + if kwargs.get("do_quote", False): + serialized = ["" if s is None else quote(str(s), safe="") for s in serialized] + + if div: + serialized = ["" if s is None else str(s) for s in serialized] + serialized = div.join(serialized) + + if "xml" in serialization_ctxt or is_xml: + # XML serialization is more complicated + xml_desc = serialization_ctxt.get("xml", {}) + xml_name = xml_desc.get("name") + if not xml_name: + xml_name = serialization_ctxt["key"] + + # Create a wrap node if necessary (use the fact that Element and list have "append") + is_wrapped = xml_desc.get("wrapped", False) + node_name = xml_desc.get("itemsName", xml_name) + if is_wrapped: + final_result = _create_xml_node(xml_name, xml_desc.get("prefix", None), xml_desc.get("ns", None)) + else: + final_result = [] + # All list elements to "local_node" + for el in serialized: + if isinstance(el, ET.Element): + el_node = el + else: + el_node = _create_xml_node(node_name, xml_desc.get("prefix", None), xml_desc.get("ns", None)) + if el is not None: # Otherwise it writes "None" :-p + el_node.text = str(el) + final_result.append(el_node) + return final_result + return serialized + + def serialize_dict(self, attr, dict_type, **kwargs): + """Serialize a dictionary of objects. + + :param dict attr: Object to be serialized. + :param str dict_type: Type of object in the dictionary. + :rtype: dict + :return: serialized dictionary + """ + serialization_ctxt = kwargs.get("serialization_ctxt", {}) + serialized = {} + for key, value in attr.items(): + try: + serialized[self.serialize_unicode(key)] = self.serialize_data(value, dict_type, **kwargs) + except ValueError as err: + if isinstance(err, SerializationError): + raise + serialized[self.serialize_unicode(key)] = None + + if "xml" in serialization_ctxt: + # XML serialization is more complicated + xml_desc = serialization_ctxt["xml"] + xml_name = xml_desc["name"] + + final_result = _create_xml_node(xml_name, xml_desc.get("prefix", None), xml_desc.get("ns", None)) + for key, value in serialized.items(): + ET.SubElement(final_result, key).text = value + return final_result + + return serialized + + def serialize_object(self, attr, **kwargs): # pylint: disable=too-many-return-statements + """Serialize a generic object. + This will be handled as a dictionary. If object passed in is not + a basic type (str, int, float, dict, list) it will simply be + cast to str. + + :param dict attr: Object to be serialized. + :rtype: dict or str + :return: serialized object + """ + if attr is None: + return None + if isinstance(attr, ET.Element): + return attr + obj_type = type(attr) + if obj_type in self.basic_types: + return self.serialize_basic(attr, self.basic_types[obj_type], **kwargs) + if obj_type is _long_type: + return self.serialize_long(attr) + if obj_type is str: + return self.serialize_unicode(attr) + if obj_type is datetime.datetime: + return self.serialize_iso(attr) + if obj_type is datetime.date: + return self.serialize_date(attr) + if obj_type is datetime.time: + return self.serialize_time(attr) + if obj_type is datetime.timedelta: + return self.serialize_duration(attr) + if obj_type is decimal.Decimal: + return self.serialize_decimal(attr) + + # If it's a model or I know this dependency, serialize as a Model + if obj_type in self.dependencies.values() or isinstance(attr, Model): + return self._serialize(attr) + + if obj_type == dict: + serialized = {} + for key, value in attr.items(): + try: + serialized[self.serialize_unicode(key)] = self.serialize_object(value, **kwargs) + except ValueError: + serialized[self.serialize_unicode(key)] = None + return serialized + + if obj_type == list: + serialized = [] + for obj in attr: + try: + serialized.append(self.serialize_object(obj, **kwargs)) + except ValueError: + pass + return serialized + return str(attr) + + @staticmethod + def serialize_enum(attr, enum_obj=None): + try: + result = attr.value + except AttributeError: + result = attr + try: + enum_obj(result) # type: ignore + return result + except ValueError as exc: + for enum_value in enum_obj: # type: ignore + if enum_value.value.lower() == str(attr).lower(): + return enum_value.value + error = "{!r} is not valid value for enum {!r}" + raise SerializationError(error.format(attr, enum_obj)) from exc + + @staticmethod + def serialize_bytearray(attr, **kwargs): # pylint: disable=unused-argument + """Serialize bytearray into base-64 string. + + :param str attr: Object to be serialized. + :rtype: str + :return: serialized base64 + """ + return b64encode(attr).decode() + + @staticmethod + def serialize_base64(attr, **kwargs): # pylint: disable=unused-argument + """Serialize str into base-64 string. + + :param str attr: Object to be serialized. + :rtype: str + :return: serialized base64 + """ + encoded = b64encode(attr).decode("ascii") + return encoded.strip("=").replace("+", "-").replace("/", "_") + + @staticmethod + def serialize_decimal(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Decimal object to float. + + :param decimal attr: Object to be serialized. + :rtype: float + :return: serialized decimal + """ + return float(attr) + + @staticmethod + def serialize_long(attr, **kwargs): # pylint: disable=unused-argument + """Serialize long (Py2) or int (Py3). + + :param int attr: Object to be serialized. + :rtype: int/long + :return: serialized long + """ + return _long_type(attr) + + @staticmethod + def serialize_date(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Date object into ISO-8601 formatted string. + + :param Date attr: Object to be serialized. + :rtype: str + :return: serialized date + """ + if isinstance(attr, str): + attr = isodate.parse_date(attr) + t = "{:04}-{:02}-{:02}".format(attr.year, attr.month, attr.day) + return t + + @staticmethod + def serialize_time(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Time object into ISO-8601 formatted string. + + :param datetime.time attr: Object to be serialized. + :rtype: str + :return: serialized time + """ + if isinstance(attr, str): + attr = isodate.parse_time(attr) + t = "{:02}:{:02}:{:02}".format(attr.hour, attr.minute, attr.second) + if attr.microsecond: + t += ".{:02}".format(attr.microsecond) + return t + + @staticmethod + def serialize_duration(attr, **kwargs): # pylint: disable=unused-argument + """Serialize TimeDelta object into ISO-8601 formatted string. + + :param TimeDelta attr: Object to be serialized. + :rtype: str + :return: serialized duration + """ + if isinstance(attr, str): + attr = isodate.parse_duration(attr) + return isodate.duration_isoformat(attr) + + @staticmethod + def serialize_rfc(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Datetime object into RFC-1123 formatted string. + + :param Datetime attr: Object to be serialized. + :rtype: str + :raises TypeError: if format invalid. + :return: serialized rfc + """ + try: + if not attr.tzinfo: + _LOGGER.warning("Datetime with no tzinfo will be considered UTC.") + utc = attr.utctimetuple() + except AttributeError as exc: + raise TypeError("RFC1123 object must be valid Datetime object.") from exc + + return "{}, {:02} {} {:04} {:02}:{:02}:{:02} GMT".format( + Serializer.days[utc.tm_wday], + utc.tm_mday, + Serializer.months[utc.tm_mon], + utc.tm_year, + utc.tm_hour, + utc.tm_min, + utc.tm_sec, + ) + + @staticmethod + def serialize_iso(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Datetime object into ISO-8601 formatted string. + + :param Datetime attr: Object to be serialized. + :rtype: str + :raises SerializationError: if format invalid. + :return: serialized iso + """ + if isinstance(attr, str): + attr = isodate.parse_datetime(attr) + try: + if not attr.tzinfo: + _LOGGER.warning("Datetime with no tzinfo will be considered UTC.") + utc = attr.utctimetuple() + if utc.tm_year > 9999 or utc.tm_year < 1: + raise OverflowError("Hit max or min date") + + microseconds = str(attr.microsecond).rjust(6, "0").rstrip("0").ljust(3, "0") + if microseconds: + microseconds = "." + microseconds + date = "{:04}-{:02}-{:02}T{:02}:{:02}:{:02}".format( + utc.tm_year, utc.tm_mon, utc.tm_mday, utc.tm_hour, utc.tm_min, utc.tm_sec + ) + return date + microseconds + "Z" + except (ValueError, OverflowError) as err: + msg = "Unable to serialize datetime object." + raise SerializationError(msg) from err + except AttributeError as err: + msg = "ISO-8601 object must be valid Datetime object." + raise TypeError(msg) from err + + @staticmethod + def serialize_unix(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Datetime object into IntTime format. + This is represented as seconds. + + :param Datetime attr: Object to be serialized. + :rtype: int + :raises SerializationError: if format invalid + :return: serialied unix + """ + if isinstance(attr, int): + return attr + try: + if not attr.tzinfo: + _LOGGER.warning("Datetime with no tzinfo will be considered UTC.") + return int(calendar.timegm(attr.utctimetuple())) + except AttributeError as exc: + raise TypeError("Unix time object must be valid Datetime object.") from exc + + +def rest_key_extractor(attr, attr_desc, data): # pylint: disable=unused-argument + key = attr_desc["key"] + working_data = data + + while "." in key: + # Need the cast, as for some reasons "split" is typed as list[str | Any] + dict_keys = cast(List[str], _FLATTEN.split(key)) + if len(dict_keys) == 1: + key = _decode_attribute_map_key(dict_keys[0]) + break + working_key = _decode_attribute_map_key(dict_keys[0]) + working_data = working_data.get(working_key, data) + if working_data is None: + # If at any point while following flatten JSON path see None, it means + # that all properties under are None as well + return None + key = ".".join(dict_keys[1:]) + + return working_data.get(key) + + +def rest_key_case_insensitive_extractor( # pylint: disable=unused-argument, inconsistent-return-statements + attr, attr_desc, data +): + key = attr_desc["key"] + working_data = data + + while "." in key: + dict_keys = _FLATTEN.split(key) + if len(dict_keys) == 1: + key = _decode_attribute_map_key(dict_keys[0]) + break + working_key = _decode_attribute_map_key(dict_keys[0]) + working_data = attribute_key_case_insensitive_extractor(working_key, None, working_data) + if working_data is None: + # If at any point while following flatten JSON path see None, it means + # that all properties under are None as well + return None + key = ".".join(dict_keys[1:]) + + if working_data: + return attribute_key_case_insensitive_extractor(key, None, working_data) + + +def last_rest_key_extractor(attr, attr_desc, data): # pylint: disable=unused-argument + """Extract the attribute in "data" based on the last part of the JSON path key. + + :param str attr: The attribute to extract + :param dict attr_desc: The attribute description + :param dict data: The data to extract from + :rtype: object + :returns: The extracted attribute + """ + key = attr_desc["key"] + dict_keys = _FLATTEN.split(key) + return attribute_key_extractor(dict_keys[-1], None, data) + + +def last_rest_key_case_insensitive_extractor(attr, attr_desc, data): # pylint: disable=unused-argument + """Extract the attribute in "data" based on the last part of the JSON path key. + + This is the case insensitive version of "last_rest_key_extractor" + :param str attr: The attribute to extract + :param dict attr_desc: The attribute description + :param dict data: The data to extract from + :rtype: object + :returns: The extracted attribute + """ + key = attr_desc["key"] + dict_keys = _FLATTEN.split(key) + return attribute_key_case_insensitive_extractor(dict_keys[-1], None, data) + + +def attribute_key_extractor(attr, _, data): + return data.get(attr) + + +def attribute_key_case_insensitive_extractor(attr, _, data): + found_key = None + lower_attr = attr.lower() + for key in data: + if lower_attr == key.lower(): + found_key = key + break + + return data.get(found_key) + + +def _extract_name_from_internal_type(internal_type): + """Given an internal type XML description, extract correct XML name with namespace. + + :param dict internal_type: An model type + :rtype: tuple + :returns: A tuple XML name + namespace dict + """ + internal_type_xml_map = getattr(internal_type, "_xml_map", {}) + xml_name = internal_type_xml_map.get("name", internal_type.__name__) + xml_ns = internal_type_xml_map.get("ns", None) + if xml_ns: + xml_name = "{{{}}}{}".format(xml_ns, xml_name) + return xml_name + + +def xml_key_extractor(attr, attr_desc, data): # pylint: disable=unused-argument,too-many-return-statements + if isinstance(data, dict): + return None + + # Test if this model is XML ready first + if not isinstance(data, ET.Element): + return None + + xml_desc = attr_desc.get("xml", {}) + xml_name = xml_desc.get("name", attr_desc["key"]) + + # Look for a children + is_iter_type = attr_desc["type"].startswith("[") + is_wrapped = xml_desc.get("wrapped", False) + internal_type = attr_desc.get("internalType", None) + internal_type_xml_map = getattr(internal_type, "_xml_map", {}) + + # Integrate namespace if necessary + xml_ns = xml_desc.get("ns", internal_type_xml_map.get("ns", None)) + if xml_ns: + xml_name = "{{{}}}{}".format(xml_ns, xml_name) + + # If it's an attribute, that's simple + if xml_desc.get("attr", False): + return data.get(xml_name) + + # If it's x-ms-text, that's simple too + if xml_desc.get("text", False): + return data.text + + # Scenario where I take the local name: + # - Wrapped node + # - Internal type is an enum (considered basic types) + # - Internal type has no XML/Name node + if is_wrapped or (internal_type and (issubclass(internal_type, Enum) or "name" not in internal_type_xml_map)): + children = data.findall(xml_name) + # If internal type has a local name and it's not a list, I use that name + elif not is_iter_type and internal_type and "name" in internal_type_xml_map: + xml_name = _extract_name_from_internal_type(internal_type) + children = data.findall(xml_name) + # That's an array + else: + if internal_type: # Complex type, ignore itemsName and use the complex type name + items_name = _extract_name_from_internal_type(internal_type) + else: + items_name = xml_desc.get("itemsName", xml_name) + children = data.findall(items_name) + + if len(children) == 0: + if is_iter_type: + if is_wrapped: + return None # is_wrapped no node, we want None + return [] # not wrapped, assume empty list + return None # Assume it's not there, maybe an optional node. + + # If is_iter_type and not wrapped, return all found children + if is_iter_type: + if not is_wrapped: + return children + # Iter and wrapped, should have found one node only (the wrap one) + if len(children) != 1: + raise DeserializationError( + "Tried to deserialize an array not wrapped, and found several nodes '{}'. Maybe you should declare this array as wrapped?".format( + xml_name + ) + ) + return list(children[0]) # Might be empty list and that's ok. + + # Here it's not a itertype, we should have found one element only or empty + if len(children) > 1: + raise DeserializationError("Find several XML '{}' where it was not expected".format(xml_name)) + return children[0] + + +class Deserializer: + """Response object model deserializer. + + :param dict classes: Class type dictionary for deserializing complex types. + :ivar list key_extractors: Ordered list of extractors to be used by this deserializer. + """ + + basic_types = {str: "str", int: "int", bool: "bool", float: "float"} + + valid_date = re.compile(r"\d{4}[-]\d{2}[-]\d{2}T\d{2}:\d{2}:\d{2}\.?\d*Z?[-+]?[\d{2}]?:?[\d{2}]?") + + def __init__(self, classes: Optional[Mapping[str, type]] = None) -> None: + self.deserialize_type = { + "iso-8601": Deserializer.deserialize_iso, + "rfc-1123": Deserializer.deserialize_rfc, + "unix-time": Deserializer.deserialize_unix, + "duration": Deserializer.deserialize_duration, + "date": Deserializer.deserialize_date, + "time": Deserializer.deserialize_time, + "decimal": Deserializer.deserialize_decimal, + "long": Deserializer.deserialize_long, + "bytearray": Deserializer.deserialize_bytearray, + "base64": Deserializer.deserialize_base64, + "object": self.deserialize_object, + "[]": self.deserialize_iter, + "{}": self.deserialize_dict, + } + self.deserialize_expected_types = { + "duration": (isodate.Duration, datetime.timedelta), + "iso-8601": (datetime.datetime), + } + self.dependencies: Dict[str, type] = dict(classes) if classes else {} + self.key_extractors = [rest_key_extractor, xml_key_extractor] + # Additional properties only works if the "rest_key_extractor" is used to + # extract the keys. Making it to work whatever the key extractor is too much + # complicated, with no real scenario for now. + # So adding a flag to disable additional properties detection. This flag should be + # used if your expect the deserialization to NOT come from a JSON REST syntax. + # Otherwise, result are unexpected + self.additional_properties_detection = True + + def __call__(self, target_obj, response_data, content_type=None): + """Call the deserializer to process a REST response. + + :param str target_obj: Target data type to deserialize to. + :param requests.Response response_data: REST response object. + :param str content_type: Swagger "produces" if available. + :raises DeserializationError: if deserialization fails. + :return: Deserialized object. + :rtype: object + """ + data = self._unpack_content(response_data, content_type) + return self._deserialize(target_obj, data) + + def _deserialize(self, target_obj, data): # pylint: disable=inconsistent-return-statements + """Call the deserializer on a model. + + Data needs to be already deserialized as JSON or XML ElementTree + + :param str target_obj: Target data type to deserialize to. + :param object data: Object to deserialize. + :raises DeserializationError: if deserialization fails. + :return: Deserialized object. + :rtype: object + """ + # This is already a model, go recursive just in case + if hasattr(data, "_attribute_map"): + constants = [name for name, config in getattr(data, "_validation", {}).items() if config.get("constant")] + try: + for attr, mapconfig in data._attribute_map.items(): # pylint: disable=protected-access + if attr in constants: + continue + value = getattr(data, attr) + if value is None: + continue + local_type = mapconfig["type"] + internal_data_type = local_type.strip("[]{}") + if internal_data_type not in self.dependencies or isinstance(internal_data_type, Enum): + continue + setattr(data, attr, self._deserialize(local_type, value)) + return data + except AttributeError: + return + + response, class_name = self._classify_target(target_obj, data) + + if isinstance(response, str): + return self.deserialize_data(data, response) + if isinstance(response, type) and issubclass(response, Enum): + return self.deserialize_enum(data, response) + + if data is None or data is CoreNull: + return data + try: + attributes = response._attribute_map # type: ignore # pylint: disable=protected-access + d_attrs = {} + for attr, attr_desc in attributes.items(): + # Check empty string. If it's not empty, someone has a real "additionalProperties"... + if attr == "additional_properties" and attr_desc["key"] == "": + continue + raw_value = None + # Enhance attr_desc with some dynamic data + attr_desc = attr_desc.copy() # Do a copy, do not change the real one + internal_data_type = attr_desc["type"].strip("[]{}") + if internal_data_type in self.dependencies: + attr_desc["internalType"] = self.dependencies[internal_data_type] + + for key_extractor in self.key_extractors: + found_value = key_extractor(attr, attr_desc, data) + if found_value is not None: + if raw_value is not None and raw_value != found_value: + msg = ( + "Ignoring extracted value '%s' from %s for key '%s'" + " (duplicate extraction, follow extractors order)" + ) + _LOGGER.warning(msg, found_value, key_extractor, attr) + continue + raw_value = found_value + + value = self.deserialize_data(raw_value, attr_desc["type"]) + d_attrs[attr] = value + except (AttributeError, TypeError, KeyError) as err: + msg = "Unable to deserialize to object: " + class_name # type: ignore + raise DeserializationError(msg) from err + additional_properties = self._build_additional_properties(attributes, data) + return self._instantiate_model(response, d_attrs, additional_properties) + + def _build_additional_properties(self, attribute_map, data): + if not self.additional_properties_detection: + return None + if "additional_properties" in attribute_map and attribute_map.get("additional_properties", {}).get("key") != "": + # Check empty string. If it's not empty, someone has a real "additionalProperties" + return None + if isinstance(data, ET.Element): + data = {el.tag: el.text for el in data} + + known_keys = { + _decode_attribute_map_key(_FLATTEN.split(desc["key"])[0]) + for desc in attribute_map.values() + if desc["key"] != "" + } + present_keys = set(data.keys()) + missing_keys = present_keys - known_keys + return {key: data[key] for key in missing_keys} + + def _classify_target(self, target, data): + """Check to see whether the deserialization target object can + be classified into a subclass. + Once classification has been determined, initialize object. + + :param str target: The target object type to deserialize to. + :param str/dict data: The response data to deserialize. + :return: The classified target object and its class name. + :rtype: tuple + """ + if target is None: + return None, None + + if isinstance(target, str): + try: + target = self.dependencies[target] + except KeyError: + return target, target + + try: + target = target._classify(data, self.dependencies) # type: ignore # pylint: disable=protected-access + except AttributeError: + pass # Target is not a Model, no classify + return target, target.__class__.__name__ # type: ignore + + def failsafe_deserialize(self, target_obj, data, content_type=None): + """Ignores any errors encountered in deserialization, + and falls back to not deserializing the object. Recommended + for use in error deserialization, as we want to return the + HttpResponseError to users, and not have them deal with + a deserialization error. + + :param str target_obj: The target object type to deserialize to. + :param str/dict data: The response data to deserialize. + :param str content_type: Swagger "produces" if available. + :return: Deserialized object. + :rtype: object + """ + try: + return self(target_obj, data, content_type=content_type) + except: # pylint: disable=bare-except + _LOGGER.debug( + "Ran into a deserialization error. Ignoring since this is failsafe deserialization", exc_info=True + ) + return None + + @staticmethod + def _unpack_content(raw_data, content_type=None): + """Extract the correct structure for deserialization. + + If raw_data is a PipelineResponse, try to extract the result of RawDeserializer. + if we can't, raise. Your Pipeline should have a RawDeserializer. + + If not a pipeline response and raw_data is bytes or string, use content-type + to decode it. If no content-type, try JSON. + + If raw_data is something else, bypass all logic and return it directly. + + :param obj raw_data: Data to be processed. + :param str content_type: How to parse if raw_data is a string/bytes. + :raises JSONDecodeError: If JSON is requested and parsing is impossible. + :raises UnicodeDecodeError: If bytes is not UTF8 + :rtype: object + :return: Unpacked content. + """ + # Assume this is enough to detect a Pipeline Response without importing it + context = getattr(raw_data, "context", {}) + if context: + if RawDeserializer.CONTEXT_NAME in context: + return context[RawDeserializer.CONTEXT_NAME] + raise ValueError("This pipeline didn't have the RawDeserializer policy; can't deserialize") + + # Assume this is enough to recognize universal_http.ClientResponse without importing it + if hasattr(raw_data, "body"): + return RawDeserializer.deserialize_from_http_generics(raw_data.text(), raw_data.headers) + + # Assume this enough to recognize requests.Response without importing it. + if hasattr(raw_data, "_content_consumed"): + return RawDeserializer.deserialize_from_http_generics(raw_data.text, raw_data.headers) + + if isinstance(raw_data, (str, bytes)) or hasattr(raw_data, "read"): + return RawDeserializer.deserialize_from_text(raw_data, content_type) # type: ignore + return raw_data + + def _instantiate_model(self, response, attrs, additional_properties=None): + """Instantiate a response model passing in deserialized args. + + :param Response response: The response model class. + :param dict attrs: The deserialized response attributes. + :param dict additional_properties: Additional properties to be set. + :rtype: Response + :return: The instantiated response model. + """ + if callable(response): + subtype = getattr(response, "_subtype_map", {}) + try: + readonly = [ + k + for k, v in response._validation.items() # pylint: disable=protected-access # type: ignore + if v.get("readonly") + ] + const = [ + k + for k, v in response._validation.items() # pylint: disable=protected-access # type: ignore + if v.get("constant") + ] + kwargs = {k: v for k, v in attrs.items() if k not in subtype and k not in readonly + const} + response_obj = response(**kwargs) + for attr in readonly: + setattr(response_obj, attr, attrs.get(attr)) + if additional_properties: + response_obj.additional_properties = additional_properties # type: ignore + return response_obj + except TypeError as err: + msg = "Unable to deserialize {} into model {}. ".format(kwargs, response) # type: ignore + raise DeserializationError(msg + str(err)) from err + else: + try: + for attr, value in attrs.items(): + setattr(response, attr, value) + return response + except Exception as exp: + msg = "Unable to populate response model. " + msg += "Type: {}, Error: {}".format(type(response), exp) + raise DeserializationError(msg) from exp + + def deserialize_data(self, data, data_type): # pylint: disable=too-many-return-statements + """Process data for deserialization according to data type. + + :param str data: The response string to be deserialized. + :param str data_type: The type to deserialize to. + :raises DeserializationError: if deserialization fails. + :return: Deserialized object. + :rtype: object + """ + if data is None: + return data + + try: + if not data_type: + return data + if data_type in self.basic_types.values(): + return self.deserialize_basic(data, data_type) + if data_type in self.deserialize_type: + if isinstance(data, self.deserialize_expected_types.get(data_type, tuple())): + return data + + is_a_text_parsing_type = lambda x: x not in [ # pylint: disable=unnecessary-lambda-assignment + "object", + "[]", + r"{}", + ] + if isinstance(data, ET.Element) and is_a_text_parsing_type(data_type) and not data.text: + return None + data_val = self.deserialize_type[data_type](data) + return data_val + + iter_type = data_type[0] + data_type[-1] + if iter_type in self.deserialize_type: + return self.deserialize_type[iter_type](data, data_type[1:-1]) + + obj_type = self.dependencies[data_type] + if issubclass(obj_type, Enum): + if isinstance(data, ET.Element): + data = data.text + return self.deserialize_enum(data, obj_type) + + except (ValueError, TypeError, AttributeError) as err: + msg = "Unable to deserialize response data." + msg += " Data: {}, {}".format(data, data_type) + raise DeserializationError(msg) from err + return self._deserialize(obj_type, data) + + def deserialize_iter(self, attr, iter_type): + """Deserialize an iterable. + + :param list attr: Iterable to be deserialized. + :param str iter_type: The type of object in the iterable. + :return: Deserialized iterable. + :rtype: list + """ + if attr is None: + return None + if isinstance(attr, ET.Element): # If I receive an element here, get the children + attr = list(attr) + if not isinstance(attr, (list, set)): + raise DeserializationError("Cannot deserialize as [{}] an object of type {}".format(iter_type, type(attr))) + return [self.deserialize_data(a, iter_type) for a in attr] + + def deserialize_dict(self, attr, dict_type): + """Deserialize a dictionary. + + :param dict/list attr: Dictionary to be deserialized. Also accepts + a list of key, value pairs. + :param str dict_type: The object type of the items in the dictionary. + :return: Deserialized dictionary. + :rtype: dict + """ + if isinstance(attr, list): + return {x["key"]: self.deserialize_data(x["value"], dict_type) for x in attr} + + if isinstance(attr, ET.Element): + # Transform value into {"Key": "value"} + attr = {el.tag: el.text for el in attr} + return {k: self.deserialize_data(v, dict_type) for k, v in attr.items()} + + def deserialize_object(self, attr, **kwargs): # pylint: disable=too-many-return-statements + """Deserialize a generic object. + This will be handled as a dictionary. + + :param dict attr: Dictionary to be deserialized. + :return: Deserialized object. + :rtype: dict + :raises TypeError: if non-builtin datatype encountered. + """ + if attr is None: + return None + if isinstance(attr, ET.Element): + # Do no recurse on XML, just return the tree as-is + return attr + if isinstance(attr, str): + return self.deserialize_basic(attr, "str") + obj_type = type(attr) + if obj_type in self.basic_types: + return self.deserialize_basic(attr, self.basic_types[obj_type]) + if obj_type is _long_type: + return self.deserialize_long(attr) + + if obj_type == dict: + deserialized = {} + for key, value in attr.items(): + try: + deserialized[key] = self.deserialize_object(value, **kwargs) + except ValueError: + deserialized[key] = None + return deserialized + + if obj_type == list: + deserialized = [] + for obj in attr: + try: + deserialized.append(self.deserialize_object(obj, **kwargs)) + except ValueError: + pass + return deserialized + + error = "Cannot deserialize generic object with type: " + raise TypeError(error + str(obj_type)) + + def deserialize_basic(self, attr, data_type): # pylint: disable=too-many-return-statements + """Deserialize basic builtin data type from string. + Will attempt to convert to str, int, float and bool. + This function will also accept '1', '0', 'true' and 'false' as + valid bool values. + + :param str attr: response string to be deserialized. + :param str data_type: deserialization data type. + :return: Deserialized basic type. + :rtype: str, int, float or bool + :raises TypeError: if string format is not valid. + """ + # If we're here, data is supposed to be a basic type. + # If it's still an XML node, take the text + if isinstance(attr, ET.Element): + attr = attr.text + if not attr: + if data_type == "str": + # None or '', node is empty string. + return "" + # None or '', node with a strong type is None. + # Don't try to model "empty bool" or "empty int" + return None + + if data_type == "bool": + if attr in [True, False, 1, 0]: + return bool(attr) + if isinstance(attr, str): + if attr.lower() in ["true", "1"]: + return True + if attr.lower() in ["false", "0"]: + return False + raise TypeError("Invalid boolean value: {}".format(attr)) + + if data_type == "str": + return self.deserialize_unicode(attr) + return eval(data_type)(attr) # nosec # pylint: disable=eval-used + + @staticmethod + def deserialize_unicode(data): + """Preserve unicode objects in Python 2, otherwise return data + as a string. + + :param str data: response string to be deserialized. + :return: Deserialized string. + :rtype: str or unicode + """ + # We might be here because we have an enum modeled as string, + # and we try to deserialize a partial dict with enum inside + if isinstance(data, Enum): + return data + + # Consider this is real string + try: + if isinstance(data, unicode): # type: ignore + return data + except NameError: + return str(data) + return str(data) + + @staticmethod + def deserialize_enum(data, enum_obj): + """Deserialize string into enum object. + + If the string is not a valid enum value it will be returned as-is + and a warning will be logged. + + :param str data: Response string to be deserialized. If this value is + None or invalid it will be returned as-is. + :param Enum enum_obj: Enum object to deserialize to. + :return: Deserialized enum object. + :rtype: Enum + """ + if isinstance(data, enum_obj) or data is None: + return data + if isinstance(data, Enum): + data = data.value + if isinstance(data, int): + # Workaround. We might consider remove it in the future. + try: + return list(enum_obj.__members__.values())[data] + except IndexError as exc: + error = "{!r} is not a valid index for enum {!r}" + raise DeserializationError(error.format(data, enum_obj)) from exc + try: + return enum_obj(str(data)) + except ValueError: + for enum_value in enum_obj: + if enum_value.value.lower() == str(data).lower(): + return enum_value + # We don't fail anymore for unknown value, we deserialize as a string + _LOGGER.warning("Deserializer is not able to find %s as valid enum in %s", data, enum_obj) + return Deserializer.deserialize_unicode(data) + + @staticmethod + def deserialize_bytearray(attr): + """Deserialize string into bytearray. + + :param str attr: response string to be deserialized. + :return: Deserialized bytearray + :rtype: bytearray + :raises TypeError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + return bytearray(b64decode(attr)) # type: ignore + + @staticmethod + def deserialize_base64(attr): + """Deserialize base64 encoded string into string. + + :param str attr: response string to be deserialized. + :return: Deserialized base64 string + :rtype: bytearray + :raises TypeError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + padding = "=" * (3 - (len(attr) + 3) % 4) # type: ignore + attr = attr + padding # type: ignore + encoded = attr.replace("-", "+").replace("_", "/") + return b64decode(encoded) + + @staticmethod + def deserialize_decimal(attr): + """Deserialize string into Decimal object. + + :param str attr: response string to be deserialized. + :return: Deserialized decimal + :raises DeserializationError: if string format invalid. + :rtype: decimal + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + return decimal.Decimal(str(attr)) # type: ignore + except decimal.DecimalException as err: + msg = "Invalid decimal {}".format(attr) + raise DeserializationError(msg) from err + + @staticmethod + def deserialize_long(attr): + """Deserialize string into long (Py2) or int (Py3). + + :param str attr: response string to be deserialized. + :return: Deserialized int + :rtype: long or int + :raises ValueError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + return _long_type(attr) # type: ignore + + @staticmethod + def deserialize_duration(attr): + """Deserialize ISO-8601 formatted string into TimeDelta object. + + :param str attr: response string to be deserialized. + :return: Deserialized duration + :rtype: TimeDelta + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + duration = isodate.parse_duration(attr) + except (ValueError, OverflowError, AttributeError) as err: + msg = "Cannot deserialize duration object." + raise DeserializationError(msg) from err + return duration + + @staticmethod + def deserialize_date(attr): + """Deserialize ISO-8601 formatted string into Date object. + + :param str attr: response string to be deserialized. + :return: Deserialized date + :rtype: Date + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + if re.search(r"[^\W\d_]", attr, re.I + re.U): # type: ignore + raise DeserializationError("Date must have only digits and -. Received: %s" % attr) + # This must NOT use defaultmonth/defaultday. Using None ensure this raises an exception. + return isodate.parse_date(attr, defaultmonth=0, defaultday=0) + + @staticmethod + def deserialize_time(attr): + """Deserialize ISO-8601 formatted string into time object. + + :param str attr: response string to be deserialized. + :return: Deserialized time + :rtype: datetime.time + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + if re.search(r"[^\W\d_]", attr, re.I + re.U): # type: ignore + raise DeserializationError("Date must have only digits and -. Received: %s" % attr) + return isodate.parse_time(attr) + + @staticmethod + def deserialize_rfc(attr): + """Deserialize RFC-1123 formatted string into Datetime object. + + :param str attr: response string to be deserialized. + :return: Deserialized RFC datetime + :rtype: Datetime + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + parsed_date = email.utils.parsedate_tz(attr) # type: ignore + date_obj = datetime.datetime( + *parsed_date[:6], tzinfo=datetime.timezone(datetime.timedelta(minutes=(parsed_date[9] or 0) / 60)) + ) + if not date_obj.tzinfo: + date_obj = date_obj.astimezone(tz=TZ_UTC) + except ValueError as err: + msg = "Cannot deserialize to rfc datetime object." + raise DeserializationError(msg) from err + return date_obj + + @staticmethod + def deserialize_iso(attr): + """Deserialize ISO-8601 formatted string into Datetime object. + + :param str attr: response string to be deserialized. + :return: Deserialized ISO datetime + :rtype: Datetime + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + attr = attr.upper() # type: ignore + match = Deserializer.valid_date.match(attr) + if not match: + raise ValueError("Invalid datetime string: " + attr) + + check_decimal = attr.split(".") + if len(check_decimal) > 1: + decimal_str = "" + for digit in check_decimal[1]: + if digit.isdigit(): + decimal_str += digit + else: + break + if len(decimal_str) > 6: + attr = attr.replace(decimal_str, decimal_str[0:6]) + + date_obj = isodate.parse_datetime(attr) + test_utc = date_obj.utctimetuple() + if test_utc.tm_year > 9999 or test_utc.tm_year < 1: + raise OverflowError("Hit max or min date") + except (ValueError, OverflowError, AttributeError) as err: + msg = "Cannot deserialize datetime object." + raise DeserializationError(msg) from err + return date_obj + + @staticmethod + def deserialize_unix(attr): + """Serialize Datetime object into IntTime format. + This is represented as seconds. + + :param int attr: Object to be serialized. + :return: Deserialized datetime + :rtype: Datetime + :raises DeserializationError: if format invalid + """ + if isinstance(attr, ET.Element): + attr = int(attr.text) # type: ignore + try: + attr = int(attr) + date_obj = datetime.datetime.fromtimestamp(attr, TZ_UTC) + except ValueError as err: + msg = "Cannot deserialize to unix datetime object." + raise DeserializationError(msg) from err + return date_obj diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCustomBaseUrl/multiapicustombaseurl/aio/_multiapi_custom_base_url_service_client.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCustomBaseUrl/multiapicustombaseurl/aio/_multiapi_custom_base_url_service_client.py index a1c6a473a44..24edac2f073 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCustomBaseUrl/multiapicustombaseurl/aio/_multiapi_custom_base_url_service_client.py +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCustomBaseUrl/multiapicustombaseurl/aio/_multiapi_custom_base_url_service_client.py @@ -17,7 +17,7 @@ from azure.profiles import KnownProfiles, ProfileDefinition from azure.profiles.multiapiclient import MultiApiClientMixin -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import MultiapiCustomBaseUrlServiceClientConfiguration from ._operations_mixin import MultiapiCustomBaseUrlServiceClientOperationsMixin diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCustomBaseUrl/multiapicustombaseurl/aio/_operations_mixin.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCustomBaseUrl/multiapicustombaseurl/aio/_operations_mixin.py index f62c3446472..5b1d22cef5e 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCustomBaseUrl/multiapicustombaseurl/aio/_operations_mixin.py +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCustomBaseUrl/multiapicustombaseurl/aio/_operations_mixin.py @@ -8,7 +8,7 @@ # Changes may cause incorrect behavior and will be lost if the code is # regenerated. # -------------------------------------------------------------------------- -from .._serialization import Serializer, Deserializer +from .._utils.serialization import Serializer, Deserializer from typing import Any from .. import models as _models diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCustomBaseUrl/multiapicustombaseurl/v1/_metadata.json b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCustomBaseUrl/multiapicustombaseurl/v1/_metadata.json index 5142ca2da1c..0bf66d63b27 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCustomBaseUrl/multiapicustombaseurl/v1/_metadata.json +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCustomBaseUrl/multiapicustombaseurl/v1/_metadata.json @@ -10,8 +10,8 @@ "azure_arm": false, "has_public_lro_operations": false, "client_side_validation": false, - "sync_imports": "{\"conditional\": {\"stdlib\": {\"typing\": [\"Any\", \"Optional\"]}}, \"regular\": {\"sdkcore\": {\"azure.core\": [\"PipelineClient\"], \"azure.core.pipeline\": [\"policies\"], \"azure.profiles\": [\"KnownProfiles\", \"ProfileDefinition\"], \"azure.profiles.multiapiclient\": [\"MultiApiClientMixin\"]}, \"local\": {\"._configuration\": [\"MultiapiCustomBaseUrlServiceClientConfiguration\"], \".._serialization\": [\"Deserializer\", \"Serializer\"], \"._operations_mixin\": [\"MultiapiCustomBaseUrlServiceClientOperationsMixin\"]}, \"stdlib\": {\"typing_extensions\": [\"Self\"]}}, \"typing\": {\"sdkcore\": {\"azure.core.credentials\": [\"TokenCredential\"]}}}", - "async_imports": "{\"conditional\": {\"stdlib\": {\"typing\": [\"Any\", \"Optional\"]}}, \"regular\": {\"sdkcore\": {\"azure.core\": [\"AsyncPipelineClient\"], \"azure.core.pipeline\": [\"policies\"], \"azure.profiles\": [\"KnownProfiles\", \"ProfileDefinition\"], \"azure.profiles.multiapiclient\": [\"MultiApiClientMixin\"]}, \"local\": {\"._configuration\": [\"MultiapiCustomBaseUrlServiceClientConfiguration\"], \"..._serialization\": [\"Deserializer\", \"Serializer\"], \"._operations_mixin\": [\"MultiapiCustomBaseUrlServiceClientOperationsMixin\"]}, \"stdlib\": {\"typing_extensions\": [\"Self\"]}}, \"typing\": {\"sdkcore\": {\"azure.core.credentials_async\": [\"AsyncTokenCredential\"]}}}" + "sync_imports": "{\"conditional\": {\"stdlib\": {\"typing\": [\"Any\", \"Optional\"]}}, \"regular\": {\"sdkcore\": {\"azure.core\": [\"PipelineClient\"], \"azure.core.pipeline\": [\"policies\"], \"azure.profiles\": [\"KnownProfiles\", \"ProfileDefinition\"], \"azure.profiles.multiapiclient\": [\"MultiApiClientMixin\"]}, \"local\": {\"._configuration\": [\"MultiapiCustomBaseUrlServiceClientConfiguration\"], \"._utils.serialization\": [\"Deserializer\", \"Serializer\"], \"._operations_mixin\": [\"MultiapiCustomBaseUrlServiceClientOperationsMixin\"]}, \"stdlib\": {\"typing_extensions\": [\"Self\"]}}, \"typing\": {\"sdkcore\": {\"azure.core.credentials\": [\"TokenCredential\"]}}}", + "async_imports": "{\"conditional\": {\"stdlib\": {\"typing\": [\"Any\", \"Optional\"]}}, \"regular\": {\"sdkcore\": {\"azure.core\": [\"AsyncPipelineClient\"], \"azure.core.pipeline\": [\"policies\"], \"azure.profiles\": [\"KnownProfiles\", \"ProfileDefinition\"], \"azure.profiles.multiapiclient\": [\"MultiApiClientMixin\"]}, \"local\": {\"._configuration\": [\"MultiapiCustomBaseUrlServiceClientConfiguration\"], \".._utils.serialization\": [\"Deserializer\", \"Serializer\"], \"._operations_mixin\": [\"MultiapiCustomBaseUrlServiceClientOperationsMixin\"]}, \"stdlib\": {\"typing_extensions\": [\"Self\"]}}, \"typing\": {\"sdkcore\": {\"azure.core.credentials_async\": [\"AsyncTokenCredential\"]}}}" }, "global_parameters": { "sync": { diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCustomBaseUrl/multiapicustombaseurl/v1/_multiapi_custom_base_url_service_client.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCustomBaseUrl/multiapicustombaseurl/v1/_multiapi_custom_base_url_service_client.py index 22df14aa670..8970a6b34a3 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCustomBaseUrl/multiapicustombaseurl/v1/_multiapi_custom_base_url_service_client.py +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCustomBaseUrl/multiapicustombaseurl/v1/_multiapi_custom_base_url_service_client.py @@ -15,8 +15,8 @@ from azure.core.rest import HttpRequest, HttpResponse from . import models as _models -from .._serialization import Deserializer, Serializer from ._configuration import MultiapiCustomBaseUrlServiceClientConfiguration +from ._utils.serialization import Deserializer, Serializer from .operations import MultiapiCustomBaseUrlServiceClientOperationsMixin if TYPE_CHECKING: diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCustomBaseUrl/multiapicustombaseurl/v1/_utils/__init__.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCustomBaseUrl/multiapicustombaseurl/v1/_utils/__init__.py new file mode 100644 index 00000000000..0af9b28f660 --- /dev/null +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCustomBaseUrl/multiapicustombaseurl/v1/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ClientEnum/clientenum/_serialization.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCustomBaseUrl/multiapicustombaseurl/v1/_utils/serialization.py similarity index 100% rename from packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ClientEnum/clientenum/_serialization.py rename to packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCustomBaseUrl/multiapicustombaseurl/v1/_utils/serialization.py diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCustomBaseUrl/multiapicustombaseurl/v1/_utils/utils.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCustomBaseUrl/multiapicustombaseurl/v1/_utils/utils.py new file mode 100644 index 00000000000..39b612f39a9 --- /dev/null +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCustomBaseUrl/multiapicustombaseurl/v1/_utils/utils.py @@ -0,0 +1,25 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from abc import ABC +from typing import Generic, TYPE_CHECKING, TypeVar + +if TYPE_CHECKING: + from .serialization import Deserializer, Serializer + + +TClient = TypeVar("TClient") +TConfig = TypeVar("TConfig") + + +class ClientMixinABC(ABC, Generic[TClient, TConfig]): + """DO NOT use this class. It is for internal typing use only.""" + + _client: TClient + _config: TConfig + _serialize: "Serializer" + _deserialize: "Deserializer" diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCustomBaseUrl/multiapicustombaseurl/v1/_vendor.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCustomBaseUrl/multiapicustombaseurl/v1/_vendor.py deleted file mode 100644 index 856dac1195a..00000000000 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCustomBaseUrl/multiapicustombaseurl/v1/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) AutoRest Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import MultiapiCustomBaseUrlServiceClientConfiguration - -if TYPE_CHECKING: - from azure.core import PipelineClient - - from .._serialization import Deserializer, Serializer - - -class MultiapiCustomBaseUrlServiceClientMixinABC(ABC): # pylint: disable=name-too-long - """DO NOT use this class. It is for internal typing use only.""" - - _client: "PipelineClient" - _config: MultiapiCustomBaseUrlServiceClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCustomBaseUrl/multiapicustombaseurl/v1/aio/_multiapi_custom_base_url_service_client.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCustomBaseUrl/multiapicustombaseurl/v1/aio/_multiapi_custom_base_url_service_client.py index 0f22aaf5ce4..4a6b13782d6 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCustomBaseUrl/multiapicustombaseurl/v1/aio/_multiapi_custom_base_url_service_client.py +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCustomBaseUrl/multiapicustombaseurl/v1/aio/_multiapi_custom_base_url_service_client.py @@ -15,7 +15,7 @@ from azure.core.rest import AsyncHttpResponse, HttpRequest from .. import models as _models -from ..._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import MultiapiCustomBaseUrlServiceClientConfiguration from .operations import MultiapiCustomBaseUrlServiceClientOperationsMixin diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCustomBaseUrl/multiapicustombaseurl/v1/aio/_vendor.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCustomBaseUrl/multiapicustombaseurl/v1/aio/_vendor.py deleted file mode 100644 index 7ad36d04654..00000000000 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCustomBaseUrl/multiapicustombaseurl/v1/aio/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) AutoRest Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import MultiapiCustomBaseUrlServiceClientConfiguration - -if TYPE_CHECKING: - from azure.core import AsyncPipelineClient - - from ..._serialization import Deserializer, Serializer - - -class MultiapiCustomBaseUrlServiceClientMixinABC(ABC): # pylint: disable=name-too-long - """DO NOT use this class. It is for internal typing use only.""" - - _client: "AsyncPipelineClient" - _config: MultiapiCustomBaseUrlServiceClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCustomBaseUrl/multiapicustombaseurl/v1/aio/operations/_multiapi_custom_base_url_service_client_operations.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCustomBaseUrl/multiapicustombaseurl/v1/aio/operations/_multiapi_custom_base_url_service_client_operations.py index 54c47689ac0..8b03d3a1914 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCustomBaseUrl/multiapicustombaseurl/v1/aio/operations/_multiapi_custom_base_url_service_client_operations.py +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCustomBaseUrl/multiapicustombaseurl/v1/aio/operations/_multiapi_custom_base_url_service_client_operations.py @@ -9,6 +9,7 @@ from collections.abc import MutableMapping from typing import Any, Callable, Dict, Optional, TypeVar +from azure.core import AsyncPipelineClient from azure.core.exceptions import ( ClientAuthenticationError, HttpResponseError, @@ -23,15 +24,16 @@ from azure.core.utils import case_insensitive_dict from ... import models as _models +from ..._utils.utils import ClientMixinABC from ...operations._multiapi_custom_base_url_service_client_operations import build_test_request -from .._vendor import MultiapiCustomBaseUrlServiceClientMixinABC +from .._configuration import MultiapiCustomBaseUrlServiceClientConfiguration T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, AsyncHttpResponse], T, Dict[str, Any]], Any]] class MultiapiCustomBaseUrlServiceClientOperationsMixin( # pylint: disable=name-too-long - MultiapiCustomBaseUrlServiceClientMixinABC + ClientMixinABC[AsyncPipelineClient, MultiapiCustomBaseUrlServiceClientConfiguration] ): def _api_version(self, op_name: str) -> str: # pylint: disable=unused-argument try: diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCustomBaseUrl/multiapicustombaseurl/v1/models/_models_py3.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCustomBaseUrl/multiapicustombaseurl/v1/models/_models_py3.py index 4ccf63e55b5..109cf147510 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCustomBaseUrl/multiapicustombaseurl/v1/models/_models_py3.py +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCustomBaseUrl/multiapicustombaseurl/v1/models/_models_py3.py @@ -8,7 +8,7 @@ from typing import Any, Optional -from ... import _serialization +from .._utils import serialization as _serialization class Error(_serialization.Model): diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCustomBaseUrl/multiapicustombaseurl/v1/operations/_multiapi_custom_base_url_service_client_operations.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCustomBaseUrl/multiapicustombaseurl/v1/operations/_multiapi_custom_base_url_service_client_operations.py index b6787dd3c1a..27868fc7871 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCustomBaseUrl/multiapicustombaseurl/v1/operations/_multiapi_custom_base_url_service_client_operations.py +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCustomBaseUrl/multiapicustombaseurl/v1/operations/_multiapi_custom_base_url_service_client_operations.py @@ -8,6 +8,7 @@ from collections.abc import MutableMapping from typing import Any, Callable, Dict, Optional, TypeVar +from azure.core import PipelineClient from azure.core.exceptions import ( ClientAuthenticationError, HttpResponseError, @@ -22,8 +23,9 @@ from azure.core.utils import case_insensitive_dict from .. import models as _models -from ..._serialization import Serializer -from .._vendor import MultiapiCustomBaseUrlServiceClientMixinABC +from .._configuration import MultiapiCustomBaseUrlServiceClientConfiguration +from .._utils.serialization import Serializer +from .._utils.utils import ClientMixinABC T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] @@ -53,7 +55,7 @@ def build_test_request(*, id: int, **kwargs: Any) -> HttpRequest: class MultiapiCustomBaseUrlServiceClientOperationsMixin( # pylint: disable=name-too-long - MultiapiCustomBaseUrlServiceClientMixinABC + ClientMixinABC[PipelineClient, MultiapiCustomBaseUrlServiceClientConfiguration] ): def _api_version(self, op_name: str) -> str: # pylint: disable=unused-argument try: diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCustomBaseUrl/multiapicustombaseurl/v2/_metadata.json b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCustomBaseUrl/multiapicustombaseurl/v2/_metadata.json index 6d520449eb0..416b8026087 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCustomBaseUrl/multiapicustombaseurl/v2/_metadata.json +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCustomBaseUrl/multiapicustombaseurl/v2/_metadata.json @@ -10,8 +10,8 @@ "azure_arm": false, "has_public_lro_operations": false, "client_side_validation": false, - "sync_imports": "{\"conditional\": {\"stdlib\": {\"typing\": [\"Any\", \"Optional\"]}}, \"regular\": {\"sdkcore\": {\"azure.core\": [\"PipelineClient\"], \"azure.core.pipeline\": [\"policies\"], \"azure.profiles\": [\"KnownProfiles\", \"ProfileDefinition\"], \"azure.profiles.multiapiclient\": [\"MultiApiClientMixin\"]}, \"local\": {\"._configuration\": [\"MultiapiCustomBaseUrlServiceClientConfiguration\"], \".._serialization\": [\"Deserializer\", \"Serializer\"], \"._operations_mixin\": [\"MultiapiCustomBaseUrlServiceClientOperationsMixin\"]}, \"stdlib\": {\"typing_extensions\": [\"Self\"]}}, \"typing\": {\"sdkcore\": {\"azure.core.credentials\": [\"TokenCredential\"]}}}", - "async_imports": "{\"conditional\": {\"stdlib\": {\"typing\": [\"Any\", \"Optional\"]}}, \"regular\": {\"sdkcore\": {\"azure.core\": [\"AsyncPipelineClient\"], \"azure.core.pipeline\": [\"policies\"], \"azure.profiles\": [\"KnownProfiles\", \"ProfileDefinition\"], \"azure.profiles.multiapiclient\": [\"MultiApiClientMixin\"]}, \"local\": {\"._configuration\": [\"MultiapiCustomBaseUrlServiceClientConfiguration\"], \"..._serialization\": [\"Deserializer\", \"Serializer\"], \"._operations_mixin\": [\"MultiapiCustomBaseUrlServiceClientOperationsMixin\"]}, \"stdlib\": {\"typing_extensions\": [\"Self\"]}}, \"typing\": {\"sdkcore\": {\"azure.core.credentials_async\": [\"AsyncTokenCredential\"]}}}" + "sync_imports": "{\"conditional\": {\"stdlib\": {\"typing\": [\"Any\", \"Optional\"]}}, \"regular\": {\"sdkcore\": {\"azure.core\": [\"PipelineClient\"], \"azure.core.pipeline\": [\"policies\"], \"azure.profiles\": [\"KnownProfiles\", \"ProfileDefinition\"], \"azure.profiles.multiapiclient\": [\"MultiApiClientMixin\"]}, \"local\": {\"._configuration\": [\"MultiapiCustomBaseUrlServiceClientConfiguration\"], \"._utils.serialization\": [\"Deserializer\", \"Serializer\"], \"._operations_mixin\": [\"MultiapiCustomBaseUrlServiceClientOperationsMixin\"]}, \"stdlib\": {\"typing_extensions\": [\"Self\"]}}, \"typing\": {\"sdkcore\": {\"azure.core.credentials\": [\"TokenCredential\"]}}}", + "async_imports": "{\"conditional\": {\"stdlib\": {\"typing\": [\"Any\", \"Optional\"]}}, \"regular\": {\"sdkcore\": {\"azure.core\": [\"AsyncPipelineClient\"], \"azure.core.pipeline\": [\"policies\"], \"azure.profiles\": [\"KnownProfiles\", \"ProfileDefinition\"], \"azure.profiles.multiapiclient\": [\"MultiApiClientMixin\"]}, \"local\": {\"._configuration\": [\"MultiapiCustomBaseUrlServiceClientConfiguration\"], \".._utils.serialization\": [\"Deserializer\", \"Serializer\"], \"._operations_mixin\": [\"MultiapiCustomBaseUrlServiceClientOperationsMixin\"]}, \"stdlib\": {\"typing_extensions\": [\"Self\"]}}, \"typing\": {\"sdkcore\": {\"azure.core.credentials_async\": [\"AsyncTokenCredential\"]}}}" }, "global_parameters": { "sync": { diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCustomBaseUrl/multiapicustombaseurl/v2/_multiapi_custom_base_url_service_client.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCustomBaseUrl/multiapicustombaseurl/v2/_multiapi_custom_base_url_service_client.py index 6dfec041437..1cb53590dac 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCustomBaseUrl/multiapicustombaseurl/v2/_multiapi_custom_base_url_service_client.py +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCustomBaseUrl/multiapicustombaseurl/v2/_multiapi_custom_base_url_service_client.py @@ -15,8 +15,8 @@ from azure.core.rest import HttpRequest, HttpResponse from . import models as _models -from .._serialization import Deserializer, Serializer from ._configuration import MultiapiCustomBaseUrlServiceClientConfiguration +from ._utils.serialization import Deserializer, Serializer from .operations import MultiapiCustomBaseUrlServiceClientOperationsMixin if TYPE_CHECKING: diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCustomBaseUrl/multiapicustombaseurl/v2/_utils/__init__.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCustomBaseUrl/multiapicustombaseurl/v2/_utils/__init__.py new file mode 100644 index 00000000000..0af9b28f660 --- /dev/null +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCustomBaseUrl/multiapicustombaseurl/v2/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Constants/constants/_serialization.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCustomBaseUrl/multiapicustombaseurl/v2/_utils/serialization.py similarity index 100% rename from packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Constants/constants/_serialization.py rename to packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCustomBaseUrl/multiapicustombaseurl/v2/_utils/serialization.py diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCustomBaseUrl/multiapicustombaseurl/v2/_utils/utils.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCustomBaseUrl/multiapicustombaseurl/v2/_utils/utils.py new file mode 100644 index 00000000000..39b612f39a9 --- /dev/null +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCustomBaseUrl/multiapicustombaseurl/v2/_utils/utils.py @@ -0,0 +1,25 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from abc import ABC +from typing import Generic, TYPE_CHECKING, TypeVar + +if TYPE_CHECKING: + from .serialization import Deserializer, Serializer + + +TClient = TypeVar("TClient") +TConfig = TypeVar("TConfig") + + +class ClientMixinABC(ABC, Generic[TClient, TConfig]): + """DO NOT use this class. It is for internal typing use only.""" + + _client: TClient + _config: TConfig + _serialize: "Serializer" + _deserialize: "Deserializer" diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCustomBaseUrl/multiapicustombaseurl/v2/_vendor.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCustomBaseUrl/multiapicustombaseurl/v2/_vendor.py deleted file mode 100644 index 856dac1195a..00000000000 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCustomBaseUrl/multiapicustombaseurl/v2/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) AutoRest Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import MultiapiCustomBaseUrlServiceClientConfiguration - -if TYPE_CHECKING: - from azure.core import PipelineClient - - from .._serialization import Deserializer, Serializer - - -class MultiapiCustomBaseUrlServiceClientMixinABC(ABC): # pylint: disable=name-too-long - """DO NOT use this class. It is for internal typing use only.""" - - _client: "PipelineClient" - _config: MultiapiCustomBaseUrlServiceClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCustomBaseUrl/multiapicustombaseurl/v2/aio/_multiapi_custom_base_url_service_client.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCustomBaseUrl/multiapicustombaseurl/v2/aio/_multiapi_custom_base_url_service_client.py index c462a585c76..ba7da225ed5 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCustomBaseUrl/multiapicustombaseurl/v2/aio/_multiapi_custom_base_url_service_client.py +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCustomBaseUrl/multiapicustombaseurl/v2/aio/_multiapi_custom_base_url_service_client.py @@ -15,7 +15,7 @@ from azure.core.rest import AsyncHttpResponse, HttpRequest from .. import models as _models -from ..._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import MultiapiCustomBaseUrlServiceClientConfiguration from .operations import MultiapiCustomBaseUrlServiceClientOperationsMixin diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCustomBaseUrl/multiapicustombaseurl/v2/aio/_vendor.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCustomBaseUrl/multiapicustombaseurl/v2/aio/_vendor.py deleted file mode 100644 index 7ad36d04654..00000000000 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCustomBaseUrl/multiapicustombaseurl/v2/aio/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) AutoRest Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import MultiapiCustomBaseUrlServiceClientConfiguration - -if TYPE_CHECKING: - from azure.core import AsyncPipelineClient - - from ..._serialization import Deserializer, Serializer - - -class MultiapiCustomBaseUrlServiceClientMixinABC(ABC): # pylint: disable=name-too-long - """DO NOT use this class. It is for internal typing use only.""" - - _client: "AsyncPipelineClient" - _config: MultiapiCustomBaseUrlServiceClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCustomBaseUrl/multiapicustombaseurl/v2/aio/operations/_multiapi_custom_base_url_service_client_operations.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCustomBaseUrl/multiapicustombaseurl/v2/aio/operations/_multiapi_custom_base_url_service_client_operations.py index 5079b18210d..c5f940271bc 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCustomBaseUrl/multiapicustombaseurl/v2/aio/operations/_multiapi_custom_base_url_service_client_operations.py +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCustomBaseUrl/multiapicustombaseurl/v2/aio/operations/_multiapi_custom_base_url_service_client_operations.py @@ -9,6 +9,7 @@ from collections.abc import MutableMapping from typing import Any, Callable, Dict, Optional, TypeVar +from azure.core import AsyncPipelineClient from azure.core.exceptions import ( ClientAuthenticationError, HttpResponseError, @@ -23,15 +24,16 @@ from azure.core.utils import case_insensitive_dict from ... import models as _models +from ..._utils.utils import ClientMixinABC from ...operations._multiapi_custom_base_url_service_client_operations import build_test_request -from .._vendor import MultiapiCustomBaseUrlServiceClientMixinABC +from .._configuration import MultiapiCustomBaseUrlServiceClientConfiguration T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, AsyncHttpResponse], T, Dict[str, Any]], Any]] class MultiapiCustomBaseUrlServiceClientOperationsMixin( # pylint: disable=name-too-long - MultiapiCustomBaseUrlServiceClientMixinABC + ClientMixinABC[AsyncPipelineClient, MultiapiCustomBaseUrlServiceClientConfiguration] ): def _api_version(self, op_name: str) -> str: # pylint: disable=unused-argument try: diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCustomBaseUrl/multiapicustombaseurl/v2/models/_models_py3.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCustomBaseUrl/multiapicustombaseurl/v2/models/_models_py3.py index 4ccf63e55b5..109cf147510 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCustomBaseUrl/multiapicustombaseurl/v2/models/_models_py3.py +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCustomBaseUrl/multiapicustombaseurl/v2/models/_models_py3.py @@ -8,7 +8,7 @@ from typing import Any, Optional -from ... import _serialization +from .._utils import serialization as _serialization class Error(_serialization.Model): diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCustomBaseUrl/multiapicustombaseurl/v2/operations/_multiapi_custom_base_url_service_client_operations.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCustomBaseUrl/multiapicustombaseurl/v2/operations/_multiapi_custom_base_url_service_client_operations.py index 8fe9b35d599..ff650f0b10c 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCustomBaseUrl/multiapicustombaseurl/v2/operations/_multiapi_custom_base_url_service_client_operations.py +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiCustomBaseUrl/multiapicustombaseurl/v2/operations/_multiapi_custom_base_url_service_client_operations.py @@ -8,6 +8,7 @@ from collections.abc import MutableMapping from typing import Any, Callable, Dict, Optional, TypeVar +from azure.core import PipelineClient from azure.core.exceptions import ( ClientAuthenticationError, HttpResponseError, @@ -22,8 +23,9 @@ from azure.core.utils import case_insensitive_dict from .. import models as _models -from ..._serialization import Serializer -from .._vendor import MultiapiCustomBaseUrlServiceClientMixinABC +from .._configuration import MultiapiCustomBaseUrlServiceClientConfiguration +from .._utils.serialization import Serializer +from .._utils.utils import ClientMixinABC T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] @@ -53,7 +55,7 @@ def build_test_request(*, id: int, **kwargs: Any) -> HttpRequest: class MultiapiCustomBaseUrlServiceClientOperationsMixin( # pylint: disable=name-too-long - MultiapiCustomBaseUrlServiceClientMixinABC + ClientMixinABC[PipelineClient, MultiapiCustomBaseUrlServiceClientConfiguration] ): def _api_version(self, op_name: str) -> str: # pylint: disable=unused-argument try: diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiDataPlane/multiapidataplane/_multiapi_service_client.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiDataPlane/multiapidataplane/_multiapi_service_client.py index e12d2069db1..34d82946557 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiDataPlane/multiapidataplane/_multiapi_service_client.py +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiDataPlane/multiapidataplane/_multiapi_service_client.py @@ -19,7 +19,7 @@ from ._configuration import MultiapiServiceClientConfiguration from ._operations_mixin import MultiapiServiceClientOperationsMixin -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer if TYPE_CHECKING: # pylint: disable=unused-import,ungrouped-imports diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiDataPlane/multiapidataplane/_operations_mixin.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiDataPlane/multiapidataplane/_operations_mixin.py index 92492cc9eb2..00d6558779d 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiDataPlane/multiapidataplane/_operations_mixin.py +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiDataPlane/multiapidataplane/_operations_mixin.py @@ -8,7 +8,7 @@ # Changes may cause incorrect behavior and will be lost if the code is # regenerated. # -------------------------------------------------------------------------- -from ._serialization import Serializer, Deserializer +from ._utils.serialization import Serializer, Deserializer from io import IOBase from typing import Any, IO, Iterable, Iterator, Optional, Union diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiDataPlane/multiapidataplane/_utils/__init__.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiDataPlane/multiapidataplane/_utils/__init__.py new file mode 100644 index 00000000000..59333308532 --- /dev/null +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiDataPlane/multiapidataplane/_utils/__init__.py @@ -0,0 +1,10 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is +# regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiDataPlane/multiapidataplane/_utils/serialization.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiDataPlane/multiapidataplane/_utils/serialization.py new file mode 100644 index 00000000000..05bcd7d403a --- /dev/null +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiDataPlane/multiapidataplane/_utils/serialization.py @@ -0,0 +1,2025 @@ +# coding=utf-8 + +# pyright: reportUnnecessaryTypeIgnoreComment=false + +from base64 import b64decode, b64encode +import calendar +import datetime +import decimal +import email +from enum import Enum +import json +import logging +import re +import sys +import codecs +from typing import ( + Dict, + Any, + cast, + Optional, + Union, + AnyStr, + IO, + Mapping, + Callable, + MutableMapping, + List, +) + +try: + from urllib import quote # type: ignore +except ImportError: + from urllib.parse import quote +import xml.etree.ElementTree as ET + +import isodate # type: ignore +from typing_extensions import Self + +from azure.core.exceptions import DeserializationError, SerializationError +from azure.core.serialization import NULL as CoreNull + +_BOM = codecs.BOM_UTF8.decode(encoding="utf-8") + +JSON = MutableMapping[str, Any] + + +class RawDeserializer: + + # Accept "text" because we're open minded people... + JSON_REGEXP = re.compile(r"^(application|text)/([a-z+.]+\+)?json$") + + # Name used in context + CONTEXT_NAME = "deserialized_data" + + @classmethod + def deserialize_from_text(cls, data: Optional[Union[AnyStr, IO]], content_type: Optional[str] = None) -> Any: + """Decode data according to content-type. + + Accept a stream of data as well, but will be load at once in memory for now. + + If no content-type, will return the string version (not bytes, not stream) + + :param data: Input, could be bytes or stream (will be decoded with UTF8) or text + :type data: str or bytes or IO + :param str content_type: The content type. + :return: The deserialized data. + :rtype: object + """ + if hasattr(data, "read"): + # Assume a stream + data = cast(IO, data).read() + + if isinstance(data, bytes): + data_as_str = data.decode(encoding="utf-8-sig") + else: + # Explain to mypy the correct type. + data_as_str = cast(str, data) + + # Remove Byte Order Mark if present in string + data_as_str = data_as_str.lstrip(_BOM) + + if content_type is None: + return data + + if cls.JSON_REGEXP.match(content_type): + try: + return json.loads(data_as_str) + except ValueError as err: + raise DeserializationError("JSON is invalid: {}".format(err), err) from err + elif "xml" in (content_type or []): + try: + + try: + if isinstance(data, unicode): # type: ignore + # If I'm Python 2.7 and unicode XML will scream if I try a "fromstring" on unicode string + data_as_str = data_as_str.encode(encoding="utf-8") # type: ignore + except NameError: + pass + + return ET.fromstring(data_as_str) # nosec + except ET.ParseError as err: + # It might be because the server has an issue, and returned JSON with + # content-type XML.... + # So let's try a JSON load, and if it's still broken + # let's flow the initial exception + def _json_attemp(data): + try: + return True, json.loads(data) + except ValueError: + return False, None # Don't care about this one + + success, json_result = _json_attemp(data) + if success: + return json_result + # If i'm here, it's not JSON, it's not XML, let's scream + # and raise the last context in this block (the XML exception) + # The function hack is because Py2.7 messes up with exception + # context otherwise. + _LOGGER.critical("Wasn't XML not JSON, failing") + raise DeserializationError("XML is invalid") from err + elif content_type.startswith("text/"): + return data_as_str + raise DeserializationError("Cannot deserialize content-type: {}".format(content_type)) + + @classmethod + def deserialize_from_http_generics(cls, body_bytes: Optional[Union[AnyStr, IO]], headers: Mapping) -> Any: + """Deserialize from HTTP response. + + Use bytes and headers to NOT use any requests/aiohttp or whatever + specific implementation. + Headers will tested for "content-type" + + :param bytes body_bytes: The body of the response. + :param dict headers: The headers of the response. + :returns: The deserialized data. + :rtype: object + """ + # Try to use content-type from headers if available + content_type = None + if "content-type" in headers: + content_type = headers["content-type"].split(";")[0].strip().lower() + # Ouch, this server did not declare what it sent... + # Let's guess it's JSON... + # Also, since Autorest was considering that an empty body was a valid JSON, + # need that test as well.... + else: + content_type = "application/json" + + if body_bytes: + return cls.deserialize_from_text(body_bytes, content_type) + return None + + +_LOGGER = logging.getLogger(__name__) + +try: + _long_type = long # type: ignore +except NameError: + _long_type = int + +TZ_UTC = datetime.timezone.utc + +_FLATTEN = re.compile(r"(? None: + self.additional_properties: Optional[Dict[str, Any]] = {} + for k in kwargs: # pylint: disable=consider-using-dict-items + if k not in self._attribute_map: + _LOGGER.warning("%s is not a known attribute of class %s and will be ignored", k, self.__class__) + elif k in self._validation and self._validation[k].get("readonly", False): + _LOGGER.warning("Readonly attribute %s will be ignored in class %s", k, self.__class__) + else: + setattr(self, k, kwargs[k]) + + def __eq__(self, other: Any) -> bool: + """Compare objects by comparing all attributes. + + :param object other: The object to compare + :returns: True if objects are equal + :rtype: bool + """ + if isinstance(other, self.__class__): + return self.__dict__ == other.__dict__ + return False + + def __ne__(self, other: Any) -> bool: + """Compare objects by comparing all attributes. + + :param object other: The object to compare + :returns: True if objects are not equal + :rtype: bool + """ + return not self.__eq__(other) + + def __str__(self) -> str: + return str(self.__dict__) + + @classmethod + def enable_additional_properties_sending(cls) -> None: + cls._attribute_map["additional_properties"] = {"key": "", "type": "{object}"} + + @classmethod + def is_xml_model(cls) -> bool: + try: + cls._xml_map # type: ignore + except AttributeError: + return False + return True + + @classmethod + def _create_xml_node(cls): + """Create XML node. + + :returns: The XML node + :rtype: xml.etree.ElementTree.Element + """ + try: + xml_map = cls._xml_map # type: ignore + except AttributeError: + xml_map = {} + + return _create_xml_node(xml_map.get("name", cls.__name__), xml_map.get("prefix", None), xml_map.get("ns", None)) + + def serialize(self, keep_readonly: bool = False, **kwargs: Any) -> JSON: + """Return the JSON that would be sent to server from this model. + + This is an alias to `as_dict(full_restapi_key_transformer, keep_readonly=False)`. + + If you want XML serialization, you can pass the kwargs is_xml=True. + + :param bool keep_readonly: If you want to serialize the readonly attributes + :returns: A dict JSON compatible object + :rtype: dict + """ + serializer = Serializer(self._infer_class_models()) + return serializer._serialize( # type: ignore # pylint: disable=protected-access + self, keep_readonly=keep_readonly, **kwargs + ) + + def as_dict( + self, + keep_readonly: bool = True, + key_transformer: Callable[[str, Dict[str, Any], Any], Any] = attribute_transformer, + **kwargs: Any + ) -> JSON: + """Return a dict that can be serialized using json.dump. + + Advanced usage might optionally use a callback as parameter: + + .. code::python + + def my_key_transformer(key, attr_desc, value): + return key + + Key is the attribute name used in Python. Attr_desc + is a dict of metadata. Currently contains 'type' with the + msrest type and 'key' with the RestAPI encoded key. + Value is the current value in this object. + + The string returned will be used to serialize the key. + If the return type is a list, this is considered hierarchical + result dict. + + See the three examples in this file: + + - attribute_transformer + - full_restapi_key_transformer + - last_restapi_key_transformer + + If you want XML serialization, you can pass the kwargs is_xml=True. + + :param bool keep_readonly: If you want to serialize the readonly attributes + :param function key_transformer: A key transformer function. + :returns: A dict JSON compatible object + :rtype: dict + """ + serializer = Serializer(self._infer_class_models()) + return serializer._serialize( # type: ignore # pylint: disable=protected-access + self, key_transformer=key_transformer, keep_readonly=keep_readonly, **kwargs + ) + + @classmethod + def _infer_class_models(cls): + try: + str_models = cls.__module__.rsplit(".", 1)[0] + models = sys.modules[str_models] + client_models = {k: v for k, v in models.__dict__.items() if isinstance(v, type)} + if cls.__name__ not in client_models: + raise ValueError("Not Autorest generated code") + except Exception: # pylint: disable=broad-exception-caught + # Assume it's not Autorest generated (tests?). Add ourselves as dependencies. + client_models = {cls.__name__: cls} + return client_models + + @classmethod + def deserialize(cls, data: Any, content_type: Optional[str] = None) -> Self: + """Parse a str using the RestAPI syntax and return a model. + + :param str data: A str using RestAPI structure. JSON by default. + :param str content_type: JSON by default, set application/xml if XML. + :returns: An instance of this model + :raises DeserializationError: if something went wrong + :rtype: Self + """ + deserializer = Deserializer(cls._infer_class_models()) + return deserializer(cls.__name__, data, content_type=content_type) # type: ignore + + @classmethod + def from_dict( + cls, + data: Any, + key_extractors: Optional[Callable[[str, Dict[str, Any], Any], Any]] = None, + content_type: Optional[str] = None, + ) -> Self: + """Parse a dict using given key extractor return a model. + + By default consider key + extractors (rest_key_case_insensitive_extractor, attribute_key_case_insensitive_extractor + and last_rest_key_case_insensitive_extractor) + + :param dict data: A dict using RestAPI structure + :param function key_extractors: A key extractor function. + :param str content_type: JSON by default, set application/xml if XML. + :returns: An instance of this model + :raises DeserializationError: if something went wrong + :rtype: Self + """ + deserializer = Deserializer(cls._infer_class_models()) + deserializer.key_extractors = ( # type: ignore + [ # type: ignore + attribute_key_case_insensitive_extractor, + rest_key_case_insensitive_extractor, + last_rest_key_case_insensitive_extractor, + ] + if key_extractors is None + else key_extractors + ) + return deserializer(cls.__name__, data, content_type=content_type) # type: ignore + + @classmethod + def _flatten_subtype(cls, key, objects): + if "_subtype_map" not in cls.__dict__: + return {} + result = dict(cls._subtype_map[key]) + for valuetype in cls._subtype_map[key].values(): + result.update(objects[valuetype]._flatten_subtype(key, objects)) # pylint: disable=protected-access + return result + + @classmethod + def _classify(cls, response, objects): + """Check the class _subtype_map for any child classes. + We want to ignore any inherited _subtype_maps. + + :param dict response: The initial data + :param dict objects: The class objects + :returns: The class to be used + :rtype: class + """ + for subtype_key in cls.__dict__.get("_subtype_map", {}).keys(): + subtype_value = None + + if not isinstance(response, ET.Element): + rest_api_response_key = cls._get_rest_key_parts(subtype_key)[-1] + subtype_value = response.get(rest_api_response_key, None) or response.get(subtype_key, None) + else: + subtype_value = xml_key_extractor(subtype_key, cls._attribute_map[subtype_key], response) + if subtype_value: + # Try to match base class. Can be class name only + # (bug to fix in Autorest to support x-ms-discriminator-name) + if cls.__name__ == subtype_value: + return cls + flatten_mapping_type = cls._flatten_subtype(subtype_key, objects) + try: + return objects[flatten_mapping_type[subtype_value]] # type: ignore + except KeyError: + _LOGGER.warning( + "Subtype value %s has no mapping, use base class %s.", + subtype_value, + cls.__name__, + ) + break + else: + _LOGGER.warning("Discriminator %s is absent or null, use base class %s.", subtype_key, cls.__name__) + break + return cls + + @classmethod + def _get_rest_key_parts(cls, attr_key): + """Get the RestAPI key of this attr, split it and decode part + :param str attr_key: Attribute key must be in attribute_map. + :returns: A list of RestAPI part + :rtype: list + """ + rest_split_key = _FLATTEN.split(cls._attribute_map[attr_key]["key"]) + return [_decode_attribute_map_key(key_part) for key_part in rest_split_key] + + +def _decode_attribute_map_key(key): + """This decode a key in an _attribute_map to the actual key we want to look at + inside the received data. + + :param str key: A key string from the generated code + :returns: The decoded key + :rtype: str + """ + return key.replace("\\.", ".") + + +class Serializer: # pylint: disable=too-many-public-methods + """Request object model serializer.""" + + basic_types = {str: "str", int: "int", bool: "bool", float: "float"} + + _xml_basic_types_serializers = {"bool": lambda x: str(x).lower()} + days = {0: "Mon", 1: "Tue", 2: "Wed", 3: "Thu", 4: "Fri", 5: "Sat", 6: "Sun"} + months = { + 1: "Jan", + 2: "Feb", + 3: "Mar", + 4: "Apr", + 5: "May", + 6: "Jun", + 7: "Jul", + 8: "Aug", + 9: "Sep", + 10: "Oct", + 11: "Nov", + 12: "Dec", + } + validation = { + "min_length": lambda x, y: len(x) < y, + "max_length": lambda x, y: len(x) > y, + "minimum": lambda x, y: x < y, + "maximum": lambda x, y: x > y, + "minimum_ex": lambda x, y: x <= y, + "maximum_ex": lambda x, y: x >= y, + "min_items": lambda x, y: len(x) < y, + "max_items": lambda x, y: len(x) > y, + "pattern": lambda x, y: not re.match(y, x, re.UNICODE), + "unique": lambda x, y: len(x) != len(set(x)), + "multiple": lambda x, y: x % y != 0, + } + + def __init__(self, classes: Optional[Mapping[str, type]] = None) -> None: + self.serialize_type = { + "iso-8601": Serializer.serialize_iso, + "rfc-1123": Serializer.serialize_rfc, + "unix-time": Serializer.serialize_unix, + "duration": Serializer.serialize_duration, + "date": Serializer.serialize_date, + "time": Serializer.serialize_time, + "decimal": Serializer.serialize_decimal, + "long": Serializer.serialize_long, + "bytearray": Serializer.serialize_bytearray, + "base64": Serializer.serialize_base64, + "object": self.serialize_object, + "[]": self.serialize_iter, + "{}": self.serialize_dict, + } + self.dependencies: Dict[str, type] = dict(classes) if classes else {} + self.key_transformer = full_restapi_key_transformer + self.client_side_validation = True + + def _serialize( # pylint: disable=too-many-nested-blocks, too-many-branches, too-many-statements, too-many-locals + self, target_obj, data_type=None, **kwargs + ): + """Serialize data into a string according to type. + + :param object target_obj: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str, dict + :raises SerializationError: if serialization fails. + :returns: The serialized data. + """ + key_transformer = kwargs.get("key_transformer", self.key_transformer) + keep_readonly = kwargs.get("keep_readonly", False) + if target_obj is None: + return None + + attr_name = None + class_name = target_obj.__class__.__name__ + + if data_type: + return self.serialize_data(target_obj, data_type, **kwargs) + + if not hasattr(target_obj, "_attribute_map"): + data_type = type(target_obj).__name__ + if data_type in self.basic_types.values(): + return self.serialize_data(target_obj, data_type, **kwargs) + + # Force "is_xml" kwargs if we detect a XML model + try: + is_xml_model_serialization = kwargs["is_xml"] + except KeyError: + is_xml_model_serialization = kwargs.setdefault("is_xml", target_obj.is_xml_model()) + + serialized = {} + if is_xml_model_serialization: + serialized = target_obj._create_xml_node() # pylint: disable=protected-access + try: + attributes = target_obj._attribute_map # pylint: disable=protected-access + for attr, attr_desc in attributes.items(): + attr_name = attr + if not keep_readonly and target_obj._validation.get( # pylint: disable=protected-access + attr_name, {} + ).get("readonly", False): + continue + + if attr_name == "additional_properties" and attr_desc["key"] == "": + if target_obj.additional_properties is not None: + serialized.update(target_obj.additional_properties) + continue + try: + + orig_attr = getattr(target_obj, attr) + if is_xml_model_serialization: + pass # Don't provide "transformer" for XML for now. Keep "orig_attr" + else: # JSON + keys, orig_attr = key_transformer(attr, attr_desc.copy(), orig_attr) + keys = keys if isinstance(keys, list) else [keys] + + kwargs["serialization_ctxt"] = attr_desc + new_attr = self.serialize_data(orig_attr, attr_desc["type"], **kwargs) + + if is_xml_model_serialization: + xml_desc = attr_desc.get("xml", {}) + xml_name = xml_desc.get("name", attr_desc["key"]) + xml_prefix = xml_desc.get("prefix", None) + xml_ns = xml_desc.get("ns", None) + if xml_desc.get("attr", False): + if xml_ns: + ET.register_namespace(xml_prefix, xml_ns) + xml_name = "{{{}}}{}".format(xml_ns, xml_name) + serialized.set(xml_name, new_attr) # type: ignore + continue + if xml_desc.get("text", False): + serialized.text = new_attr # type: ignore + continue + if isinstance(new_attr, list): + serialized.extend(new_attr) # type: ignore + elif isinstance(new_attr, ET.Element): + # If the down XML has no XML/Name, + # we MUST replace the tag with the local tag. But keeping the namespaces. + if "name" not in getattr(orig_attr, "_xml_map", {}): + splitted_tag = new_attr.tag.split("}") + if len(splitted_tag) == 2: # Namespace + new_attr.tag = "}".join([splitted_tag[0], xml_name]) + else: + new_attr.tag = xml_name + serialized.append(new_attr) # type: ignore + else: # That's a basic type + # Integrate namespace if necessary + local_node = _create_xml_node(xml_name, xml_prefix, xml_ns) + local_node.text = str(new_attr) + serialized.append(local_node) # type: ignore + else: # JSON + for k in reversed(keys): # type: ignore + new_attr = {k: new_attr} + + _new_attr = new_attr + _serialized = serialized + for k in keys: # type: ignore + if k not in _serialized: + _serialized.update(_new_attr) # type: ignore + _new_attr = _new_attr[k] # type: ignore + _serialized = _serialized[k] + except ValueError as err: + if isinstance(err, SerializationError): + raise + + except (AttributeError, KeyError, TypeError) as err: + msg = "Attribute {} in object {} cannot be serialized.\n{}".format(attr_name, class_name, str(target_obj)) + raise SerializationError(msg) from err + return serialized + + def body(self, data, data_type, **kwargs): + """Serialize data intended for a request body. + + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: dict + :raises SerializationError: if serialization fails. + :raises ValueError: if data is None + :returns: The serialized request body + """ + + # Just in case this is a dict + internal_data_type_str = data_type.strip("[]{}") + internal_data_type = self.dependencies.get(internal_data_type_str, None) + try: + is_xml_model_serialization = kwargs["is_xml"] + except KeyError: + if internal_data_type and issubclass(internal_data_type, Model): + is_xml_model_serialization = kwargs.setdefault("is_xml", internal_data_type.is_xml_model()) + else: + is_xml_model_serialization = False + if internal_data_type and not isinstance(internal_data_type, Enum): + try: + deserializer = Deserializer(self.dependencies) + # Since it's on serialization, it's almost sure that format is not JSON REST + # We're not able to deal with additional properties for now. + deserializer.additional_properties_detection = False + if is_xml_model_serialization: + deserializer.key_extractors = [ # type: ignore + attribute_key_case_insensitive_extractor, + ] + else: + deserializer.key_extractors = [ + rest_key_case_insensitive_extractor, + attribute_key_case_insensitive_extractor, + last_rest_key_case_insensitive_extractor, + ] + data = deserializer._deserialize(data_type, data) # pylint: disable=protected-access + except DeserializationError as err: + raise SerializationError("Unable to build a model: " + str(err)) from err + + return self._serialize(data, data_type, **kwargs) + + def url(self, name, data, data_type, **kwargs): + """Serialize data intended for a URL path. + + :param str name: The name of the URL path parameter. + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str + :returns: The serialized URL path + :raises TypeError: if serialization fails. + :raises ValueError: if data is None + """ + try: + output = self.serialize_data(data, data_type, **kwargs) + if data_type == "bool": + output = json.dumps(output) + + if kwargs.get("skip_quote") is True: + output = str(output) + output = output.replace("{", quote("{")).replace("}", quote("}")) + else: + output = quote(str(output), safe="") + except SerializationError as exc: + raise TypeError("{} must be type {}.".format(name, data_type)) from exc + return output + + def query(self, name, data, data_type, **kwargs): + """Serialize data intended for a URL query. + + :param str name: The name of the query parameter. + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str, list + :raises TypeError: if serialization fails. + :raises ValueError: if data is None + :returns: The serialized query parameter + """ + try: + # Treat the list aside, since we don't want to encode the div separator + if data_type.startswith("["): + internal_data_type = data_type[1:-1] + do_quote = not kwargs.get("skip_quote", False) + return self.serialize_iter(data, internal_data_type, do_quote=do_quote, **kwargs) + + # Not a list, regular serialization + output = self.serialize_data(data, data_type, **kwargs) + if data_type == "bool": + output = json.dumps(output) + if kwargs.get("skip_quote") is True: + output = str(output) + else: + output = quote(str(output), safe="") + except SerializationError as exc: + raise TypeError("{} must be type {}.".format(name, data_type)) from exc + return str(output) + + def header(self, name, data, data_type, **kwargs): + """Serialize data intended for a request header. + + :param str name: The name of the header. + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str + :raises TypeError: if serialization fails. + :raises ValueError: if data is None + :returns: The serialized header + """ + try: + if data_type in ["[str]"]: + data = ["" if d is None else d for d in data] + + output = self.serialize_data(data, data_type, **kwargs) + if data_type == "bool": + output = json.dumps(output) + except SerializationError as exc: + raise TypeError("{} must be type {}.".format(name, data_type)) from exc + return str(output) + + def serialize_data(self, data, data_type, **kwargs): + """Serialize generic data according to supplied data type. + + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :raises AttributeError: if required data is None. + :raises ValueError: if data is None + :raises SerializationError: if serialization fails. + :returns: The serialized data. + :rtype: str, int, float, bool, dict, list + """ + if data is None: + raise ValueError("No value for given attribute") + + try: + if data is CoreNull: + return None + if data_type in self.basic_types.values(): + return self.serialize_basic(data, data_type, **kwargs) + + if data_type in self.serialize_type: + return self.serialize_type[data_type](data, **kwargs) + + # If dependencies is empty, try with current data class + # It has to be a subclass of Enum anyway + enum_type = self.dependencies.get(data_type, data.__class__) + if issubclass(enum_type, Enum): + return Serializer.serialize_enum(data, enum_obj=enum_type) + + iter_type = data_type[0] + data_type[-1] + if iter_type in self.serialize_type: + return self.serialize_type[iter_type](data, data_type[1:-1], **kwargs) + + except (ValueError, TypeError) as err: + msg = "Unable to serialize value: {!r} as type: {!r}." + raise SerializationError(msg.format(data, data_type)) from err + return self._serialize(data, **kwargs) + + @classmethod + def _get_custom_serializers(cls, data_type, **kwargs): # pylint: disable=inconsistent-return-statements + custom_serializer = kwargs.get("basic_types_serializers", {}).get(data_type) + if custom_serializer: + return custom_serializer + if kwargs.get("is_xml", False): + return cls._xml_basic_types_serializers.get(data_type) + + @classmethod + def serialize_basic(cls, data, data_type, **kwargs): + """Serialize basic builting data type. + Serializes objects to str, int, float or bool. + + Possible kwargs: + - basic_types_serializers dict[str, callable] : If set, use the callable as serializer + - is_xml bool : If set, use xml_basic_types_serializers + + :param obj data: Object to be serialized. + :param str data_type: Type of object in the iterable. + :rtype: str, int, float, bool + :return: serialized object + """ + custom_serializer = cls._get_custom_serializers(data_type, **kwargs) + if custom_serializer: + return custom_serializer(data) + if data_type == "str": + return cls.serialize_unicode(data) + return eval(data_type)(data) # nosec # pylint: disable=eval-used + + @classmethod + def serialize_unicode(cls, data): + """Special handling for serializing unicode strings in Py2. + Encode to UTF-8 if unicode, otherwise handle as a str. + + :param str data: Object to be serialized. + :rtype: str + :return: serialized object + """ + try: # If I received an enum, return its value + return data.value + except AttributeError: + pass + + try: + if isinstance(data, unicode): # type: ignore + # Don't change it, JSON and XML ElementTree are totally able + # to serialize correctly u'' strings + return data + except NameError: + return str(data) + return str(data) + + def serialize_iter(self, data, iter_type, div=None, **kwargs): + """Serialize iterable. + + Supported kwargs: + - serialization_ctxt dict : The current entry of _attribute_map, or same format. + serialization_ctxt['type'] should be same as data_type. + - is_xml bool : If set, serialize as XML + + :param list data: Object to be serialized. + :param str iter_type: Type of object in the iterable. + :param str div: If set, this str will be used to combine the elements + in the iterable into a combined string. Default is 'None'. + Defaults to False. + :rtype: list, str + :return: serialized iterable + """ + if isinstance(data, str): + raise SerializationError("Refuse str type as a valid iter type.") + + serialization_ctxt = kwargs.get("serialization_ctxt", {}) + is_xml = kwargs.get("is_xml", False) + + serialized = [] + for d in data: + try: + serialized.append(self.serialize_data(d, iter_type, **kwargs)) + except ValueError as err: + if isinstance(err, SerializationError): + raise + serialized.append(None) + + if kwargs.get("do_quote", False): + serialized = ["" if s is None else quote(str(s), safe="") for s in serialized] + + if div: + serialized = ["" if s is None else str(s) for s in serialized] + serialized = div.join(serialized) + + if "xml" in serialization_ctxt or is_xml: + # XML serialization is more complicated + xml_desc = serialization_ctxt.get("xml", {}) + xml_name = xml_desc.get("name") + if not xml_name: + xml_name = serialization_ctxt["key"] + + # Create a wrap node if necessary (use the fact that Element and list have "append") + is_wrapped = xml_desc.get("wrapped", False) + node_name = xml_desc.get("itemsName", xml_name) + if is_wrapped: + final_result = _create_xml_node(xml_name, xml_desc.get("prefix", None), xml_desc.get("ns", None)) + else: + final_result = [] + # All list elements to "local_node" + for el in serialized: + if isinstance(el, ET.Element): + el_node = el + else: + el_node = _create_xml_node(node_name, xml_desc.get("prefix", None), xml_desc.get("ns", None)) + if el is not None: # Otherwise it writes "None" :-p + el_node.text = str(el) + final_result.append(el_node) + return final_result + return serialized + + def serialize_dict(self, attr, dict_type, **kwargs): + """Serialize a dictionary of objects. + + :param dict attr: Object to be serialized. + :param str dict_type: Type of object in the dictionary. + :rtype: dict + :return: serialized dictionary + """ + serialization_ctxt = kwargs.get("serialization_ctxt", {}) + serialized = {} + for key, value in attr.items(): + try: + serialized[self.serialize_unicode(key)] = self.serialize_data(value, dict_type, **kwargs) + except ValueError as err: + if isinstance(err, SerializationError): + raise + serialized[self.serialize_unicode(key)] = None + + if "xml" in serialization_ctxt: + # XML serialization is more complicated + xml_desc = serialization_ctxt["xml"] + xml_name = xml_desc["name"] + + final_result = _create_xml_node(xml_name, xml_desc.get("prefix", None), xml_desc.get("ns", None)) + for key, value in serialized.items(): + ET.SubElement(final_result, key).text = value + return final_result + + return serialized + + def serialize_object(self, attr, **kwargs): # pylint: disable=too-many-return-statements + """Serialize a generic object. + This will be handled as a dictionary. If object passed in is not + a basic type (str, int, float, dict, list) it will simply be + cast to str. + + :param dict attr: Object to be serialized. + :rtype: dict or str + :return: serialized object + """ + if attr is None: + return None + if isinstance(attr, ET.Element): + return attr + obj_type = type(attr) + if obj_type in self.basic_types: + return self.serialize_basic(attr, self.basic_types[obj_type], **kwargs) + if obj_type is _long_type: + return self.serialize_long(attr) + if obj_type is str: + return self.serialize_unicode(attr) + if obj_type is datetime.datetime: + return self.serialize_iso(attr) + if obj_type is datetime.date: + return self.serialize_date(attr) + if obj_type is datetime.time: + return self.serialize_time(attr) + if obj_type is datetime.timedelta: + return self.serialize_duration(attr) + if obj_type is decimal.Decimal: + return self.serialize_decimal(attr) + + # If it's a model or I know this dependency, serialize as a Model + if obj_type in self.dependencies.values() or isinstance(attr, Model): + return self._serialize(attr) + + if obj_type == dict: + serialized = {} + for key, value in attr.items(): + try: + serialized[self.serialize_unicode(key)] = self.serialize_object(value, **kwargs) + except ValueError: + serialized[self.serialize_unicode(key)] = None + return serialized + + if obj_type == list: + serialized = [] + for obj in attr: + try: + serialized.append(self.serialize_object(obj, **kwargs)) + except ValueError: + pass + return serialized + return str(attr) + + @staticmethod + def serialize_enum(attr, enum_obj=None): + try: + result = attr.value + except AttributeError: + result = attr + try: + enum_obj(result) # type: ignore + return result + except ValueError as exc: + for enum_value in enum_obj: # type: ignore + if enum_value.value.lower() == str(attr).lower(): + return enum_value.value + error = "{!r} is not valid value for enum {!r}" + raise SerializationError(error.format(attr, enum_obj)) from exc + + @staticmethod + def serialize_bytearray(attr, **kwargs): # pylint: disable=unused-argument + """Serialize bytearray into base-64 string. + + :param str attr: Object to be serialized. + :rtype: str + :return: serialized base64 + """ + return b64encode(attr).decode() + + @staticmethod + def serialize_base64(attr, **kwargs): # pylint: disable=unused-argument + """Serialize str into base-64 string. + + :param str attr: Object to be serialized. + :rtype: str + :return: serialized base64 + """ + encoded = b64encode(attr).decode("ascii") + return encoded.strip("=").replace("+", "-").replace("/", "_") + + @staticmethod + def serialize_decimal(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Decimal object to float. + + :param decimal attr: Object to be serialized. + :rtype: float + :return: serialized decimal + """ + return float(attr) + + @staticmethod + def serialize_long(attr, **kwargs): # pylint: disable=unused-argument + """Serialize long (Py2) or int (Py3). + + :param int attr: Object to be serialized. + :rtype: int/long + :return: serialized long + """ + return _long_type(attr) + + @staticmethod + def serialize_date(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Date object into ISO-8601 formatted string. + + :param Date attr: Object to be serialized. + :rtype: str + :return: serialized date + """ + if isinstance(attr, str): + attr = isodate.parse_date(attr) + t = "{:04}-{:02}-{:02}".format(attr.year, attr.month, attr.day) + return t + + @staticmethod + def serialize_time(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Time object into ISO-8601 formatted string. + + :param datetime.time attr: Object to be serialized. + :rtype: str + :return: serialized time + """ + if isinstance(attr, str): + attr = isodate.parse_time(attr) + t = "{:02}:{:02}:{:02}".format(attr.hour, attr.minute, attr.second) + if attr.microsecond: + t += ".{:02}".format(attr.microsecond) + return t + + @staticmethod + def serialize_duration(attr, **kwargs): # pylint: disable=unused-argument + """Serialize TimeDelta object into ISO-8601 formatted string. + + :param TimeDelta attr: Object to be serialized. + :rtype: str + :return: serialized duration + """ + if isinstance(attr, str): + attr = isodate.parse_duration(attr) + return isodate.duration_isoformat(attr) + + @staticmethod + def serialize_rfc(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Datetime object into RFC-1123 formatted string. + + :param Datetime attr: Object to be serialized. + :rtype: str + :raises TypeError: if format invalid. + :return: serialized rfc + """ + try: + if not attr.tzinfo: + _LOGGER.warning("Datetime with no tzinfo will be considered UTC.") + utc = attr.utctimetuple() + except AttributeError as exc: + raise TypeError("RFC1123 object must be valid Datetime object.") from exc + + return "{}, {:02} {} {:04} {:02}:{:02}:{:02} GMT".format( + Serializer.days[utc.tm_wday], + utc.tm_mday, + Serializer.months[utc.tm_mon], + utc.tm_year, + utc.tm_hour, + utc.tm_min, + utc.tm_sec, + ) + + @staticmethod + def serialize_iso(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Datetime object into ISO-8601 formatted string. + + :param Datetime attr: Object to be serialized. + :rtype: str + :raises SerializationError: if format invalid. + :return: serialized iso + """ + if isinstance(attr, str): + attr = isodate.parse_datetime(attr) + try: + if not attr.tzinfo: + _LOGGER.warning("Datetime with no tzinfo will be considered UTC.") + utc = attr.utctimetuple() + if utc.tm_year > 9999 or utc.tm_year < 1: + raise OverflowError("Hit max or min date") + + microseconds = str(attr.microsecond).rjust(6, "0").rstrip("0").ljust(3, "0") + if microseconds: + microseconds = "." + microseconds + date = "{:04}-{:02}-{:02}T{:02}:{:02}:{:02}".format( + utc.tm_year, utc.tm_mon, utc.tm_mday, utc.tm_hour, utc.tm_min, utc.tm_sec + ) + return date + microseconds + "Z" + except (ValueError, OverflowError) as err: + msg = "Unable to serialize datetime object." + raise SerializationError(msg) from err + except AttributeError as err: + msg = "ISO-8601 object must be valid Datetime object." + raise TypeError(msg) from err + + @staticmethod + def serialize_unix(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Datetime object into IntTime format. + This is represented as seconds. + + :param Datetime attr: Object to be serialized. + :rtype: int + :raises SerializationError: if format invalid + :return: serialied unix + """ + if isinstance(attr, int): + return attr + try: + if not attr.tzinfo: + _LOGGER.warning("Datetime with no tzinfo will be considered UTC.") + return int(calendar.timegm(attr.utctimetuple())) + except AttributeError as exc: + raise TypeError("Unix time object must be valid Datetime object.") from exc + + +def rest_key_extractor(attr, attr_desc, data): # pylint: disable=unused-argument + key = attr_desc["key"] + working_data = data + + while "." in key: + # Need the cast, as for some reasons "split" is typed as list[str | Any] + dict_keys = cast(List[str], _FLATTEN.split(key)) + if len(dict_keys) == 1: + key = _decode_attribute_map_key(dict_keys[0]) + break + working_key = _decode_attribute_map_key(dict_keys[0]) + working_data = working_data.get(working_key, data) + if working_data is None: + # If at any point while following flatten JSON path see None, it means + # that all properties under are None as well + return None + key = ".".join(dict_keys[1:]) + + return working_data.get(key) + + +def rest_key_case_insensitive_extractor( # pylint: disable=unused-argument, inconsistent-return-statements + attr, attr_desc, data +): + key = attr_desc["key"] + working_data = data + + while "." in key: + dict_keys = _FLATTEN.split(key) + if len(dict_keys) == 1: + key = _decode_attribute_map_key(dict_keys[0]) + break + working_key = _decode_attribute_map_key(dict_keys[0]) + working_data = attribute_key_case_insensitive_extractor(working_key, None, working_data) + if working_data is None: + # If at any point while following flatten JSON path see None, it means + # that all properties under are None as well + return None + key = ".".join(dict_keys[1:]) + + if working_data: + return attribute_key_case_insensitive_extractor(key, None, working_data) + + +def last_rest_key_extractor(attr, attr_desc, data): # pylint: disable=unused-argument + """Extract the attribute in "data" based on the last part of the JSON path key. + + :param str attr: The attribute to extract + :param dict attr_desc: The attribute description + :param dict data: The data to extract from + :rtype: object + :returns: The extracted attribute + """ + key = attr_desc["key"] + dict_keys = _FLATTEN.split(key) + return attribute_key_extractor(dict_keys[-1], None, data) + + +def last_rest_key_case_insensitive_extractor(attr, attr_desc, data): # pylint: disable=unused-argument + """Extract the attribute in "data" based on the last part of the JSON path key. + + This is the case insensitive version of "last_rest_key_extractor" + :param str attr: The attribute to extract + :param dict attr_desc: The attribute description + :param dict data: The data to extract from + :rtype: object + :returns: The extracted attribute + """ + key = attr_desc["key"] + dict_keys = _FLATTEN.split(key) + return attribute_key_case_insensitive_extractor(dict_keys[-1], None, data) + + +def attribute_key_extractor(attr, _, data): + return data.get(attr) + + +def attribute_key_case_insensitive_extractor(attr, _, data): + found_key = None + lower_attr = attr.lower() + for key in data: + if lower_attr == key.lower(): + found_key = key + break + + return data.get(found_key) + + +def _extract_name_from_internal_type(internal_type): + """Given an internal type XML description, extract correct XML name with namespace. + + :param dict internal_type: An model type + :rtype: tuple + :returns: A tuple XML name + namespace dict + """ + internal_type_xml_map = getattr(internal_type, "_xml_map", {}) + xml_name = internal_type_xml_map.get("name", internal_type.__name__) + xml_ns = internal_type_xml_map.get("ns", None) + if xml_ns: + xml_name = "{{{}}}{}".format(xml_ns, xml_name) + return xml_name + + +def xml_key_extractor(attr, attr_desc, data): # pylint: disable=unused-argument,too-many-return-statements + if isinstance(data, dict): + return None + + # Test if this model is XML ready first + if not isinstance(data, ET.Element): + return None + + xml_desc = attr_desc.get("xml", {}) + xml_name = xml_desc.get("name", attr_desc["key"]) + + # Look for a children + is_iter_type = attr_desc["type"].startswith("[") + is_wrapped = xml_desc.get("wrapped", False) + internal_type = attr_desc.get("internalType", None) + internal_type_xml_map = getattr(internal_type, "_xml_map", {}) + + # Integrate namespace if necessary + xml_ns = xml_desc.get("ns", internal_type_xml_map.get("ns", None)) + if xml_ns: + xml_name = "{{{}}}{}".format(xml_ns, xml_name) + + # If it's an attribute, that's simple + if xml_desc.get("attr", False): + return data.get(xml_name) + + # If it's x-ms-text, that's simple too + if xml_desc.get("text", False): + return data.text + + # Scenario where I take the local name: + # - Wrapped node + # - Internal type is an enum (considered basic types) + # - Internal type has no XML/Name node + if is_wrapped or (internal_type and (issubclass(internal_type, Enum) or "name" not in internal_type_xml_map)): + children = data.findall(xml_name) + # If internal type has a local name and it's not a list, I use that name + elif not is_iter_type and internal_type and "name" in internal_type_xml_map: + xml_name = _extract_name_from_internal_type(internal_type) + children = data.findall(xml_name) + # That's an array + else: + if internal_type: # Complex type, ignore itemsName and use the complex type name + items_name = _extract_name_from_internal_type(internal_type) + else: + items_name = xml_desc.get("itemsName", xml_name) + children = data.findall(items_name) + + if len(children) == 0: + if is_iter_type: + if is_wrapped: + return None # is_wrapped no node, we want None + return [] # not wrapped, assume empty list + return None # Assume it's not there, maybe an optional node. + + # If is_iter_type and not wrapped, return all found children + if is_iter_type: + if not is_wrapped: + return children + # Iter and wrapped, should have found one node only (the wrap one) + if len(children) != 1: + raise DeserializationError( + "Tried to deserialize an array not wrapped, and found several nodes '{}'. Maybe you should declare this array as wrapped?".format( + xml_name + ) + ) + return list(children[0]) # Might be empty list and that's ok. + + # Here it's not a itertype, we should have found one element only or empty + if len(children) > 1: + raise DeserializationError("Find several XML '{}' where it was not expected".format(xml_name)) + return children[0] + + +class Deserializer: + """Response object model deserializer. + + :param dict classes: Class type dictionary for deserializing complex types. + :ivar list key_extractors: Ordered list of extractors to be used by this deserializer. + """ + + basic_types = {str: "str", int: "int", bool: "bool", float: "float"} + + valid_date = re.compile(r"\d{4}[-]\d{2}[-]\d{2}T\d{2}:\d{2}:\d{2}\.?\d*Z?[-+]?[\d{2}]?:?[\d{2}]?") + + def __init__(self, classes: Optional[Mapping[str, type]] = None) -> None: + self.deserialize_type = { + "iso-8601": Deserializer.deserialize_iso, + "rfc-1123": Deserializer.deserialize_rfc, + "unix-time": Deserializer.deserialize_unix, + "duration": Deserializer.deserialize_duration, + "date": Deserializer.deserialize_date, + "time": Deserializer.deserialize_time, + "decimal": Deserializer.deserialize_decimal, + "long": Deserializer.deserialize_long, + "bytearray": Deserializer.deserialize_bytearray, + "base64": Deserializer.deserialize_base64, + "object": self.deserialize_object, + "[]": self.deserialize_iter, + "{}": self.deserialize_dict, + } + self.deserialize_expected_types = { + "duration": (isodate.Duration, datetime.timedelta), + "iso-8601": (datetime.datetime), + } + self.dependencies: Dict[str, type] = dict(classes) if classes else {} + self.key_extractors = [rest_key_extractor, xml_key_extractor] + # Additional properties only works if the "rest_key_extractor" is used to + # extract the keys. Making it to work whatever the key extractor is too much + # complicated, with no real scenario for now. + # So adding a flag to disable additional properties detection. This flag should be + # used if your expect the deserialization to NOT come from a JSON REST syntax. + # Otherwise, result are unexpected + self.additional_properties_detection = True + + def __call__(self, target_obj, response_data, content_type=None): + """Call the deserializer to process a REST response. + + :param str target_obj: Target data type to deserialize to. + :param requests.Response response_data: REST response object. + :param str content_type: Swagger "produces" if available. + :raises DeserializationError: if deserialization fails. + :return: Deserialized object. + :rtype: object + """ + data = self._unpack_content(response_data, content_type) + return self._deserialize(target_obj, data) + + def _deserialize(self, target_obj, data): # pylint: disable=inconsistent-return-statements + """Call the deserializer on a model. + + Data needs to be already deserialized as JSON or XML ElementTree + + :param str target_obj: Target data type to deserialize to. + :param object data: Object to deserialize. + :raises DeserializationError: if deserialization fails. + :return: Deserialized object. + :rtype: object + """ + # This is already a model, go recursive just in case + if hasattr(data, "_attribute_map"): + constants = [name for name, config in getattr(data, "_validation", {}).items() if config.get("constant")] + try: + for attr, mapconfig in data._attribute_map.items(): # pylint: disable=protected-access + if attr in constants: + continue + value = getattr(data, attr) + if value is None: + continue + local_type = mapconfig["type"] + internal_data_type = local_type.strip("[]{}") + if internal_data_type not in self.dependencies or isinstance(internal_data_type, Enum): + continue + setattr(data, attr, self._deserialize(local_type, value)) + return data + except AttributeError: + return + + response, class_name = self._classify_target(target_obj, data) + + if isinstance(response, str): + return self.deserialize_data(data, response) + if isinstance(response, type) and issubclass(response, Enum): + return self.deserialize_enum(data, response) + + if data is None or data is CoreNull: + return data + try: + attributes = response._attribute_map # type: ignore # pylint: disable=protected-access + d_attrs = {} + for attr, attr_desc in attributes.items(): + # Check empty string. If it's not empty, someone has a real "additionalProperties"... + if attr == "additional_properties" and attr_desc["key"] == "": + continue + raw_value = None + # Enhance attr_desc with some dynamic data + attr_desc = attr_desc.copy() # Do a copy, do not change the real one + internal_data_type = attr_desc["type"].strip("[]{}") + if internal_data_type in self.dependencies: + attr_desc["internalType"] = self.dependencies[internal_data_type] + + for key_extractor in self.key_extractors: + found_value = key_extractor(attr, attr_desc, data) + if found_value is not None: + if raw_value is not None and raw_value != found_value: + msg = ( + "Ignoring extracted value '%s' from %s for key '%s'" + " (duplicate extraction, follow extractors order)" + ) + _LOGGER.warning(msg, found_value, key_extractor, attr) + continue + raw_value = found_value + + value = self.deserialize_data(raw_value, attr_desc["type"]) + d_attrs[attr] = value + except (AttributeError, TypeError, KeyError) as err: + msg = "Unable to deserialize to object: " + class_name # type: ignore + raise DeserializationError(msg) from err + additional_properties = self._build_additional_properties(attributes, data) + return self._instantiate_model(response, d_attrs, additional_properties) + + def _build_additional_properties(self, attribute_map, data): + if not self.additional_properties_detection: + return None + if "additional_properties" in attribute_map and attribute_map.get("additional_properties", {}).get("key") != "": + # Check empty string. If it's not empty, someone has a real "additionalProperties" + return None + if isinstance(data, ET.Element): + data = {el.tag: el.text for el in data} + + known_keys = { + _decode_attribute_map_key(_FLATTEN.split(desc["key"])[0]) + for desc in attribute_map.values() + if desc["key"] != "" + } + present_keys = set(data.keys()) + missing_keys = present_keys - known_keys + return {key: data[key] for key in missing_keys} + + def _classify_target(self, target, data): + """Check to see whether the deserialization target object can + be classified into a subclass. + Once classification has been determined, initialize object. + + :param str target: The target object type to deserialize to. + :param str/dict data: The response data to deserialize. + :return: The classified target object and its class name. + :rtype: tuple + """ + if target is None: + return None, None + + if isinstance(target, str): + try: + target = self.dependencies[target] + except KeyError: + return target, target + + try: + target = target._classify(data, self.dependencies) # type: ignore # pylint: disable=protected-access + except AttributeError: + pass # Target is not a Model, no classify + return target, target.__class__.__name__ # type: ignore + + def failsafe_deserialize(self, target_obj, data, content_type=None): + """Ignores any errors encountered in deserialization, + and falls back to not deserializing the object. Recommended + for use in error deserialization, as we want to return the + HttpResponseError to users, and not have them deal with + a deserialization error. + + :param str target_obj: The target object type to deserialize to. + :param str/dict data: The response data to deserialize. + :param str content_type: Swagger "produces" if available. + :return: Deserialized object. + :rtype: object + """ + try: + return self(target_obj, data, content_type=content_type) + except: # pylint: disable=bare-except + _LOGGER.debug( + "Ran into a deserialization error. Ignoring since this is failsafe deserialization", exc_info=True + ) + return None + + @staticmethod + def _unpack_content(raw_data, content_type=None): + """Extract the correct structure for deserialization. + + If raw_data is a PipelineResponse, try to extract the result of RawDeserializer. + if we can't, raise. Your Pipeline should have a RawDeserializer. + + If not a pipeline response and raw_data is bytes or string, use content-type + to decode it. If no content-type, try JSON. + + If raw_data is something else, bypass all logic and return it directly. + + :param obj raw_data: Data to be processed. + :param str content_type: How to parse if raw_data is a string/bytes. + :raises JSONDecodeError: If JSON is requested and parsing is impossible. + :raises UnicodeDecodeError: If bytes is not UTF8 + :rtype: object + :return: Unpacked content. + """ + # Assume this is enough to detect a Pipeline Response without importing it + context = getattr(raw_data, "context", {}) + if context: + if RawDeserializer.CONTEXT_NAME in context: + return context[RawDeserializer.CONTEXT_NAME] + raise ValueError("This pipeline didn't have the RawDeserializer policy; can't deserialize") + + # Assume this is enough to recognize universal_http.ClientResponse without importing it + if hasattr(raw_data, "body"): + return RawDeserializer.deserialize_from_http_generics(raw_data.text(), raw_data.headers) + + # Assume this enough to recognize requests.Response without importing it. + if hasattr(raw_data, "_content_consumed"): + return RawDeserializer.deserialize_from_http_generics(raw_data.text, raw_data.headers) + + if isinstance(raw_data, (str, bytes)) or hasattr(raw_data, "read"): + return RawDeserializer.deserialize_from_text(raw_data, content_type) # type: ignore + return raw_data + + def _instantiate_model(self, response, attrs, additional_properties=None): + """Instantiate a response model passing in deserialized args. + + :param Response response: The response model class. + :param dict attrs: The deserialized response attributes. + :param dict additional_properties: Additional properties to be set. + :rtype: Response + :return: The instantiated response model. + """ + if callable(response): + subtype = getattr(response, "_subtype_map", {}) + try: + readonly = [ + k + for k, v in response._validation.items() # pylint: disable=protected-access # type: ignore + if v.get("readonly") + ] + const = [ + k + for k, v in response._validation.items() # pylint: disable=protected-access # type: ignore + if v.get("constant") + ] + kwargs = {k: v for k, v in attrs.items() if k not in subtype and k not in readonly + const} + response_obj = response(**kwargs) + for attr in readonly: + setattr(response_obj, attr, attrs.get(attr)) + if additional_properties: + response_obj.additional_properties = additional_properties # type: ignore + return response_obj + except TypeError as err: + msg = "Unable to deserialize {} into model {}. ".format(kwargs, response) # type: ignore + raise DeserializationError(msg + str(err)) from err + else: + try: + for attr, value in attrs.items(): + setattr(response, attr, value) + return response + except Exception as exp: + msg = "Unable to populate response model. " + msg += "Type: {}, Error: {}".format(type(response), exp) + raise DeserializationError(msg) from exp + + def deserialize_data(self, data, data_type): # pylint: disable=too-many-return-statements + """Process data for deserialization according to data type. + + :param str data: The response string to be deserialized. + :param str data_type: The type to deserialize to. + :raises DeserializationError: if deserialization fails. + :return: Deserialized object. + :rtype: object + """ + if data is None: + return data + + try: + if not data_type: + return data + if data_type in self.basic_types.values(): + return self.deserialize_basic(data, data_type) + if data_type in self.deserialize_type: + if isinstance(data, self.deserialize_expected_types.get(data_type, tuple())): + return data + + is_a_text_parsing_type = lambda x: x not in [ # pylint: disable=unnecessary-lambda-assignment + "object", + "[]", + r"{}", + ] + if isinstance(data, ET.Element) and is_a_text_parsing_type(data_type) and not data.text: + return None + data_val = self.deserialize_type[data_type](data) + return data_val + + iter_type = data_type[0] + data_type[-1] + if iter_type in self.deserialize_type: + return self.deserialize_type[iter_type](data, data_type[1:-1]) + + obj_type = self.dependencies[data_type] + if issubclass(obj_type, Enum): + if isinstance(data, ET.Element): + data = data.text + return self.deserialize_enum(data, obj_type) + + except (ValueError, TypeError, AttributeError) as err: + msg = "Unable to deserialize response data." + msg += " Data: {}, {}".format(data, data_type) + raise DeserializationError(msg) from err + return self._deserialize(obj_type, data) + + def deserialize_iter(self, attr, iter_type): + """Deserialize an iterable. + + :param list attr: Iterable to be deserialized. + :param str iter_type: The type of object in the iterable. + :return: Deserialized iterable. + :rtype: list + """ + if attr is None: + return None + if isinstance(attr, ET.Element): # If I receive an element here, get the children + attr = list(attr) + if not isinstance(attr, (list, set)): + raise DeserializationError("Cannot deserialize as [{}] an object of type {}".format(iter_type, type(attr))) + return [self.deserialize_data(a, iter_type) for a in attr] + + def deserialize_dict(self, attr, dict_type): + """Deserialize a dictionary. + + :param dict/list attr: Dictionary to be deserialized. Also accepts + a list of key, value pairs. + :param str dict_type: The object type of the items in the dictionary. + :return: Deserialized dictionary. + :rtype: dict + """ + if isinstance(attr, list): + return {x["key"]: self.deserialize_data(x["value"], dict_type) for x in attr} + + if isinstance(attr, ET.Element): + # Transform value into {"Key": "value"} + attr = {el.tag: el.text for el in attr} + return {k: self.deserialize_data(v, dict_type) for k, v in attr.items()} + + def deserialize_object(self, attr, **kwargs): # pylint: disable=too-many-return-statements + """Deserialize a generic object. + This will be handled as a dictionary. + + :param dict attr: Dictionary to be deserialized. + :return: Deserialized object. + :rtype: dict + :raises TypeError: if non-builtin datatype encountered. + """ + if attr is None: + return None + if isinstance(attr, ET.Element): + # Do no recurse on XML, just return the tree as-is + return attr + if isinstance(attr, str): + return self.deserialize_basic(attr, "str") + obj_type = type(attr) + if obj_type in self.basic_types: + return self.deserialize_basic(attr, self.basic_types[obj_type]) + if obj_type is _long_type: + return self.deserialize_long(attr) + + if obj_type == dict: + deserialized = {} + for key, value in attr.items(): + try: + deserialized[key] = self.deserialize_object(value, **kwargs) + except ValueError: + deserialized[key] = None + return deserialized + + if obj_type == list: + deserialized = [] + for obj in attr: + try: + deserialized.append(self.deserialize_object(obj, **kwargs)) + except ValueError: + pass + return deserialized + + error = "Cannot deserialize generic object with type: " + raise TypeError(error + str(obj_type)) + + def deserialize_basic(self, attr, data_type): # pylint: disable=too-many-return-statements + """Deserialize basic builtin data type from string. + Will attempt to convert to str, int, float and bool. + This function will also accept '1', '0', 'true' and 'false' as + valid bool values. + + :param str attr: response string to be deserialized. + :param str data_type: deserialization data type. + :return: Deserialized basic type. + :rtype: str, int, float or bool + :raises TypeError: if string format is not valid. + """ + # If we're here, data is supposed to be a basic type. + # If it's still an XML node, take the text + if isinstance(attr, ET.Element): + attr = attr.text + if not attr: + if data_type == "str": + # None or '', node is empty string. + return "" + # None or '', node with a strong type is None. + # Don't try to model "empty bool" or "empty int" + return None + + if data_type == "bool": + if attr in [True, False, 1, 0]: + return bool(attr) + if isinstance(attr, str): + if attr.lower() in ["true", "1"]: + return True + if attr.lower() in ["false", "0"]: + return False + raise TypeError("Invalid boolean value: {}".format(attr)) + + if data_type == "str": + return self.deserialize_unicode(attr) + return eval(data_type)(attr) # nosec # pylint: disable=eval-used + + @staticmethod + def deserialize_unicode(data): + """Preserve unicode objects in Python 2, otherwise return data + as a string. + + :param str data: response string to be deserialized. + :return: Deserialized string. + :rtype: str or unicode + """ + # We might be here because we have an enum modeled as string, + # and we try to deserialize a partial dict with enum inside + if isinstance(data, Enum): + return data + + # Consider this is real string + try: + if isinstance(data, unicode): # type: ignore + return data + except NameError: + return str(data) + return str(data) + + @staticmethod + def deserialize_enum(data, enum_obj): + """Deserialize string into enum object. + + If the string is not a valid enum value it will be returned as-is + and a warning will be logged. + + :param str data: Response string to be deserialized. If this value is + None or invalid it will be returned as-is. + :param Enum enum_obj: Enum object to deserialize to. + :return: Deserialized enum object. + :rtype: Enum + """ + if isinstance(data, enum_obj) or data is None: + return data + if isinstance(data, Enum): + data = data.value + if isinstance(data, int): + # Workaround. We might consider remove it in the future. + try: + return list(enum_obj.__members__.values())[data] + except IndexError as exc: + error = "{!r} is not a valid index for enum {!r}" + raise DeserializationError(error.format(data, enum_obj)) from exc + try: + return enum_obj(str(data)) + except ValueError: + for enum_value in enum_obj: + if enum_value.value.lower() == str(data).lower(): + return enum_value + # We don't fail anymore for unknown value, we deserialize as a string + _LOGGER.warning("Deserializer is not able to find %s as valid enum in %s", data, enum_obj) + return Deserializer.deserialize_unicode(data) + + @staticmethod + def deserialize_bytearray(attr): + """Deserialize string into bytearray. + + :param str attr: response string to be deserialized. + :return: Deserialized bytearray + :rtype: bytearray + :raises TypeError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + return bytearray(b64decode(attr)) # type: ignore + + @staticmethod + def deserialize_base64(attr): + """Deserialize base64 encoded string into string. + + :param str attr: response string to be deserialized. + :return: Deserialized base64 string + :rtype: bytearray + :raises TypeError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + padding = "=" * (3 - (len(attr) + 3) % 4) # type: ignore + attr = attr + padding # type: ignore + encoded = attr.replace("-", "+").replace("_", "/") + return b64decode(encoded) + + @staticmethod + def deserialize_decimal(attr): + """Deserialize string into Decimal object. + + :param str attr: response string to be deserialized. + :return: Deserialized decimal + :raises DeserializationError: if string format invalid. + :rtype: decimal + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + return decimal.Decimal(str(attr)) # type: ignore + except decimal.DecimalException as err: + msg = "Invalid decimal {}".format(attr) + raise DeserializationError(msg) from err + + @staticmethod + def deserialize_long(attr): + """Deserialize string into long (Py2) or int (Py3). + + :param str attr: response string to be deserialized. + :return: Deserialized int + :rtype: long or int + :raises ValueError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + return _long_type(attr) # type: ignore + + @staticmethod + def deserialize_duration(attr): + """Deserialize ISO-8601 formatted string into TimeDelta object. + + :param str attr: response string to be deserialized. + :return: Deserialized duration + :rtype: TimeDelta + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + duration = isodate.parse_duration(attr) + except (ValueError, OverflowError, AttributeError) as err: + msg = "Cannot deserialize duration object." + raise DeserializationError(msg) from err + return duration + + @staticmethod + def deserialize_date(attr): + """Deserialize ISO-8601 formatted string into Date object. + + :param str attr: response string to be deserialized. + :return: Deserialized date + :rtype: Date + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + if re.search(r"[^\W\d_]", attr, re.I + re.U): # type: ignore + raise DeserializationError("Date must have only digits and -. Received: %s" % attr) + # This must NOT use defaultmonth/defaultday. Using None ensure this raises an exception. + return isodate.parse_date(attr, defaultmonth=0, defaultday=0) + + @staticmethod + def deserialize_time(attr): + """Deserialize ISO-8601 formatted string into time object. + + :param str attr: response string to be deserialized. + :return: Deserialized time + :rtype: datetime.time + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + if re.search(r"[^\W\d_]", attr, re.I + re.U): # type: ignore + raise DeserializationError("Date must have only digits and -. Received: %s" % attr) + return isodate.parse_time(attr) + + @staticmethod + def deserialize_rfc(attr): + """Deserialize RFC-1123 formatted string into Datetime object. + + :param str attr: response string to be deserialized. + :return: Deserialized RFC datetime + :rtype: Datetime + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + parsed_date = email.utils.parsedate_tz(attr) # type: ignore + date_obj = datetime.datetime( + *parsed_date[:6], tzinfo=datetime.timezone(datetime.timedelta(minutes=(parsed_date[9] or 0) / 60)) + ) + if not date_obj.tzinfo: + date_obj = date_obj.astimezone(tz=TZ_UTC) + except ValueError as err: + msg = "Cannot deserialize to rfc datetime object." + raise DeserializationError(msg) from err + return date_obj + + @staticmethod + def deserialize_iso(attr): + """Deserialize ISO-8601 formatted string into Datetime object. + + :param str attr: response string to be deserialized. + :return: Deserialized ISO datetime + :rtype: Datetime + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + attr = attr.upper() # type: ignore + match = Deserializer.valid_date.match(attr) + if not match: + raise ValueError("Invalid datetime string: " + attr) + + check_decimal = attr.split(".") + if len(check_decimal) > 1: + decimal_str = "" + for digit in check_decimal[1]: + if digit.isdigit(): + decimal_str += digit + else: + break + if len(decimal_str) > 6: + attr = attr.replace(decimal_str, decimal_str[0:6]) + + date_obj = isodate.parse_datetime(attr) + test_utc = date_obj.utctimetuple() + if test_utc.tm_year > 9999 or test_utc.tm_year < 1: + raise OverflowError("Hit max or min date") + except (ValueError, OverflowError, AttributeError) as err: + msg = "Cannot deserialize datetime object." + raise DeserializationError(msg) from err + return date_obj + + @staticmethod + def deserialize_unix(attr): + """Serialize Datetime object into IntTime format. + This is represented as seconds. + + :param int attr: Object to be serialized. + :return: Deserialized datetime + :rtype: Datetime + :raises DeserializationError: if format invalid + """ + if isinstance(attr, ET.Element): + attr = int(attr.text) # type: ignore + try: + attr = int(attr) + date_obj = datetime.datetime.fromtimestamp(attr, TZ_UTC) + except ValueError as err: + msg = "Cannot deserialize to unix datetime object." + raise DeserializationError(msg) from err + return date_obj diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiDataPlane/multiapidataplane/aio/_multiapi_service_client.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiDataPlane/multiapidataplane/aio/_multiapi_service_client.py index c8ec3590978..9b14c3dc97f 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiDataPlane/multiapidataplane/aio/_multiapi_service_client.py +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiDataPlane/multiapidataplane/aio/_multiapi_service_client.py @@ -17,7 +17,7 @@ from azure.profiles import KnownProfiles, ProfileDefinition from azure.profiles.multiapiclient import MultiApiClientMixin -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import MultiapiServiceClientConfiguration from ._operations_mixin import MultiapiServiceClientOperationsMixin diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiDataPlane/multiapidataplane/aio/_operations_mixin.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiDataPlane/multiapidataplane/aio/_operations_mixin.py index e8b708ca879..254843ab360 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiDataPlane/multiapidataplane/aio/_operations_mixin.py +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiDataPlane/multiapidataplane/aio/_operations_mixin.py @@ -8,7 +8,7 @@ # Changes may cause incorrect behavior and will be lost if the code is # regenerated. # -------------------------------------------------------------------------- -from .._serialization import Serializer, Deserializer +from .._utils.serialization import Serializer, Deserializer from io import IOBase from typing import Any, AsyncIterable, AsyncIterator, IO, Optional, Union diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiDataPlane/multiapidataplane/v1/_metadata.json b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiDataPlane/multiapidataplane/v1/_metadata.json index dc85166c75a..09140c7930b 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiDataPlane/multiapidataplane/v1/_metadata.json +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiDataPlane/multiapidataplane/v1/_metadata.json @@ -10,8 +10,8 @@ "azure_arm": false, "has_public_lro_operations": true, "client_side_validation": false, - "sync_imports": "{\"conditional\": {\"stdlib\": {\"typing\": [\"Any\", \"Optional\"]}}, \"regular\": {\"sdkcore\": {\"azure.core\": [\"PipelineClient\"], \"azure.core.pipeline\": [\"policies\"], \"azure.profiles\": [\"KnownProfiles\", \"ProfileDefinition\"], \"azure.profiles.multiapiclient\": [\"MultiApiClientMixin\"]}, \"local\": {\"._configuration\": [\"MultiapiServiceClientConfiguration\"], \".._serialization\": [\"Deserializer\", \"Serializer\"], \"._operations_mixin\": [\"MultiapiServiceClientOperationsMixin\"]}, \"stdlib\": {\"typing_extensions\": [\"Self\"]}}, \"typing\": {\"sdkcore\": {\"azure.core.credentials\": [\"TokenCredential\"]}}}", - "async_imports": "{\"conditional\": {\"stdlib\": {\"typing\": [\"Any\", \"Optional\"]}}, \"regular\": {\"sdkcore\": {\"azure.core\": [\"AsyncPipelineClient\"], \"azure.core.pipeline\": [\"policies\"], \"azure.profiles\": [\"KnownProfiles\", \"ProfileDefinition\"], \"azure.profiles.multiapiclient\": [\"MultiApiClientMixin\"]}, \"local\": {\"._configuration\": [\"MultiapiServiceClientConfiguration\"], \"..._serialization\": [\"Deserializer\", \"Serializer\"], \"._operations_mixin\": [\"MultiapiServiceClientOperationsMixin\"]}, \"stdlib\": {\"typing_extensions\": [\"Self\"]}}, \"typing\": {\"sdkcore\": {\"azure.core.credentials_async\": [\"AsyncTokenCredential\"]}}}" + "sync_imports": "{\"conditional\": {\"stdlib\": {\"typing\": [\"Any\", \"Optional\"]}}, \"regular\": {\"sdkcore\": {\"azure.core\": [\"PipelineClient\"], \"azure.core.pipeline\": [\"policies\"], \"azure.profiles\": [\"KnownProfiles\", \"ProfileDefinition\"], \"azure.profiles.multiapiclient\": [\"MultiApiClientMixin\"]}, \"local\": {\"._configuration\": [\"MultiapiServiceClientConfiguration\"], \"._utils.serialization\": [\"Deserializer\", \"Serializer\"], \"._operations_mixin\": [\"MultiapiServiceClientOperationsMixin\"]}, \"stdlib\": {\"typing_extensions\": [\"Self\"]}}, \"typing\": {\"sdkcore\": {\"azure.core.credentials\": [\"TokenCredential\"]}}}", + "async_imports": "{\"conditional\": {\"stdlib\": {\"typing\": [\"Any\", \"Optional\"]}}, \"regular\": {\"sdkcore\": {\"azure.core\": [\"AsyncPipelineClient\"], \"azure.core.pipeline\": [\"policies\"], \"azure.profiles\": [\"KnownProfiles\", \"ProfileDefinition\"], \"azure.profiles.multiapiclient\": [\"MultiApiClientMixin\"]}, \"local\": {\"._configuration\": [\"MultiapiServiceClientConfiguration\"], \".._utils.serialization\": [\"Deserializer\", \"Serializer\"], \"._operations_mixin\": [\"MultiapiServiceClientOperationsMixin\"]}, \"stdlib\": {\"typing_extensions\": [\"Self\"]}}, \"typing\": {\"sdkcore\": {\"azure.core.credentials_async\": [\"AsyncTokenCredential\"]}}}" }, "global_parameters": { "sync": { diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiDataPlane/multiapidataplane/v1/_multiapi_service_client.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiDataPlane/multiapidataplane/v1/_multiapi_service_client.py index 745909ae315..1b29166016c 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiDataPlane/multiapidataplane/v1/_multiapi_service_client.py +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiDataPlane/multiapidataplane/v1/_multiapi_service_client.py @@ -15,8 +15,8 @@ from azure.core.rest import HttpRequest, HttpResponse from . import models as _models -from .._serialization import Deserializer, Serializer from ._configuration import MultiapiServiceClientConfiguration +from ._utils.serialization import Deserializer, Serializer from .operations import MultiapiServiceClientOperationsMixin, OperationGroupOneOperations if TYPE_CHECKING: diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiDataPlane/multiapidataplane/v1/_utils/__init__.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiDataPlane/multiapidataplane/v1/_utils/__init__.py new file mode 100644 index 00000000000..0af9b28f660 --- /dev/null +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiDataPlane/multiapidataplane/v1/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/CustomBaseUriMoreOptions/custombaseurlmoreoptions/_serialization.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiDataPlane/multiapidataplane/v1/_utils/serialization.py similarity index 100% rename from packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/CustomBaseUriMoreOptions/custombaseurlmoreoptions/_serialization.py rename to packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiDataPlane/multiapidataplane/v1/_utils/serialization.py diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiDataPlane/multiapidataplane/v1/_utils/utils.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiDataPlane/multiapidataplane/v1/_utils/utils.py new file mode 100644 index 00000000000..39b612f39a9 --- /dev/null +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiDataPlane/multiapidataplane/v1/_utils/utils.py @@ -0,0 +1,25 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from abc import ABC +from typing import Generic, TYPE_CHECKING, TypeVar + +if TYPE_CHECKING: + from .serialization import Deserializer, Serializer + + +TClient = TypeVar("TClient") +TConfig = TypeVar("TConfig") + + +class ClientMixinABC(ABC, Generic[TClient, TConfig]): + """DO NOT use this class. It is for internal typing use only.""" + + _client: TClient + _config: TConfig + _serialize: "Serializer" + _deserialize: "Deserializer" diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiDataPlane/multiapidataplane/v1/_vendor.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiDataPlane/multiapidataplane/v1/_vendor.py deleted file mode 100644 index 70517e0b7af..00000000000 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiDataPlane/multiapidataplane/v1/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) AutoRest Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import MultiapiServiceClientConfiguration - -if TYPE_CHECKING: - from azure.core import PipelineClient - - from .._serialization import Deserializer, Serializer - - -class MultiapiServiceClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "PipelineClient" - _config: MultiapiServiceClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiDataPlane/multiapidataplane/v1/aio/_multiapi_service_client.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiDataPlane/multiapidataplane/v1/aio/_multiapi_service_client.py index fa594eb8b02..15f862472f8 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiDataPlane/multiapidataplane/v1/aio/_multiapi_service_client.py +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiDataPlane/multiapidataplane/v1/aio/_multiapi_service_client.py @@ -15,7 +15,7 @@ from azure.core.rest import AsyncHttpResponse, HttpRequest from .. import models as _models -from ..._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import MultiapiServiceClientConfiguration from .operations import MultiapiServiceClientOperationsMixin, OperationGroupOneOperations diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiDataPlane/multiapidataplane/v1/aio/_vendor.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiDataPlane/multiapidataplane/v1/aio/_vendor.py deleted file mode 100644 index 9c6fd05bb21..00000000000 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiDataPlane/multiapidataplane/v1/aio/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) AutoRest Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import MultiapiServiceClientConfiguration - -if TYPE_CHECKING: - from azure.core import AsyncPipelineClient - - from ..._serialization import Deserializer, Serializer - - -class MultiapiServiceClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "AsyncPipelineClient" - _config: MultiapiServiceClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiDataPlane/multiapidataplane/v1/aio/operations/_multiapi_service_client_operations.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiDataPlane/multiapidataplane/v1/aio/operations/_multiapi_service_client_operations.py index 4eb6a158b43..85c879f27a4 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiDataPlane/multiapidataplane/v1/aio/operations/_multiapi_service_client_operations.py +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiDataPlane/multiapidataplane/v1/aio/operations/_multiapi_service_client_operations.py @@ -11,6 +11,7 @@ from typing import Any, AsyncIterable, AsyncIterator, Callable, Dict, IO, Optional, TypeVar, Union, cast, overload import urllib.parse +from azure.core import AsyncPipelineClient from azure.core.async_paging import AsyncItemPaged, AsyncList from azure.core.exceptions import ( ClientAuthenticationError, @@ -31,19 +32,20 @@ from azure.core.utils import case_insensitive_dict from ... import models as _models +from ..._utils.utils import ClientMixinABC from ...operations._multiapi_service_client_operations import ( build_test_different_calls_request, build_test_lro_and_paging_request, build_test_lro_request, build_test_one_request, ) -from .._vendor import MultiapiServiceClientMixinABC +from .._configuration import MultiapiServiceClientConfiguration T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, AsyncHttpResponse], T, Dict[str, Any]], Any]] -class MultiapiServiceClientOperationsMixin(MultiapiServiceClientMixinABC): +class MultiapiServiceClientOperationsMixin(ClientMixinABC[AsyncPipelineClient, MultiapiServiceClientConfiguration]): def _api_version(self, op_name: str) -> str: # pylint: disable=unused-argument try: return self._config.api_version diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiDataPlane/multiapidataplane/v1/aio/operations/_operation_group_one_operations.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiDataPlane/multiapidataplane/v1/aio/operations/_operation_group_one_operations.py index 41de30f74c5..6e85a1463fa 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiDataPlane/multiapidataplane/v1/aio/operations/_operation_group_one_operations.py +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiDataPlane/multiapidataplane/v1/aio/operations/_operation_group_one_operations.py @@ -23,7 +23,7 @@ from azure.core.utils import case_insensitive_dict from ... import models as _models -from ...._serialization import Deserializer, Serializer +from ..._utils.serialization import Deserializer, Serializer from ...operations._operation_group_one_operations import build_test_two_request from .._configuration import MultiapiServiceClientConfiguration diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiDataPlane/multiapidataplane/v1/models/_models_py3.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiDataPlane/multiapidataplane/v1/models/_models_py3.py index 918a39761c2..e51da879214 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiDataPlane/multiapidataplane/v1/models/_models_py3.py +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiDataPlane/multiapidataplane/v1/models/_models_py3.py @@ -8,7 +8,7 @@ from typing import Any, List, Optional, TYPE_CHECKING -from ... import _serialization +from .._utils import serialization as _serialization if TYPE_CHECKING: from .. import models as _models diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiDataPlane/multiapidataplane/v1/operations/_multiapi_service_client_operations.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiDataPlane/multiapidataplane/v1/operations/_multiapi_service_client_operations.py index 625b7b25503..71776d1b522 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiDataPlane/multiapidataplane/v1/operations/_multiapi_service_client_operations.py +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiDataPlane/multiapidataplane/v1/operations/_multiapi_service_client_operations.py @@ -10,6 +10,7 @@ from typing import Any, Callable, Dict, IO, Iterable, Iterator, Optional, TypeVar, Union, cast, overload import urllib.parse +from azure.core import PipelineClient from azure.core.exceptions import ( ClientAuthenticationError, HttpResponseError, @@ -29,8 +30,9 @@ from azure.core.utils import case_insensitive_dict from .. import models as _models -from ..._serialization import Serializer -from .._vendor import MultiapiServiceClientMixinABC +from .._configuration import MultiapiServiceClientConfiguration +from .._utils.serialization import Serializer +from .._utils.utils import ClientMixinABC T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] @@ -120,7 +122,7 @@ def build_test_different_calls_request(*, greeting_in_english: str, **kwargs: An return HttpRequest(method="GET", url=_url, params=_params, headers=_headers, **kwargs) -class MultiapiServiceClientOperationsMixin(MultiapiServiceClientMixinABC): +class MultiapiServiceClientOperationsMixin(ClientMixinABC[PipelineClient, MultiapiServiceClientConfiguration]): def _api_version(self, op_name: str) -> str: # pylint: disable=unused-argument try: return self._config.api_version diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiDataPlane/multiapidataplane/v1/operations/_operation_group_one_operations.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiDataPlane/multiapidataplane/v1/operations/_operation_group_one_operations.py index 8d0a504bf22..9416c221fee 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiDataPlane/multiapidataplane/v1/operations/_operation_group_one_operations.py +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiDataPlane/multiapidataplane/v1/operations/_operation_group_one_operations.py @@ -23,8 +23,8 @@ from azure.core.utils import case_insensitive_dict from .. import models as _models -from ..._serialization import Deserializer, Serializer from .._configuration import MultiapiServiceClientConfiguration +from .._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiDataPlane/multiapidataplane/v2/_metadata.json b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiDataPlane/multiapidataplane/v2/_metadata.json index a897337ae5d..4bce8d1cdf9 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiDataPlane/multiapidataplane/v2/_metadata.json +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiDataPlane/multiapidataplane/v2/_metadata.json @@ -10,8 +10,8 @@ "azure_arm": false, "has_public_lro_operations": false, "client_side_validation": false, - "sync_imports": "{\"conditional\": {\"stdlib\": {\"typing\": [\"Any\", \"Optional\"]}}, \"regular\": {\"sdkcore\": {\"azure.core\": [\"PipelineClient\"], \"azure.core.pipeline\": [\"policies\"], \"azure.profiles\": [\"KnownProfiles\", \"ProfileDefinition\"], \"azure.profiles.multiapiclient\": [\"MultiApiClientMixin\"]}, \"local\": {\"._configuration\": [\"MultiapiServiceClientConfiguration\"], \".._serialization\": [\"Deserializer\", \"Serializer\"], \"._operations_mixin\": [\"MultiapiServiceClientOperationsMixin\"]}, \"stdlib\": {\"typing_extensions\": [\"Self\"]}}, \"typing\": {\"sdkcore\": {\"azure.core.credentials\": [\"TokenCredential\"]}}}", - "async_imports": "{\"conditional\": {\"stdlib\": {\"typing\": [\"Any\", \"Optional\"]}}, \"regular\": {\"sdkcore\": {\"azure.core\": [\"AsyncPipelineClient\"], \"azure.core.pipeline\": [\"policies\"], \"azure.profiles\": [\"KnownProfiles\", \"ProfileDefinition\"], \"azure.profiles.multiapiclient\": [\"MultiApiClientMixin\"]}, \"local\": {\"._configuration\": [\"MultiapiServiceClientConfiguration\"], \"..._serialization\": [\"Deserializer\", \"Serializer\"], \"._operations_mixin\": [\"MultiapiServiceClientOperationsMixin\"]}, \"stdlib\": {\"typing_extensions\": [\"Self\"]}}, \"typing\": {\"sdkcore\": {\"azure.core.credentials_async\": [\"AsyncTokenCredential\"]}}}" + "sync_imports": "{\"conditional\": {\"stdlib\": {\"typing\": [\"Any\", \"Optional\"]}}, \"regular\": {\"sdkcore\": {\"azure.core\": [\"PipelineClient\"], \"azure.core.pipeline\": [\"policies\"], \"azure.profiles\": [\"KnownProfiles\", \"ProfileDefinition\"], \"azure.profiles.multiapiclient\": [\"MultiApiClientMixin\"]}, \"local\": {\"._configuration\": [\"MultiapiServiceClientConfiguration\"], \"._utils.serialization\": [\"Deserializer\", \"Serializer\"], \"._operations_mixin\": [\"MultiapiServiceClientOperationsMixin\"]}, \"stdlib\": {\"typing_extensions\": [\"Self\"]}}, \"typing\": {\"sdkcore\": {\"azure.core.credentials\": [\"TokenCredential\"]}}}", + "async_imports": "{\"conditional\": {\"stdlib\": {\"typing\": [\"Any\", \"Optional\"]}}, \"regular\": {\"sdkcore\": {\"azure.core\": [\"AsyncPipelineClient\"], \"azure.core.pipeline\": [\"policies\"], \"azure.profiles\": [\"KnownProfiles\", \"ProfileDefinition\"], \"azure.profiles.multiapiclient\": [\"MultiApiClientMixin\"]}, \"local\": {\"._configuration\": [\"MultiapiServiceClientConfiguration\"], \".._utils.serialization\": [\"Deserializer\", \"Serializer\"], \"._operations_mixin\": [\"MultiapiServiceClientOperationsMixin\"]}, \"stdlib\": {\"typing_extensions\": [\"Self\"]}}, \"typing\": {\"sdkcore\": {\"azure.core.credentials_async\": [\"AsyncTokenCredential\"]}}}" }, "global_parameters": { "sync": { diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiDataPlane/multiapidataplane/v2/_multiapi_service_client.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiDataPlane/multiapidataplane/v2/_multiapi_service_client.py index 13c82562010..9fcf15f7aa4 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiDataPlane/multiapidataplane/v2/_multiapi_service_client.py +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiDataPlane/multiapidataplane/v2/_multiapi_service_client.py @@ -15,8 +15,8 @@ from azure.core.rest import HttpRequest, HttpResponse from . import models as _models -from .._serialization import Deserializer, Serializer from ._configuration import MultiapiServiceClientConfiguration +from ._utils.serialization import Deserializer, Serializer from .operations import MultiapiServiceClientOperationsMixin, OperationGroupOneOperations, OperationGroupTwoOperations if TYPE_CHECKING: diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiDataPlane/multiapidataplane/v2/_utils/__init__.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiDataPlane/multiapidataplane/v2/_utils/__init__.py new file mode 100644 index 00000000000..0af9b28f660 --- /dev/null +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiDataPlane/multiapidataplane/v2/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ErrorWithSecrets/errorwithsecrets/_serialization.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiDataPlane/multiapidataplane/v2/_utils/serialization.py similarity index 100% rename from packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ErrorWithSecrets/errorwithsecrets/_serialization.py rename to packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiDataPlane/multiapidataplane/v2/_utils/serialization.py diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiDataPlane/multiapidataplane/v2/_utils/utils.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiDataPlane/multiapidataplane/v2/_utils/utils.py new file mode 100644 index 00000000000..39b612f39a9 --- /dev/null +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiDataPlane/multiapidataplane/v2/_utils/utils.py @@ -0,0 +1,25 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from abc import ABC +from typing import Generic, TYPE_CHECKING, TypeVar + +if TYPE_CHECKING: + from .serialization import Deserializer, Serializer + + +TClient = TypeVar("TClient") +TConfig = TypeVar("TConfig") + + +class ClientMixinABC(ABC, Generic[TClient, TConfig]): + """DO NOT use this class. It is for internal typing use only.""" + + _client: TClient + _config: TConfig + _serialize: "Serializer" + _deserialize: "Deserializer" diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiDataPlane/multiapidataplane/v2/_vendor.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiDataPlane/multiapidataplane/v2/_vendor.py deleted file mode 100644 index 70517e0b7af..00000000000 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiDataPlane/multiapidataplane/v2/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) AutoRest Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import MultiapiServiceClientConfiguration - -if TYPE_CHECKING: - from azure.core import PipelineClient - - from .._serialization import Deserializer, Serializer - - -class MultiapiServiceClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "PipelineClient" - _config: MultiapiServiceClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiDataPlane/multiapidataplane/v2/aio/_multiapi_service_client.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiDataPlane/multiapidataplane/v2/aio/_multiapi_service_client.py index 00468326ef1..116cc3944db 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiDataPlane/multiapidataplane/v2/aio/_multiapi_service_client.py +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiDataPlane/multiapidataplane/v2/aio/_multiapi_service_client.py @@ -15,7 +15,7 @@ from azure.core.rest import AsyncHttpResponse, HttpRequest from .. import models as _models -from ..._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import MultiapiServiceClientConfiguration from .operations import MultiapiServiceClientOperationsMixin, OperationGroupOneOperations, OperationGroupTwoOperations diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiDataPlane/multiapidataplane/v2/aio/_vendor.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiDataPlane/multiapidataplane/v2/aio/_vendor.py deleted file mode 100644 index 9c6fd05bb21..00000000000 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiDataPlane/multiapidataplane/v2/aio/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) AutoRest Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import MultiapiServiceClientConfiguration - -if TYPE_CHECKING: - from azure.core import AsyncPipelineClient - - from ..._serialization import Deserializer, Serializer - - -class MultiapiServiceClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "AsyncPipelineClient" - _config: MultiapiServiceClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiDataPlane/multiapidataplane/v2/aio/operations/_multiapi_service_client_operations.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiDataPlane/multiapidataplane/v2/aio/operations/_multiapi_service_client_operations.py index ecb912ace42..30fc9f76033 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiDataPlane/multiapidataplane/v2/aio/operations/_multiapi_service_client_operations.py +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiDataPlane/multiapidataplane/v2/aio/operations/_multiapi_service_client_operations.py @@ -9,6 +9,7 @@ from collections.abc import MutableMapping from typing import Any, Callable, Dict, Optional, TypeVar +from azure.core import AsyncPipelineClient from azure.core.exceptions import ( ClientAuthenticationError, HttpResponseError, @@ -23,14 +24,15 @@ from azure.core.utils import case_insensitive_dict from ... import models as _models +from ..._utils.utils import ClientMixinABC from ...operations._multiapi_service_client_operations import build_test_different_calls_request, build_test_one_request -from .._vendor import MultiapiServiceClientMixinABC +from .._configuration import MultiapiServiceClientConfiguration T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, AsyncHttpResponse], T, Dict[str, Any]], Any]] -class MultiapiServiceClientOperationsMixin(MultiapiServiceClientMixinABC): +class MultiapiServiceClientOperationsMixin(ClientMixinABC[AsyncPipelineClient, MultiapiServiceClientConfiguration]): def _api_version(self, op_name: str) -> str: # pylint: disable=unused-argument try: return self._config.api_version diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiDataPlane/multiapidataplane/v2/aio/operations/_operation_group_one_operations.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiDataPlane/multiapidataplane/v2/aio/operations/_operation_group_one_operations.py index 24925d79286..37b3540d142 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiDataPlane/multiapidataplane/v2/aio/operations/_operation_group_one_operations.py +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiDataPlane/multiapidataplane/v2/aio/operations/_operation_group_one_operations.py @@ -24,7 +24,7 @@ from azure.core.utils import case_insensitive_dict from ... import models as _models -from ...._serialization import Deserializer, Serializer +from ..._utils.serialization import Deserializer, Serializer from ...operations._operation_group_one_operations import build_test_three_request, build_test_two_request from .._configuration import MultiapiServiceClientConfiguration diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiDataPlane/multiapidataplane/v2/aio/operations/_operation_group_two_operations.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiDataPlane/multiapidataplane/v2/aio/operations/_operation_group_two_operations.py index bc656b2d765..0eac39118b5 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiDataPlane/multiapidataplane/v2/aio/operations/_operation_group_two_operations.py +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiDataPlane/multiapidataplane/v2/aio/operations/_operation_group_two_operations.py @@ -23,7 +23,7 @@ from azure.core.utils import case_insensitive_dict from ... import models as _models -from ...._serialization import Deserializer, Serializer +from ..._utils.serialization import Deserializer, Serializer from ...operations._operation_group_two_operations import build_test_four_request from .._configuration import MultiapiServiceClientConfiguration diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiDataPlane/multiapidataplane/v2/models/_models_py3.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiDataPlane/multiapidataplane/v2/models/_models_py3.py index 46990252065..a00726a3da2 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiDataPlane/multiapidataplane/v2/models/_models_py3.py +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiDataPlane/multiapidataplane/v2/models/_models_py3.py @@ -8,7 +8,7 @@ from typing import Any, Optional -from ... import _serialization +from .._utils import serialization as _serialization class Error(_serialization.Model): diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiDataPlane/multiapidataplane/v2/operations/_multiapi_service_client_operations.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiDataPlane/multiapidataplane/v2/operations/_multiapi_service_client_operations.py index e7bda124855..af93bace224 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiDataPlane/multiapidataplane/v2/operations/_multiapi_service_client_operations.py +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiDataPlane/multiapidataplane/v2/operations/_multiapi_service_client_operations.py @@ -8,6 +8,7 @@ from collections.abc import MutableMapping from typing import Any, Callable, Dict, Optional, TypeVar +from azure.core import PipelineClient from azure.core.exceptions import ( ClientAuthenticationError, HttpResponseError, @@ -22,8 +23,9 @@ from azure.core.utils import case_insensitive_dict from .. import models as _models -from ..._serialization import Serializer -from .._vendor import MultiapiServiceClientMixinABC +from .._configuration import MultiapiServiceClientConfiguration +from .._utils.serialization import Serializer +from .._utils.utils import ClientMixinABC T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] @@ -78,7 +80,7 @@ def build_test_different_calls_request( return HttpRequest(method="GET", url=_url, params=_params, headers=_headers, **kwargs) -class MultiapiServiceClientOperationsMixin(MultiapiServiceClientMixinABC): +class MultiapiServiceClientOperationsMixin(ClientMixinABC[PipelineClient, MultiapiServiceClientConfiguration]): def _api_version(self, op_name: str) -> str: # pylint: disable=unused-argument try: return self._config.api_version diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiDataPlane/multiapidataplane/v2/operations/_operation_group_one_operations.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiDataPlane/multiapidataplane/v2/operations/_operation_group_one_operations.py index 46f137fb915..9473ffd4da3 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiDataPlane/multiapidataplane/v2/operations/_operation_group_one_operations.py +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiDataPlane/multiapidataplane/v2/operations/_operation_group_one_operations.py @@ -24,8 +24,8 @@ from azure.core.utils import case_insensitive_dict from .. import models as _models -from ..._serialization import Deserializer, Serializer from .._configuration import MultiapiServiceClientConfiguration +from .._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiDataPlane/multiapidataplane/v2/operations/_operation_group_two_operations.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiDataPlane/multiapidataplane/v2/operations/_operation_group_two_operations.py index 07ca8773cca..f522c929128 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiDataPlane/multiapidataplane/v2/operations/_operation_group_two_operations.py +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiDataPlane/multiapidataplane/v2/operations/_operation_group_two_operations.py @@ -23,8 +23,8 @@ from azure.core.utils import case_insensitive_dict from .. import models as _models -from ..._serialization import Deserializer, Serializer from .._configuration import MultiapiServiceClientConfiguration +from .._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiDataPlane/multiapidataplane/v3/_metadata.json b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiDataPlane/multiapidataplane/v3/_metadata.json index 3e0f12a2ab7..68d2ba21f1a 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiDataPlane/multiapidataplane/v3/_metadata.json +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiDataPlane/multiapidataplane/v3/_metadata.json @@ -10,8 +10,8 @@ "azure_arm": false, "has_public_lro_operations": false, "client_side_validation": false, - "sync_imports": "{\"conditional\": {\"stdlib\": {\"typing\": [\"Any\", \"Optional\"]}}, \"regular\": {\"sdkcore\": {\"azure.core\": [\"PipelineClient\"], \"azure.core.pipeline\": [\"policies\"], \"azure.profiles\": [\"KnownProfiles\", \"ProfileDefinition\"], \"azure.profiles.multiapiclient\": [\"MultiApiClientMixin\"]}, \"local\": {\"._configuration\": [\"MultiapiServiceClientConfiguration\"], \".._serialization\": [\"Deserializer\", \"Serializer\"], \"._operations_mixin\": [\"MultiapiServiceClientOperationsMixin\"]}, \"stdlib\": {\"typing_extensions\": [\"Self\"]}}, \"typing\": {\"sdkcore\": {\"azure.core.credentials\": [\"TokenCredential\"]}}}", - "async_imports": "{\"conditional\": {\"stdlib\": {\"typing\": [\"Any\", \"Optional\"]}}, \"regular\": {\"sdkcore\": {\"azure.core\": [\"AsyncPipelineClient\"], \"azure.core.pipeline\": [\"policies\"], \"azure.profiles\": [\"KnownProfiles\", \"ProfileDefinition\"], \"azure.profiles.multiapiclient\": [\"MultiApiClientMixin\"]}, \"local\": {\"._configuration\": [\"MultiapiServiceClientConfiguration\"], \"..._serialization\": [\"Deserializer\", \"Serializer\"], \"._operations_mixin\": [\"MultiapiServiceClientOperationsMixin\"]}, \"stdlib\": {\"typing_extensions\": [\"Self\"]}}, \"typing\": {\"sdkcore\": {\"azure.core.credentials_async\": [\"AsyncTokenCredential\"]}}}" + "sync_imports": "{\"conditional\": {\"stdlib\": {\"typing\": [\"Any\", \"Optional\"]}}, \"regular\": {\"sdkcore\": {\"azure.core\": [\"PipelineClient\"], \"azure.core.pipeline\": [\"policies\"], \"azure.profiles\": [\"KnownProfiles\", \"ProfileDefinition\"], \"azure.profiles.multiapiclient\": [\"MultiApiClientMixin\"]}, \"local\": {\"._configuration\": [\"MultiapiServiceClientConfiguration\"], \"._utils.serialization\": [\"Deserializer\", \"Serializer\"], \"._operations_mixin\": [\"MultiapiServiceClientOperationsMixin\"]}, \"stdlib\": {\"typing_extensions\": [\"Self\"]}}, \"typing\": {\"sdkcore\": {\"azure.core.credentials\": [\"TokenCredential\"]}}}", + "async_imports": "{\"conditional\": {\"stdlib\": {\"typing\": [\"Any\", \"Optional\"]}}, \"regular\": {\"sdkcore\": {\"azure.core\": [\"AsyncPipelineClient\"], \"azure.core.pipeline\": [\"policies\"], \"azure.profiles\": [\"KnownProfiles\", \"ProfileDefinition\"], \"azure.profiles.multiapiclient\": [\"MultiApiClientMixin\"]}, \"local\": {\"._configuration\": [\"MultiapiServiceClientConfiguration\"], \".._utils.serialization\": [\"Deserializer\", \"Serializer\"], \"._operations_mixin\": [\"MultiapiServiceClientOperationsMixin\"]}, \"stdlib\": {\"typing_extensions\": [\"Self\"]}}, \"typing\": {\"sdkcore\": {\"azure.core.credentials_async\": [\"AsyncTokenCredential\"]}}}" }, "global_parameters": { "sync": { diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiDataPlane/multiapidataplane/v3/_multiapi_service_client.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiDataPlane/multiapidataplane/v3/_multiapi_service_client.py index 1d40f8db628..1bb4be8e1eb 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiDataPlane/multiapidataplane/v3/_multiapi_service_client.py +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiDataPlane/multiapidataplane/v3/_multiapi_service_client.py @@ -15,8 +15,8 @@ from azure.core.rest import HttpRequest, HttpResponse from . import models as _models -from .._serialization import Deserializer, Serializer from ._configuration import MultiapiServiceClientConfiguration +from ._utils.serialization import Deserializer, Serializer from .operations import MultiapiServiceClientOperationsMixin, OperationGroupOneOperations, OperationGroupTwoOperations if TYPE_CHECKING: diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiDataPlane/multiapidataplane/v3/_utils/__init__.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiDataPlane/multiapidataplane/v3/_utils/__init__.py new file mode 100644 index 00000000000..0af9b28f660 --- /dev/null +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiDataPlane/multiapidataplane/v3/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ExtensibleEnums/extensibleenumsswagger/_serialization.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiDataPlane/multiapidataplane/v3/_utils/serialization.py similarity index 100% rename from packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ExtensibleEnums/extensibleenumsswagger/_serialization.py rename to packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiDataPlane/multiapidataplane/v3/_utils/serialization.py diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiDataPlane/multiapidataplane/v3/_utils/utils.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiDataPlane/multiapidataplane/v3/_utils/utils.py new file mode 100644 index 00000000000..39b612f39a9 --- /dev/null +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiDataPlane/multiapidataplane/v3/_utils/utils.py @@ -0,0 +1,25 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from abc import ABC +from typing import Generic, TYPE_CHECKING, TypeVar + +if TYPE_CHECKING: + from .serialization import Deserializer, Serializer + + +TClient = TypeVar("TClient") +TConfig = TypeVar("TConfig") + + +class ClientMixinABC(ABC, Generic[TClient, TConfig]): + """DO NOT use this class. It is for internal typing use only.""" + + _client: TClient + _config: TConfig + _serialize: "Serializer" + _deserialize: "Deserializer" diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiDataPlane/multiapidataplane/v3/_vendor.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiDataPlane/multiapidataplane/v3/_vendor.py deleted file mode 100644 index 70517e0b7af..00000000000 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiDataPlane/multiapidataplane/v3/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) AutoRest Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import MultiapiServiceClientConfiguration - -if TYPE_CHECKING: - from azure.core import PipelineClient - - from .._serialization import Deserializer, Serializer - - -class MultiapiServiceClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "PipelineClient" - _config: MultiapiServiceClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiDataPlane/multiapidataplane/v3/aio/_multiapi_service_client.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiDataPlane/multiapidataplane/v3/aio/_multiapi_service_client.py index 9a5c88942ca..023f005a955 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiDataPlane/multiapidataplane/v3/aio/_multiapi_service_client.py +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiDataPlane/multiapidataplane/v3/aio/_multiapi_service_client.py @@ -15,7 +15,7 @@ from azure.core.rest import AsyncHttpResponse, HttpRequest from .. import models as _models -from ..._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import MultiapiServiceClientConfiguration from .operations import MultiapiServiceClientOperationsMixin, OperationGroupOneOperations, OperationGroupTwoOperations diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiDataPlane/multiapidataplane/v3/aio/_vendor.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiDataPlane/multiapidataplane/v3/aio/_vendor.py deleted file mode 100644 index 9c6fd05bb21..00000000000 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiDataPlane/multiapidataplane/v3/aio/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) AutoRest Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import MultiapiServiceClientConfiguration - -if TYPE_CHECKING: - from azure.core import AsyncPipelineClient - - from ..._serialization import Deserializer, Serializer - - -class MultiapiServiceClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "AsyncPipelineClient" - _config: MultiapiServiceClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiDataPlane/multiapidataplane/v3/aio/operations/_multiapi_service_client_operations.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiDataPlane/multiapidataplane/v3/aio/operations/_multiapi_service_client_operations.py index 7978b5d6483..addf014fa23 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiDataPlane/multiapidataplane/v3/aio/operations/_multiapi_service_client_operations.py +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiDataPlane/multiapidataplane/v3/aio/operations/_multiapi_service_client_operations.py @@ -10,6 +10,7 @@ from typing import Any, AsyncIterable, Callable, Dict, Optional, TypeVar import urllib.parse +from azure.core import AsyncPipelineClient from azure.core.async_paging import AsyncItemPaged, AsyncList from azure.core.exceptions import ( ClientAuthenticationError, @@ -26,17 +27,18 @@ from azure.core.utils import case_insensitive_dict from ... import models as _models +from ..._utils.utils import ClientMixinABC from ...operations._multiapi_service_client_operations import ( build_test_different_calls_request, build_test_paging_request, ) -from .._vendor import MultiapiServiceClientMixinABC +from .._configuration import MultiapiServiceClientConfiguration T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, AsyncHttpResponse], T, Dict[str, Any]], Any]] -class MultiapiServiceClientOperationsMixin(MultiapiServiceClientMixinABC): +class MultiapiServiceClientOperationsMixin(ClientMixinABC[AsyncPipelineClient, MultiapiServiceClientConfiguration]): def _api_version(self, op_name: str) -> str: # pylint: disable=unused-argument try: return self._config.api_version diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiDataPlane/multiapidataplane/v3/aio/operations/_operation_group_one_operations.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiDataPlane/multiapidataplane/v3/aio/operations/_operation_group_one_operations.py index fffa104254f..81019a543f2 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiDataPlane/multiapidataplane/v3/aio/operations/_operation_group_one_operations.py +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiDataPlane/multiapidataplane/v3/aio/operations/_operation_group_one_operations.py @@ -27,7 +27,7 @@ from azure.core.utils import case_insensitive_dict from ... import models as _models -from ...._serialization import Deserializer, Serializer +from ..._utils.serialization import Deserializer, Serializer from ...operations._operation_group_one_operations import ( build_test_operation_group_paging_request, build_test_two_request, diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiDataPlane/multiapidataplane/v3/aio/operations/_operation_group_two_operations.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiDataPlane/multiapidataplane/v3/aio/operations/_operation_group_two_operations.py index 4cb5585698a..357af5d2bcd 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiDataPlane/multiapidataplane/v3/aio/operations/_operation_group_two_operations.py +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiDataPlane/multiapidataplane/v3/aio/operations/_operation_group_two_operations.py @@ -24,7 +24,7 @@ from azure.core.utils import case_insensitive_dict from ... import models as _models -from ...._serialization import Deserializer, Serializer +from ..._utils.serialization import Deserializer, Serializer from ...operations._operation_group_two_operations import build_test_five_request, build_test_four_request from .._configuration import MultiapiServiceClientConfiguration diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiDataPlane/multiapidataplane/v3/models/_models_py3.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiDataPlane/multiapidataplane/v3/models/_models_py3.py index 0b7fe77b89e..f3b491f644d 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiDataPlane/multiapidataplane/v3/models/_models_py3.py +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiDataPlane/multiapidataplane/v3/models/_models_py3.py @@ -8,7 +8,7 @@ from typing import Any, List, Optional, TYPE_CHECKING -from ... import _serialization +from .._utils import serialization as _serialization if TYPE_CHECKING: from .. import models as _models diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiDataPlane/multiapidataplane/v3/operations/_multiapi_service_client_operations.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiDataPlane/multiapidataplane/v3/operations/_multiapi_service_client_operations.py index 7faf56f8c3a..2145e54ecc9 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiDataPlane/multiapidataplane/v3/operations/_multiapi_service_client_operations.py +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiDataPlane/multiapidataplane/v3/operations/_multiapi_service_client_operations.py @@ -9,6 +9,7 @@ from typing import Any, Callable, Dict, Iterable, Optional, TypeVar import urllib.parse +from azure.core import PipelineClient from azure.core.exceptions import ( ClientAuthenticationError, HttpResponseError, @@ -24,8 +25,9 @@ from azure.core.utils import case_insensitive_dict from .. import models as _models -from ..._serialization import Serializer -from .._vendor import MultiapiServiceClientMixinABC +from .._configuration import MultiapiServiceClientConfiguration +from .._utils.serialization import Serializer +from .._utils.utils import ClientMixinABC T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] @@ -78,7 +80,7 @@ def build_test_different_calls_request( return HttpRequest(method="GET", url=_url, params=_params, headers=_headers, **kwargs) -class MultiapiServiceClientOperationsMixin(MultiapiServiceClientMixinABC): +class MultiapiServiceClientOperationsMixin(ClientMixinABC[PipelineClient, MultiapiServiceClientConfiguration]): def _api_version(self, op_name: str) -> str: # pylint: disable=unused-argument try: return self._config.api_version diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiDataPlane/multiapidataplane/v3/operations/_operation_group_one_operations.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiDataPlane/multiapidataplane/v3/operations/_operation_group_one_operations.py index b73409fb8d9..1b959dd75eb 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiDataPlane/multiapidataplane/v3/operations/_operation_group_one_operations.py +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiDataPlane/multiapidataplane/v3/operations/_operation_group_one_operations.py @@ -26,8 +26,8 @@ from azure.core.utils import case_insensitive_dict from .. import models as _models -from ..._serialization import Deserializer, Serializer from .._configuration import MultiapiServiceClientConfiguration +from .._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiDataPlane/multiapidataplane/v3/operations/_operation_group_two_operations.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiDataPlane/multiapidataplane/v3/operations/_operation_group_two_operations.py index e7f7e00f37c..ed3b85e3b50 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiDataPlane/multiapidataplane/v3/operations/_operation_group_two_operations.py +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiDataPlane/multiapidataplane/v3/operations/_operation_group_two_operations.py @@ -24,8 +24,8 @@ from azure.core.utils import case_insensitive_dict from .. import models as _models -from ..._serialization import Deserializer, Serializer from .._configuration import MultiapiServiceClientConfiguration +from .._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiKeywordOnly/multiapikeywordonly/_multiapi_service_client.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiKeywordOnly/multiapikeywordonly/_multiapi_service_client.py index 84164bb2598..6ed492f80de 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiKeywordOnly/multiapikeywordonly/_multiapi_service_client.py +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiKeywordOnly/multiapikeywordonly/_multiapi_service_client.py @@ -19,7 +19,7 @@ from ._configuration import MultiapiServiceClientConfiguration from ._operations_mixin import MultiapiServiceClientOperationsMixin -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer if TYPE_CHECKING: # pylint: disable=unused-import,ungrouped-imports diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiKeywordOnly/multiapikeywordonly/_operations_mixin.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiKeywordOnly/multiapikeywordonly/_operations_mixin.py index 825654e9f06..efdc378987e 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiKeywordOnly/multiapikeywordonly/_operations_mixin.py +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiKeywordOnly/multiapikeywordonly/_operations_mixin.py @@ -8,7 +8,7 @@ # Changes may cause incorrect behavior and will be lost if the code is # regenerated. # -------------------------------------------------------------------------- -from ._serialization import Serializer, Deserializer +from ._utils.serialization import Serializer, Deserializer from io import IOBase from typing import Any, IO, Iterable, Iterator, Optional, Union diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiKeywordOnly/multiapikeywordonly/_utils/__init__.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiKeywordOnly/multiapikeywordonly/_utils/__init__.py new file mode 100644 index 00000000000..59333308532 --- /dev/null +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiKeywordOnly/multiapikeywordonly/_utils/__init__.py @@ -0,0 +1,10 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is +# regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiKeywordOnly/multiapikeywordonly/_utils/serialization.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiKeywordOnly/multiapikeywordonly/_utils/serialization.py new file mode 100644 index 00000000000..05bcd7d403a --- /dev/null +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiKeywordOnly/multiapikeywordonly/_utils/serialization.py @@ -0,0 +1,2025 @@ +# coding=utf-8 + +# pyright: reportUnnecessaryTypeIgnoreComment=false + +from base64 import b64decode, b64encode +import calendar +import datetime +import decimal +import email +from enum import Enum +import json +import logging +import re +import sys +import codecs +from typing import ( + Dict, + Any, + cast, + Optional, + Union, + AnyStr, + IO, + Mapping, + Callable, + MutableMapping, + List, +) + +try: + from urllib import quote # type: ignore +except ImportError: + from urllib.parse import quote +import xml.etree.ElementTree as ET + +import isodate # type: ignore +from typing_extensions import Self + +from azure.core.exceptions import DeserializationError, SerializationError +from azure.core.serialization import NULL as CoreNull + +_BOM = codecs.BOM_UTF8.decode(encoding="utf-8") + +JSON = MutableMapping[str, Any] + + +class RawDeserializer: + + # Accept "text" because we're open minded people... + JSON_REGEXP = re.compile(r"^(application|text)/([a-z+.]+\+)?json$") + + # Name used in context + CONTEXT_NAME = "deserialized_data" + + @classmethod + def deserialize_from_text(cls, data: Optional[Union[AnyStr, IO]], content_type: Optional[str] = None) -> Any: + """Decode data according to content-type. + + Accept a stream of data as well, but will be load at once in memory for now. + + If no content-type, will return the string version (not bytes, not stream) + + :param data: Input, could be bytes or stream (will be decoded with UTF8) or text + :type data: str or bytes or IO + :param str content_type: The content type. + :return: The deserialized data. + :rtype: object + """ + if hasattr(data, "read"): + # Assume a stream + data = cast(IO, data).read() + + if isinstance(data, bytes): + data_as_str = data.decode(encoding="utf-8-sig") + else: + # Explain to mypy the correct type. + data_as_str = cast(str, data) + + # Remove Byte Order Mark if present in string + data_as_str = data_as_str.lstrip(_BOM) + + if content_type is None: + return data + + if cls.JSON_REGEXP.match(content_type): + try: + return json.loads(data_as_str) + except ValueError as err: + raise DeserializationError("JSON is invalid: {}".format(err), err) from err + elif "xml" in (content_type or []): + try: + + try: + if isinstance(data, unicode): # type: ignore + # If I'm Python 2.7 and unicode XML will scream if I try a "fromstring" on unicode string + data_as_str = data_as_str.encode(encoding="utf-8") # type: ignore + except NameError: + pass + + return ET.fromstring(data_as_str) # nosec + except ET.ParseError as err: + # It might be because the server has an issue, and returned JSON with + # content-type XML.... + # So let's try a JSON load, and if it's still broken + # let's flow the initial exception + def _json_attemp(data): + try: + return True, json.loads(data) + except ValueError: + return False, None # Don't care about this one + + success, json_result = _json_attemp(data) + if success: + return json_result + # If i'm here, it's not JSON, it's not XML, let's scream + # and raise the last context in this block (the XML exception) + # The function hack is because Py2.7 messes up with exception + # context otherwise. + _LOGGER.critical("Wasn't XML not JSON, failing") + raise DeserializationError("XML is invalid") from err + elif content_type.startswith("text/"): + return data_as_str + raise DeserializationError("Cannot deserialize content-type: {}".format(content_type)) + + @classmethod + def deserialize_from_http_generics(cls, body_bytes: Optional[Union[AnyStr, IO]], headers: Mapping) -> Any: + """Deserialize from HTTP response. + + Use bytes and headers to NOT use any requests/aiohttp or whatever + specific implementation. + Headers will tested for "content-type" + + :param bytes body_bytes: The body of the response. + :param dict headers: The headers of the response. + :returns: The deserialized data. + :rtype: object + """ + # Try to use content-type from headers if available + content_type = None + if "content-type" in headers: + content_type = headers["content-type"].split(";")[0].strip().lower() + # Ouch, this server did not declare what it sent... + # Let's guess it's JSON... + # Also, since Autorest was considering that an empty body was a valid JSON, + # need that test as well.... + else: + content_type = "application/json" + + if body_bytes: + return cls.deserialize_from_text(body_bytes, content_type) + return None + + +_LOGGER = logging.getLogger(__name__) + +try: + _long_type = long # type: ignore +except NameError: + _long_type = int + +TZ_UTC = datetime.timezone.utc + +_FLATTEN = re.compile(r"(? None: + self.additional_properties: Optional[Dict[str, Any]] = {} + for k in kwargs: # pylint: disable=consider-using-dict-items + if k not in self._attribute_map: + _LOGGER.warning("%s is not a known attribute of class %s and will be ignored", k, self.__class__) + elif k in self._validation and self._validation[k].get("readonly", False): + _LOGGER.warning("Readonly attribute %s will be ignored in class %s", k, self.__class__) + else: + setattr(self, k, kwargs[k]) + + def __eq__(self, other: Any) -> bool: + """Compare objects by comparing all attributes. + + :param object other: The object to compare + :returns: True if objects are equal + :rtype: bool + """ + if isinstance(other, self.__class__): + return self.__dict__ == other.__dict__ + return False + + def __ne__(self, other: Any) -> bool: + """Compare objects by comparing all attributes. + + :param object other: The object to compare + :returns: True if objects are not equal + :rtype: bool + """ + return not self.__eq__(other) + + def __str__(self) -> str: + return str(self.__dict__) + + @classmethod + def enable_additional_properties_sending(cls) -> None: + cls._attribute_map["additional_properties"] = {"key": "", "type": "{object}"} + + @classmethod + def is_xml_model(cls) -> bool: + try: + cls._xml_map # type: ignore + except AttributeError: + return False + return True + + @classmethod + def _create_xml_node(cls): + """Create XML node. + + :returns: The XML node + :rtype: xml.etree.ElementTree.Element + """ + try: + xml_map = cls._xml_map # type: ignore + except AttributeError: + xml_map = {} + + return _create_xml_node(xml_map.get("name", cls.__name__), xml_map.get("prefix", None), xml_map.get("ns", None)) + + def serialize(self, keep_readonly: bool = False, **kwargs: Any) -> JSON: + """Return the JSON that would be sent to server from this model. + + This is an alias to `as_dict(full_restapi_key_transformer, keep_readonly=False)`. + + If you want XML serialization, you can pass the kwargs is_xml=True. + + :param bool keep_readonly: If you want to serialize the readonly attributes + :returns: A dict JSON compatible object + :rtype: dict + """ + serializer = Serializer(self._infer_class_models()) + return serializer._serialize( # type: ignore # pylint: disable=protected-access + self, keep_readonly=keep_readonly, **kwargs + ) + + def as_dict( + self, + keep_readonly: bool = True, + key_transformer: Callable[[str, Dict[str, Any], Any], Any] = attribute_transformer, + **kwargs: Any + ) -> JSON: + """Return a dict that can be serialized using json.dump. + + Advanced usage might optionally use a callback as parameter: + + .. code::python + + def my_key_transformer(key, attr_desc, value): + return key + + Key is the attribute name used in Python. Attr_desc + is a dict of metadata. Currently contains 'type' with the + msrest type and 'key' with the RestAPI encoded key. + Value is the current value in this object. + + The string returned will be used to serialize the key. + If the return type is a list, this is considered hierarchical + result dict. + + See the three examples in this file: + + - attribute_transformer + - full_restapi_key_transformer + - last_restapi_key_transformer + + If you want XML serialization, you can pass the kwargs is_xml=True. + + :param bool keep_readonly: If you want to serialize the readonly attributes + :param function key_transformer: A key transformer function. + :returns: A dict JSON compatible object + :rtype: dict + """ + serializer = Serializer(self._infer_class_models()) + return serializer._serialize( # type: ignore # pylint: disable=protected-access + self, key_transformer=key_transformer, keep_readonly=keep_readonly, **kwargs + ) + + @classmethod + def _infer_class_models(cls): + try: + str_models = cls.__module__.rsplit(".", 1)[0] + models = sys.modules[str_models] + client_models = {k: v for k, v in models.__dict__.items() if isinstance(v, type)} + if cls.__name__ not in client_models: + raise ValueError("Not Autorest generated code") + except Exception: # pylint: disable=broad-exception-caught + # Assume it's not Autorest generated (tests?). Add ourselves as dependencies. + client_models = {cls.__name__: cls} + return client_models + + @classmethod + def deserialize(cls, data: Any, content_type: Optional[str] = None) -> Self: + """Parse a str using the RestAPI syntax and return a model. + + :param str data: A str using RestAPI structure. JSON by default. + :param str content_type: JSON by default, set application/xml if XML. + :returns: An instance of this model + :raises DeserializationError: if something went wrong + :rtype: Self + """ + deserializer = Deserializer(cls._infer_class_models()) + return deserializer(cls.__name__, data, content_type=content_type) # type: ignore + + @classmethod + def from_dict( + cls, + data: Any, + key_extractors: Optional[Callable[[str, Dict[str, Any], Any], Any]] = None, + content_type: Optional[str] = None, + ) -> Self: + """Parse a dict using given key extractor return a model. + + By default consider key + extractors (rest_key_case_insensitive_extractor, attribute_key_case_insensitive_extractor + and last_rest_key_case_insensitive_extractor) + + :param dict data: A dict using RestAPI structure + :param function key_extractors: A key extractor function. + :param str content_type: JSON by default, set application/xml if XML. + :returns: An instance of this model + :raises DeserializationError: if something went wrong + :rtype: Self + """ + deserializer = Deserializer(cls._infer_class_models()) + deserializer.key_extractors = ( # type: ignore + [ # type: ignore + attribute_key_case_insensitive_extractor, + rest_key_case_insensitive_extractor, + last_rest_key_case_insensitive_extractor, + ] + if key_extractors is None + else key_extractors + ) + return deserializer(cls.__name__, data, content_type=content_type) # type: ignore + + @classmethod + def _flatten_subtype(cls, key, objects): + if "_subtype_map" not in cls.__dict__: + return {} + result = dict(cls._subtype_map[key]) + for valuetype in cls._subtype_map[key].values(): + result.update(objects[valuetype]._flatten_subtype(key, objects)) # pylint: disable=protected-access + return result + + @classmethod + def _classify(cls, response, objects): + """Check the class _subtype_map for any child classes. + We want to ignore any inherited _subtype_maps. + + :param dict response: The initial data + :param dict objects: The class objects + :returns: The class to be used + :rtype: class + """ + for subtype_key in cls.__dict__.get("_subtype_map", {}).keys(): + subtype_value = None + + if not isinstance(response, ET.Element): + rest_api_response_key = cls._get_rest_key_parts(subtype_key)[-1] + subtype_value = response.get(rest_api_response_key, None) or response.get(subtype_key, None) + else: + subtype_value = xml_key_extractor(subtype_key, cls._attribute_map[subtype_key], response) + if subtype_value: + # Try to match base class. Can be class name only + # (bug to fix in Autorest to support x-ms-discriminator-name) + if cls.__name__ == subtype_value: + return cls + flatten_mapping_type = cls._flatten_subtype(subtype_key, objects) + try: + return objects[flatten_mapping_type[subtype_value]] # type: ignore + except KeyError: + _LOGGER.warning( + "Subtype value %s has no mapping, use base class %s.", + subtype_value, + cls.__name__, + ) + break + else: + _LOGGER.warning("Discriminator %s is absent or null, use base class %s.", subtype_key, cls.__name__) + break + return cls + + @classmethod + def _get_rest_key_parts(cls, attr_key): + """Get the RestAPI key of this attr, split it and decode part + :param str attr_key: Attribute key must be in attribute_map. + :returns: A list of RestAPI part + :rtype: list + """ + rest_split_key = _FLATTEN.split(cls._attribute_map[attr_key]["key"]) + return [_decode_attribute_map_key(key_part) for key_part in rest_split_key] + + +def _decode_attribute_map_key(key): + """This decode a key in an _attribute_map to the actual key we want to look at + inside the received data. + + :param str key: A key string from the generated code + :returns: The decoded key + :rtype: str + """ + return key.replace("\\.", ".") + + +class Serializer: # pylint: disable=too-many-public-methods + """Request object model serializer.""" + + basic_types = {str: "str", int: "int", bool: "bool", float: "float"} + + _xml_basic_types_serializers = {"bool": lambda x: str(x).lower()} + days = {0: "Mon", 1: "Tue", 2: "Wed", 3: "Thu", 4: "Fri", 5: "Sat", 6: "Sun"} + months = { + 1: "Jan", + 2: "Feb", + 3: "Mar", + 4: "Apr", + 5: "May", + 6: "Jun", + 7: "Jul", + 8: "Aug", + 9: "Sep", + 10: "Oct", + 11: "Nov", + 12: "Dec", + } + validation = { + "min_length": lambda x, y: len(x) < y, + "max_length": lambda x, y: len(x) > y, + "minimum": lambda x, y: x < y, + "maximum": lambda x, y: x > y, + "minimum_ex": lambda x, y: x <= y, + "maximum_ex": lambda x, y: x >= y, + "min_items": lambda x, y: len(x) < y, + "max_items": lambda x, y: len(x) > y, + "pattern": lambda x, y: not re.match(y, x, re.UNICODE), + "unique": lambda x, y: len(x) != len(set(x)), + "multiple": lambda x, y: x % y != 0, + } + + def __init__(self, classes: Optional[Mapping[str, type]] = None) -> None: + self.serialize_type = { + "iso-8601": Serializer.serialize_iso, + "rfc-1123": Serializer.serialize_rfc, + "unix-time": Serializer.serialize_unix, + "duration": Serializer.serialize_duration, + "date": Serializer.serialize_date, + "time": Serializer.serialize_time, + "decimal": Serializer.serialize_decimal, + "long": Serializer.serialize_long, + "bytearray": Serializer.serialize_bytearray, + "base64": Serializer.serialize_base64, + "object": self.serialize_object, + "[]": self.serialize_iter, + "{}": self.serialize_dict, + } + self.dependencies: Dict[str, type] = dict(classes) if classes else {} + self.key_transformer = full_restapi_key_transformer + self.client_side_validation = True + + def _serialize( # pylint: disable=too-many-nested-blocks, too-many-branches, too-many-statements, too-many-locals + self, target_obj, data_type=None, **kwargs + ): + """Serialize data into a string according to type. + + :param object target_obj: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str, dict + :raises SerializationError: if serialization fails. + :returns: The serialized data. + """ + key_transformer = kwargs.get("key_transformer", self.key_transformer) + keep_readonly = kwargs.get("keep_readonly", False) + if target_obj is None: + return None + + attr_name = None + class_name = target_obj.__class__.__name__ + + if data_type: + return self.serialize_data(target_obj, data_type, **kwargs) + + if not hasattr(target_obj, "_attribute_map"): + data_type = type(target_obj).__name__ + if data_type in self.basic_types.values(): + return self.serialize_data(target_obj, data_type, **kwargs) + + # Force "is_xml" kwargs if we detect a XML model + try: + is_xml_model_serialization = kwargs["is_xml"] + except KeyError: + is_xml_model_serialization = kwargs.setdefault("is_xml", target_obj.is_xml_model()) + + serialized = {} + if is_xml_model_serialization: + serialized = target_obj._create_xml_node() # pylint: disable=protected-access + try: + attributes = target_obj._attribute_map # pylint: disable=protected-access + for attr, attr_desc in attributes.items(): + attr_name = attr + if not keep_readonly and target_obj._validation.get( # pylint: disable=protected-access + attr_name, {} + ).get("readonly", False): + continue + + if attr_name == "additional_properties" and attr_desc["key"] == "": + if target_obj.additional_properties is not None: + serialized.update(target_obj.additional_properties) + continue + try: + + orig_attr = getattr(target_obj, attr) + if is_xml_model_serialization: + pass # Don't provide "transformer" for XML for now. Keep "orig_attr" + else: # JSON + keys, orig_attr = key_transformer(attr, attr_desc.copy(), orig_attr) + keys = keys if isinstance(keys, list) else [keys] + + kwargs["serialization_ctxt"] = attr_desc + new_attr = self.serialize_data(orig_attr, attr_desc["type"], **kwargs) + + if is_xml_model_serialization: + xml_desc = attr_desc.get("xml", {}) + xml_name = xml_desc.get("name", attr_desc["key"]) + xml_prefix = xml_desc.get("prefix", None) + xml_ns = xml_desc.get("ns", None) + if xml_desc.get("attr", False): + if xml_ns: + ET.register_namespace(xml_prefix, xml_ns) + xml_name = "{{{}}}{}".format(xml_ns, xml_name) + serialized.set(xml_name, new_attr) # type: ignore + continue + if xml_desc.get("text", False): + serialized.text = new_attr # type: ignore + continue + if isinstance(new_attr, list): + serialized.extend(new_attr) # type: ignore + elif isinstance(new_attr, ET.Element): + # If the down XML has no XML/Name, + # we MUST replace the tag with the local tag. But keeping the namespaces. + if "name" not in getattr(orig_attr, "_xml_map", {}): + splitted_tag = new_attr.tag.split("}") + if len(splitted_tag) == 2: # Namespace + new_attr.tag = "}".join([splitted_tag[0], xml_name]) + else: + new_attr.tag = xml_name + serialized.append(new_attr) # type: ignore + else: # That's a basic type + # Integrate namespace if necessary + local_node = _create_xml_node(xml_name, xml_prefix, xml_ns) + local_node.text = str(new_attr) + serialized.append(local_node) # type: ignore + else: # JSON + for k in reversed(keys): # type: ignore + new_attr = {k: new_attr} + + _new_attr = new_attr + _serialized = serialized + for k in keys: # type: ignore + if k not in _serialized: + _serialized.update(_new_attr) # type: ignore + _new_attr = _new_attr[k] # type: ignore + _serialized = _serialized[k] + except ValueError as err: + if isinstance(err, SerializationError): + raise + + except (AttributeError, KeyError, TypeError) as err: + msg = "Attribute {} in object {} cannot be serialized.\n{}".format(attr_name, class_name, str(target_obj)) + raise SerializationError(msg) from err + return serialized + + def body(self, data, data_type, **kwargs): + """Serialize data intended for a request body. + + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: dict + :raises SerializationError: if serialization fails. + :raises ValueError: if data is None + :returns: The serialized request body + """ + + # Just in case this is a dict + internal_data_type_str = data_type.strip("[]{}") + internal_data_type = self.dependencies.get(internal_data_type_str, None) + try: + is_xml_model_serialization = kwargs["is_xml"] + except KeyError: + if internal_data_type and issubclass(internal_data_type, Model): + is_xml_model_serialization = kwargs.setdefault("is_xml", internal_data_type.is_xml_model()) + else: + is_xml_model_serialization = False + if internal_data_type and not isinstance(internal_data_type, Enum): + try: + deserializer = Deserializer(self.dependencies) + # Since it's on serialization, it's almost sure that format is not JSON REST + # We're not able to deal with additional properties for now. + deserializer.additional_properties_detection = False + if is_xml_model_serialization: + deserializer.key_extractors = [ # type: ignore + attribute_key_case_insensitive_extractor, + ] + else: + deserializer.key_extractors = [ + rest_key_case_insensitive_extractor, + attribute_key_case_insensitive_extractor, + last_rest_key_case_insensitive_extractor, + ] + data = deserializer._deserialize(data_type, data) # pylint: disable=protected-access + except DeserializationError as err: + raise SerializationError("Unable to build a model: " + str(err)) from err + + return self._serialize(data, data_type, **kwargs) + + def url(self, name, data, data_type, **kwargs): + """Serialize data intended for a URL path. + + :param str name: The name of the URL path parameter. + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str + :returns: The serialized URL path + :raises TypeError: if serialization fails. + :raises ValueError: if data is None + """ + try: + output = self.serialize_data(data, data_type, **kwargs) + if data_type == "bool": + output = json.dumps(output) + + if kwargs.get("skip_quote") is True: + output = str(output) + output = output.replace("{", quote("{")).replace("}", quote("}")) + else: + output = quote(str(output), safe="") + except SerializationError as exc: + raise TypeError("{} must be type {}.".format(name, data_type)) from exc + return output + + def query(self, name, data, data_type, **kwargs): + """Serialize data intended for a URL query. + + :param str name: The name of the query parameter. + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str, list + :raises TypeError: if serialization fails. + :raises ValueError: if data is None + :returns: The serialized query parameter + """ + try: + # Treat the list aside, since we don't want to encode the div separator + if data_type.startswith("["): + internal_data_type = data_type[1:-1] + do_quote = not kwargs.get("skip_quote", False) + return self.serialize_iter(data, internal_data_type, do_quote=do_quote, **kwargs) + + # Not a list, regular serialization + output = self.serialize_data(data, data_type, **kwargs) + if data_type == "bool": + output = json.dumps(output) + if kwargs.get("skip_quote") is True: + output = str(output) + else: + output = quote(str(output), safe="") + except SerializationError as exc: + raise TypeError("{} must be type {}.".format(name, data_type)) from exc + return str(output) + + def header(self, name, data, data_type, **kwargs): + """Serialize data intended for a request header. + + :param str name: The name of the header. + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str + :raises TypeError: if serialization fails. + :raises ValueError: if data is None + :returns: The serialized header + """ + try: + if data_type in ["[str]"]: + data = ["" if d is None else d for d in data] + + output = self.serialize_data(data, data_type, **kwargs) + if data_type == "bool": + output = json.dumps(output) + except SerializationError as exc: + raise TypeError("{} must be type {}.".format(name, data_type)) from exc + return str(output) + + def serialize_data(self, data, data_type, **kwargs): + """Serialize generic data according to supplied data type. + + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :raises AttributeError: if required data is None. + :raises ValueError: if data is None + :raises SerializationError: if serialization fails. + :returns: The serialized data. + :rtype: str, int, float, bool, dict, list + """ + if data is None: + raise ValueError("No value for given attribute") + + try: + if data is CoreNull: + return None + if data_type in self.basic_types.values(): + return self.serialize_basic(data, data_type, **kwargs) + + if data_type in self.serialize_type: + return self.serialize_type[data_type](data, **kwargs) + + # If dependencies is empty, try with current data class + # It has to be a subclass of Enum anyway + enum_type = self.dependencies.get(data_type, data.__class__) + if issubclass(enum_type, Enum): + return Serializer.serialize_enum(data, enum_obj=enum_type) + + iter_type = data_type[0] + data_type[-1] + if iter_type in self.serialize_type: + return self.serialize_type[iter_type](data, data_type[1:-1], **kwargs) + + except (ValueError, TypeError) as err: + msg = "Unable to serialize value: {!r} as type: {!r}." + raise SerializationError(msg.format(data, data_type)) from err + return self._serialize(data, **kwargs) + + @classmethod + def _get_custom_serializers(cls, data_type, **kwargs): # pylint: disable=inconsistent-return-statements + custom_serializer = kwargs.get("basic_types_serializers", {}).get(data_type) + if custom_serializer: + return custom_serializer + if kwargs.get("is_xml", False): + return cls._xml_basic_types_serializers.get(data_type) + + @classmethod + def serialize_basic(cls, data, data_type, **kwargs): + """Serialize basic builting data type. + Serializes objects to str, int, float or bool. + + Possible kwargs: + - basic_types_serializers dict[str, callable] : If set, use the callable as serializer + - is_xml bool : If set, use xml_basic_types_serializers + + :param obj data: Object to be serialized. + :param str data_type: Type of object in the iterable. + :rtype: str, int, float, bool + :return: serialized object + """ + custom_serializer = cls._get_custom_serializers(data_type, **kwargs) + if custom_serializer: + return custom_serializer(data) + if data_type == "str": + return cls.serialize_unicode(data) + return eval(data_type)(data) # nosec # pylint: disable=eval-used + + @classmethod + def serialize_unicode(cls, data): + """Special handling for serializing unicode strings in Py2. + Encode to UTF-8 if unicode, otherwise handle as a str. + + :param str data: Object to be serialized. + :rtype: str + :return: serialized object + """ + try: # If I received an enum, return its value + return data.value + except AttributeError: + pass + + try: + if isinstance(data, unicode): # type: ignore + # Don't change it, JSON and XML ElementTree are totally able + # to serialize correctly u'' strings + return data + except NameError: + return str(data) + return str(data) + + def serialize_iter(self, data, iter_type, div=None, **kwargs): + """Serialize iterable. + + Supported kwargs: + - serialization_ctxt dict : The current entry of _attribute_map, or same format. + serialization_ctxt['type'] should be same as data_type. + - is_xml bool : If set, serialize as XML + + :param list data: Object to be serialized. + :param str iter_type: Type of object in the iterable. + :param str div: If set, this str will be used to combine the elements + in the iterable into a combined string. Default is 'None'. + Defaults to False. + :rtype: list, str + :return: serialized iterable + """ + if isinstance(data, str): + raise SerializationError("Refuse str type as a valid iter type.") + + serialization_ctxt = kwargs.get("serialization_ctxt", {}) + is_xml = kwargs.get("is_xml", False) + + serialized = [] + for d in data: + try: + serialized.append(self.serialize_data(d, iter_type, **kwargs)) + except ValueError as err: + if isinstance(err, SerializationError): + raise + serialized.append(None) + + if kwargs.get("do_quote", False): + serialized = ["" if s is None else quote(str(s), safe="") for s in serialized] + + if div: + serialized = ["" if s is None else str(s) for s in serialized] + serialized = div.join(serialized) + + if "xml" in serialization_ctxt or is_xml: + # XML serialization is more complicated + xml_desc = serialization_ctxt.get("xml", {}) + xml_name = xml_desc.get("name") + if not xml_name: + xml_name = serialization_ctxt["key"] + + # Create a wrap node if necessary (use the fact that Element and list have "append") + is_wrapped = xml_desc.get("wrapped", False) + node_name = xml_desc.get("itemsName", xml_name) + if is_wrapped: + final_result = _create_xml_node(xml_name, xml_desc.get("prefix", None), xml_desc.get("ns", None)) + else: + final_result = [] + # All list elements to "local_node" + for el in serialized: + if isinstance(el, ET.Element): + el_node = el + else: + el_node = _create_xml_node(node_name, xml_desc.get("prefix", None), xml_desc.get("ns", None)) + if el is not None: # Otherwise it writes "None" :-p + el_node.text = str(el) + final_result.append(el_node) + return final_result + return serialized + + def serialize_dict(self, attr, dict_type, **kwargs): + """Serialize a dictionary of objects. + + :param dict attr: Object to be serialized. + :param str dict_type: Type of object in the dictionary. + :rtype: dict + :return: serialized dictionary + """ + serialization_ctxt = kwargs.get("serialization_ctxt", {}) + serialized = {} + for key, value in attr.items(): + try: + serialized[self.serialize_unicode(key)] = self.serialize_data(value, dict_type, **kwargs) + except ValueError as err: + if isinstance(err, SerializationError): + raise + serialized[self.serialize_unicode(key)] = None + + if "xml" in serialization_ctxt: + # XML serialization is more complicated + xml_desc = serialization_ctxt["xml"] + xml_name = xml_desc["name"] + + final_result = _create_xml_node(xml_name, xml_desc.get("prefix", None), xml_desc.get("ns", None)) + for key, value in serialized.items(): + ET.SubElement(final_result, key).text = value + return final_result + + return serialized + + def serialize_object(self, attr, **kwargs): # pylint: disable=too-many-return-statements + """Serialize a generic object. + This will be handled as a dictionary. If object passed in is not + a basic type (str, int, float, dict, list) it will simply be + cast to str. + + :param dict attr: Object to be serialized. + :rtype: dict or str + :return: serialized object + """ + if attr is None: + return None + if isinstance(attr, ET.Element): + return attr + obj_type = type(attr) + if obj_type in self.basic_types: + return self.serialize_basic(attr, self.basic_types[obj_type], **kwargs) + if obj_type is _long_type: + return self.serialize_long(attr) + if obj_type is str: + return self.serialize_unicode(attr) + if obj_type is datetime.datetime: + return self.serialize_iso(attr) + if obj_type is datetime.date: + return self.serialize_date(attr) + if obj_type is datetime.time: + return self.serialize_time(attr) + if obj_type is datetime.timedelta: + return self.serialize_duration(attr) + if obj_type is decimal.Decimal: + return self.serialize_decimal(attr) + + # If it's a model or I know this dependency, serialize as a Model + if obj_type in self.dependencies.values() or isinstance(attr, Model): + return self._serialize(attr) + + if obj_type == dict: + serialized = {} + for key, value in attr.items(): + try: + serialized[self.serialize_unicode(key)] = self.serialize_object(value, **kwargs) + except ValueError: + serialized[self.serialize_unicode(key)] = None + return serialized + + if obj_type == list: + serialized = [] + for obj in attr: + try: + serialized.append(self.serialize_object(obj, **kwargs)) + except ValueError: + pass + return serialized + return str(attr) + + @staticmethod + def serialize_enum(attr, enum_obj=None): + try: + result = attr.value + except AttributeError: + result = attr + try: + enum_obj(result) # type: ignore + return result + except ValueError as exc: + for enum_value in enum_obj: # type: ignore + if enum_value.value.lower() == str(attr).lower(): + return enum_value.value + error = "{!r} is not valid value for enum {!r}" + raise SerializationError(error.format(attr, enum_obj)) from exc + + @staticmethod + def serialize_bytearray(attr, **kwargs): # pylint: disable=unused-argument + """Serialize bytearray into base-64 string. + + :param str attr: Object to be serialized. + :rtype: str + :return: serialized base64 + """ + return b64encode(attr).decode() + + @staticmethod + def serialize_base64(attr, **kwargs): # pylint: disable=unused-argument + """Serialize str into base-64 string. + + :param str attr: Object to be serialized. + :rtype: str + :return: serialized base64 + """ + encoded = b64encode(attr).decode("ascii") + return encoded.strip("=").replace("+", "-").replace("/", "_") + + @staticmethod + def serialize_decimal(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Decimal object to float. + + :param decimal attr: Object to be serialized. + :rtype: float + :return: serialized decimal + """ + return float(attr) + + @staticmethod + def serialize_long(attr, **kwargs): # pylint: disable=unused-argument + """Serialize long (Py2) or int (Py3). + + :param int attr: Object to be serialized. + :rtype: int/long + :return: serialized long + """ + return _long_type(attr) + + @staticmethod + def serialize_date(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Date object into ISO-8601 formatted string. + + :param Date attr: Object to be serialized. + :rtype: str + :return: serialized date + """ + if isinstance(attr, str): + attr = isodate.parse_date(attr) + t = "{:04}-{:02}-{:02}".format(attr.year, attr.month, attr.day) + return t + + @staticmethod + def serialize_time(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Time object into ISO-8601 formatted string. + + :param datetime.time attr: Object to be serialized. + :rtype: str + :return: serialized time + """ + if isinstance(attr, str): + attr = isodate.parse_time(attr) + t = "{:02}:{:02}:{:02}".format(attr.hour, attr.minute, attr.second) + if attr.microsecond: + t += ".{:02}".format(attr.microsecond) + return t + + @staticmethod + def serialize_duration(attr, **kwargs): # pylint: disable=unused-argument + """Serialize TimeDelta object into ISO-8601 formatted string. + + :param TimeDelta attr: Object to be serialized. + :rtype: str + :return: serialized duration + """ + if isinstance(attr, str): + attr = isodate.parse_duration(attr) + return isodate.duration_isoformat(attr) + + @staticmethod + def serialize_rfc(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Datetime object into RFC-1123 formatted string. + + :param Datetime attr: Object to be serialized. + :rtype: str + :raises TypeError: if format invalid. + :return: serialized rfc + """ + try: + if not attr.tzinfo: + _LOGGER.warning("Datetime with no tzinfo will be considered UTC.") + utc = attr.utctimetuple() + except AttributeError as exc: + raise TypeError("RFC1123 object must be valid Datetime object.") from exc + + return "{}, {:02} {} {:04} {:02}:{:02}:{:02} GMT".format( + Serializer.days[utc.tm_wday], + utc.tm_mday, + Serializer.months[utc.tm_mon], + utc.tm_year, + utc.tm_hour, + utc.tm_min, + utc.tm_sec, + ) + + @staticmethod + def serialize_iso(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Datetime object into ISO-8601 formatted string. + + :param Datetime attr: Object to be serialized. + :rtype: str + :raises SerializationError: if format invalid. + :return: serialized iso + """ + if isinstance(attr, str): + attr = isodate.parse_datetime(attr) + try: + if not attr.tzinfo: + _LOGGER.warning("Datetime with no tzinfo will be considered UTC.") + utc = attr.utctimetuple() + if utc.tm_year > 9999 or utc.tm_year < 1: + raise OverflowError("Hit max or min date") + + microseconds = str(attr.microsecond).rjust(6, "0").rstrip("0").ljust(3, "0") + if microseconds: + microseconds = "." + microseconds + date = "{:04}-{:02}-{:02}T{:02}:{:02}:{:02}".format( + utc.tm_year, utc.tm_mon, utc.tm_mday, utc.tm_hour, utc.tm_min, utc.tm_sec + ) + return date + microseconds + "Z" + except (ValueError, OverflowError) as err: + msg = "Unable to serialize datetime object." + raise SerializationError(msg) from err + except AttributeError as err: + msg = "ISO-8601 object must be valid Datetime object." + raise TypeError(msg) from err + + @staticmethod + def serialize_unix(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Datetime object into IntTime format. + This is represented as seconds. + + :param Datetime attr: Object to be serialized. + :rtype: int + :raises SerializationError: if format invalid + :return: serialied unix + """ + if isinstance(attr, int): + return attr + try: + if not attr.tzinfo: + _LOGGER.warning("Datetime with no tzinfo will be considered UTC.") + return int(calendar.timegm(attr.utctimetuple())) + except AttributeError as exc: + raise TypeError("Unix time object must be valid Datetime object.") from exc + + +def rest_key_extractor(attr, attr_desc, data): # pylint: disable=unused-argument + key = attr_desc["key"] + working_data = data + + while "." in key: + # Need the cast, as for some reasons "split" is typed as list[str | Any] + dict_keys = cast(List[str], _FLATTEN.split(key)) + if len(dict_keys) == 1: + key = _decode_attribute_map_key(dict_keys[0]) + break + working_key = _decode_attribute_map_key(dict_keys[0]) + working_data = working_data.get(working_key, data) + if working_data is None: + # If at any point while following flatten JSON path see None, it means + # that all properties under are None as well + return None + key = ".".join(dict_keys[1:]) + + return working_data.get(key) + + +def rest_key_case_insensitive_extractor( # pylint: disable=unused-argument, inconsistent-return-statements + attr, attr_desc, data +): + key = attr_desc["key"] + working_data = data + + while "." in key: + dict_keys = _FLATTEN.split(key) + if len(dict_keys) == 1: + key = _decode_attribute_map_key(dict_keys[0]) + break + working_key = _decode_attribute_map_key(dict_keys[0]) + working_data = attribute_key_case_insensitive_extractor(working_key, None, working_data) + if working_data is None: + # If at any point while following flatten JSON path see None, it means + # that all properties under are None as well + return None + key = ".".join(dict_keys[1:]) + + if working_data: + return attribute_key_case_insensitive_extractor(key, None, working_data) + + +def last_rest_key_extractor(attr, attr_desc, data): # pylint: disable=unused-argument + """Extract the attribute in "data" based on the last part of the JSON path key. + + :param str attr: The attribute to extract + :param dict attr_desc: The attribute description + :param dict data: The data to extract from + :rtype: object + :returns: The extracted attribute + """ + key = attr_desc["key"] + dict_keys = _FLATTEN.split(key) + return attribute_key_extractor(dict_keys[-1], None, data) + + +def last_rest_key_case_insensitive_extractor(attr, attr_desc, data): # pylint: disable=unused-argument + """Extract the attribute in "data" based on the last part of the JSON path key. + + This is the case insensitive version of "last_rest_key_extractor" + :param str attr: The attribute to extract + :param dict attr_desc: The attribute description + :param dict data: The data to extract from + :rtype: object + :returns: The extracted attribute + """ + key = attr_desc["key"] + dict_keys = _FLATTEN.split(key) + return attribute_key_case_insensitive_extractor(dict_keys[-1], None, data) + + +def attribute_key_extractor(attr, _, data): + return data.get(attr) + + +def attribute_key_case_insensitive_extractor(attr, _, data): + found_key = None + lower_attr = attr.lower() + for key in data: + if lower_attr == key.lower(): + found_key = key + break + + return data.get(found_key) + + +def _extract_name_from_internal_type(internal_type): + """Given an internal type XML description, extract correct XML name with namespace. + + :param dict internal_type: An model type + :rtype: tuple + :returns: A tuple XML name + namespace dict + """ + internal_type_xml_map = getattr(internal_type, "_xml_map", {}) + xml_name = internal_type_xml_map.get("name", internal_type.__name__) + xml_ns = internal_type_xml_map.get("ns", None) + if xml_ns: + xml_name = "{{{}}}{}".format(xml_ns, xml_name) + return xml_name + + +def xml_key_extractor(attr, attr_desc, data): # pylint: disable=unused-argument,too-many-return-statements + if isinstance(data, dict): + return None + + # Test if this model is XML ready first + if not isinstance(data, ET.Element): + return None + + xml_desc = attr_desc.get("xml", {}) + xml_name = xml_desc.get("name", attr_desc["key"]) + + # Look for a children + is_iter_type = attr_desc["type"].startswith("[") + is_wrapped = xml_desc.get("wrapped", False) + internal_type = attr_desc.get("internalType", None) + internal_type_xml_map = getattr(internal_type, "_xml_map", {}) + + # Integrate namespace if necessary + xml_ns = xml_desc.get("ns", internal_type_xml_map.get("ns", None)) + if xml_ns: + xml_name = "{{{}}}{}".format(xml_ns, xml_name) + + # If it's an attribute, that's simple + if xml_desc.get("attr", False): + return data.get(xml_name) + + # If it's x-ms-text, that's simple too + if xml_desc.get("text", False): + return data.text + + # Scenario where I take the local name: + # - Wrapped node + # - Internal type is an enum (considered basic types) + # - Internal type has no XML/Name node + if is_wrapped or (internal_type and (issubclass(internal_type, Enum) or "name" not in internal_type_xml_map)): + children = data.findall(xml_name) + # If internal type has a local name and it's not a list, I use that name + elif not is_iter_type and internal_type and "name" in internal_type_xml_map: + xml_name = _extract_name_from_internal_type(internal_type) + children = data.findall(xml_name) + # That's an array + else: + if internal_type: # Complex type, ignore itemsName and use the complex type name + items_name = _extract_name_from_internal_type(internal_type) + else: + items_name = xml_desc.get("itemsName", xml_name) + children = data.findall(items_name) + + if len(children) == 0: + if is_iter_type: + if is_wrapped: + return None # is_wrapped no node, we want None + return [] # not wrapped, assume empty list + return None # Assume it's not there, maybe an optional node. + + # If is_iter_type and not wrapped, return all found children + if is_iter_type: + if not is_wrapped: + return children + # Iter and wrapped, should have found one node only (the wrap one) + if len(children) != 1: + raise DeserializationError( + "Tried to deserialize an array not wrapped, and found several nodes '{}'. Maybe you should declare this array as wrapped?".format( + xml_name + ) + ) + return list(children[0]) # Might be empty list and that's ok. + + # Here it's not a itertype, we should have found one element only or empty + if len(children) > 1: + raise DeserializationError("Find several XML '{}' where it was not expected".format(xml_name)) + return children[0] + + +class Deserializer: + """Response object model deserializer. + + :param dict classes: Class type dictionary for deserializing complex types. + :ivar list key_extractors: Ordered list of extractors to be used by this deserializer. + """ + + basic_types = {str: "str", int: "int", bool: "bool", float: "float"} + + valid_date = re.compile(r"\d{4}[-]\d{2}[-]\d{2}T\d{2}:\d{2}:\d{2}\.?\d*Z?[-+]?[\d{2}]?:?[\d{2}]?") + + def __init__(self, classes: Optional[Mapping[str, type]] = None) -> None: + self.deserialize_type = { + "iso-8601": Deserializer.deserialize_iso, + "rfc-1123": Deserializer.deserialize_rfc, + "unix-time": Deserializer.deserialize_unix, + "duration": Deserializer.deserialize_duration, + "date": Deserializer.deserialize_date, + "time": Deserializer.deserialize_time, + "decimal": Deserializer.deserialize_decimal, + "long": Deserializer.deserialize_long, + "bytearray": Deserializer.deserialize_bytearray, + "base64": Deserializer.deserialize_base64, + "object": self.deserialize_object, + "[]": self.deserialize_iter, + "{}": self.deserialize_dict, + } + self.deserialize_expected_types = { + "duration": (isodate.Duration, datetime.timedelta), + "iso-8601": (datetime.datetime), + } + self.dependencies: Dict[str, type] = dict(classes) if classes else {} + self.key_extractors = [rest_key_extractor, xml_key_extractor] + # Additional properties only works if the "rest_key_extractor" is used to + # extract the keys. Making it to work whatever the key extractor is too much + # complicated, with no real scenario for now. + # So adding a flag to disable additional properties detection. This flag should be + # used if your expect the deserialization to NOT come from a JSON REST syntax. + # Otherwise, result are unexpected + self.additional_properties_detection = True + + def __call__(self, target_obj, response_data, content_type=None): + """Call the deserializer to process a REST response. + + :param str target_obj: Target data type to deserialize to. + :param requests.Response response_data: REST response object. + :param str content_type: Swagger "produces" if available. + :raises DeserializationError: if deserialization fails. + :return: Deserialized object. + :rtype: object + """ + data = self._unpack_content(response_data, content_type) + return self._deserialize(target_obj, data) + + def _deserialize(self, target_obj, data): # pylint: disable=inconsistent-return-statements + """Call the deserializer on a model. + + Data needs to be already deserialized as JSON or XML ElementTree + + :param str target_obj: Target data type to deserialize to. + :param object data: Object to deserialize. + :raises DeserializationError: if deserialization fails. + :return: Deserialized object. + :rtype: object + """ + # This is already a model, go recursive just in case + if hasattr(data, "_attribute_map"): + constants = [name for name, config in getattr(data, "_validation", {}).items() if config.get("constant")] + try: + for attr, mapconfig in data._attribute_map.items(): # pylint: disable=protected-access + if attr in constants: + continue + value = getattr(data, attr) + if value is None: + continue + local_type = mapconfig["type"] + internal_data_type = local_type.strip("[]{}") + if internal_data_type not in self.dependencies or isinstance(internal_data_type, Enum): + continue + setattr(data, attr, self._deserialize(local_type, value)) + return data + except AttributeError: + return + + response, class_name = self._classify_target(target_obj, data) + + if isinstance(response, str): + return self.deserialize_data(data, response) + if isinstance(response, type) and issubclass(response, Enum): + return self.deserialize_enum(data, response) + + if data is None or data is CoreNull: + return data + try: + attributes = response._attribute_map # type: ignore # pylint: disable=protected-access + d_attrs = {} + for attr, attr_desc in attributes.items(): + # Check empty string. If it's not empty, someone has a real "additionalProperties"... + if attr == "additional_properties" and attr_desc["key"] == "": + continue + raw_value = None + # Enhance attr_desc with some dynamic data + attr_desc = attr_desc.copy() # Do a copy, do not change the real one + internal_data_type = attr_desc["type"].strip("[]{}") + if internal_data_type in self.dependencies: + attr_desc["internalType"] = self.dependencies[internal_data_type] + + for key_extractor in self.key_extractors: + found_value = key_extractor(attr, attr_desc, data) + if found_value is not None: + if raw_value is not None and raw_value != found_value: + msg = ( + "Ignoring extracted value '%s' from %s for key '%s'" + " (duplicate extraction, follow extractors order)" + ) + _LOGGER.warning(msg, found_value, key_extractor, attr) + continue + raw_value = found_value + + value = self.deserialize_data(raw_value, attr_desc["type"]) + d_attrs[attr] = value + except (AttributeError, TypeError, KeyError) as err: + msg = "Unable to deserialize to object: " + class_name # type: ignore + raise DeserializationError(msg) from err + additional_properties = self._build_additional_properties(attributes, data) + return self._instantiate_model(response, d_attrs, additional_properties) + + def _build_additional_properties(self, attribute_map, data): + if not self.additional_properties_detection: + return None + if "additional_properties" in attribute_map and attribute_map.get("additional_properties", {}).get("key") != "": + # Check empty string. If it's not empty, someone has a real "additionalProperties" + return None + if isinstance(data, ET.Element): + data = {el.tag: el.text for el in data} + + known_keys = { + _decode_attribute_map_key(_FLATTEN.split(desc["key"])[0]) + for desc in attribute_map.values() + if desc["key"] != "" + } + present_keys = set(data.keys()) + missing_keys = present_keys - known_keys + return {key: data[key] for key in missing_keys} + + def _classify_target(self, target, data): + """Check to see whether the deserialization target object can + be classified into a subclass. + Once classification has been determined, initialize object. + + :param str target: The target object type to deserialize to. + :param str/dict data: The response data to deserialize. + :return: The classified target object and its class name. + :rtype: tuple + """ + if target is None: + return None, None + + if isinstance(target, str): + try: + target = self.dependencies[target] + except KeyError: + return target, target + + try: + target = target._classify(data, self.dependencies) # type: ignore # pylint: disable=protected-access + except AttributeError: + pass # Target is not a Model, no classify + return target, target.__class__.__name__ # type: ignore + + def failsafe_deserialize(self, target_obj, data, content_type=None): + """Ignores any errors encountered in deserialization, + and falls back to not deserializing the object. Recommended + for use in error deserialization, as we want to return the + HttpResponseError to users, and not have them deal with + a deserialization error. + + :param str target_obj: The target object type to deserialize to. + :param str/dict data: The response data to deserialize. + :param str content_type: Swagger "produces" if available. + :return: Deserialized object. + :rtype: object + """ + try: + return self(target_obj, data, content_type=content_type) + except: # pylint: disable=bare-except + _LOGGER.debug( + "Ran into a deserialization error. Ignoring since this is failsafe deserialization", exc_info=True + ) + return None + + @staticmethod + def _unpack_content(raw_data, content_type=None): + """Extract the correct structure for deserialization. + + If raw_data is a PipelineResponse, try to extract the result of RawDeserializer. + if we can't, raise. Your Pipeline should have a RawDeserializer. + + If not a pipeline response and raw_data is bytes or string, use content-type + to decode it. If no content-type, try JSON. + + If raw_data is something else, bypass all logic and return it directly. + + :param obj raw_data: Data to be processed. + :param str content_type: How to parse if raw_data is a string/bytes. + :raises JSONDecodeError: If JSON is requested and parsing is impossible. + :raises UnicodeDecodeError: If bytes is not UTF8 + :rtype: object + :return: Unpacked content. + """ + # Assume this is enough to detect a Pipeline Response without importing it + context = getattr(raw_data, "context", {}) + if context: + if RawDeserializer.CONTEXT_NAME in context: + return context[RawDeserializer.CONTEXT_NAME] + raise ValueError("This pipeline didn't have the RawDeserializer policy; can't deserialize") + + # Assume this is enough to recognize universal_http.ClientResponse without importing it + if hasattr(raw_data, "body"): + return RawDeserializer.deserialize_from_http_generics(raw_data.text(), raw_data.headers) + + # Assume this enough to recognize requests.Response without importing it. + if hasattr(raw_data, "_content_consumed"): + return RawDeserializer.deserialize_from_http_generics(raw_data.text, raw_data.headers) + + if isinstance(raw_data, (str, bytes)) or hasattr(raw_data, "read"): + return RawDeserializer.deserialize_from_text(raw_data, content_type) # type: ignore + return raw_data + + def _instantiate_model(self, response, attrs, additional_properties=None): + """Instantiate a response model passing in deserialized args. + + :param Response response: The response model class. + :param dict attrs: The deserialized response attributes. + :param dict additional_properties: Additional properties to be set. + :rtype: Response + :return: The instantiated response model. + """ + if callable(response): + subtype = getattr(response, "_subtype_map", {}) + try: + readonly = [ + k + for k, v in response._validation.items() # pylint: disable=protected-access # type: ignore + if v.get("readonly") + ] + const = [ + k + for k, v in response._validation.items() # pylint: disable=protected-access # type: ignore + if v.get("constant") + ] + kwargs = {k: v for k, v in attrs.items() if k not in subtype and k not in readonly + const} + response_obj = response(**kwargs) + for attr in readonly: + setattr(response_obj, attr, attrs.get(attr)) + if additional_properties: + response_obj.additional_properties = additional_properties # type: ignore + return response_obj + except TypeError as err: + msg = "Unable to deserialize {} into model {}. ".format(kwargs, response) # type: ignore + raise DeserializationError(msg + str(err)) from err + else: + try: + for attr, value in attrs.items(): + setattr(response, attr, value) + return response + except Exception as exp: + msg = "Unable to populate response model. " + msg += "Type: {}, Error: {}".format(type(response), exp) + raise DeserializationError(msg) from exp + + def deserialize_data(self, data, data_type): # pylint: disable=too-many-return-statements + """Process data for deserialization according to data type. + + :param str data: The response string to be deserialized. + :param str data_type: The type to deserialize to. + :raises DeserializationError: if deserialization fails. + :return: Deserialized object. + :rtype: object + """ + if data is None: + return data + + try: + if not data_type: + return data + if data_type in self.basic_types.values(): + return self.deserialize_basic(data, data_type) + if data_type in self.deserialize_type: + if isinstance(data, self.deserialize_expected_types.get(data_type, tuple())): + return data + + is_a_text_parsing_type = lambda x: x not in [ # pylint: disable=unnecessary-lambda-assignment + "object", + "[]", + r"{}", + ] + if isinstance(data, ET.Element) and is_a_text_parsing_type(data_type) and not data.text: + return None + data_val = self.deserialize_type[data_type](data) + return data_val + + iter_type = data_type[0] + data_type[-1] + if iter_type in self.deserialize_type: + return self.deserialize_type[iter_type](data, data_type[1:-1]) + + obj_type = self.dependencies[data_type] + if issubclass(obj_type, Enum): + if isinstance(data, ET.Element): + data = data.text + return self.deserialize_enum(data, obj_type) + + except (ValueError, TypeError, AttributeError) as err: + msg = "Unable to deserialize response data." + msg += " Data: {}, {}".format(data, data_type) + raise DeserializationError(msg) from err + return self._deserialize(obj_type, data) + + def deserialize_iter(self, attr, iter_type): + """Deserialize an iterable. + + :param list attr: Iterable to be deserialized. + :param str iter_type: The type of object in the iterable. + :return: Deserialized iterable. + :rtype: list + """ + if attr is None: + return None + if isinstance(attr, ET.Element): # If I receive an element here, get the children + attr = list(attr) + if not isinstance(attr, (list, set)): + raise DeserializationError("Cannot deserialize as [{}] an object of type {}".format(iter_type, type(attr))) + return [self.deserialize_data(a, iter_type) for a in attr] + + def deserialize_dict(self, attr, dict_type): + """Deserialize a dictionary. + + :param dict/list attr: Dictionary to be deserialized. Also accepts + a list of key, value pairs. + :param str dict_type: The object type of the items in the dictionary. + :return: Deserialized dictionary. + :rtype: dict + """ + if isinstance(attr, list): + return {x["key"]: self.deserialize_data(x["value"], dict_type) for x in attr} + + if isinstance(attr, ET.Element): + # Transform value into {"Key": "value"} + attr = {el.tag: el.text for el in attr} + return {k: self.deserialize_data(v, dict_type) for k, v in attr.items()} + + def deserialize_object(self, attr, **kwargs): # pylint: disable=too-many-return-statements + """Deserialize a generic object. + This will be handled as a dictionary. + + :param dict attr: Dictionary to be deserialized. + :return: Deserialized object. + :rtype: dict + :raises TypeError: if non-builtin datatype encountered. + """ + if attr is None: + return None + if isinstance(attr, ET.Element): + # Do no recurse on XML, just return the tree as-is + return attr + if isinstance(attr, str): + return self.deserialize_basic(attr, "str") + obj_type = type(attr) + if obj_type in self.basic_types: + return self.deserialize_basic(attr, self.basic_types[obj_type]) + if obj_type is _long_type: + return self.deserialize_long(attr) + + if obj_type == dict: + deserialized = {} + for key, value in attr.items(): + try: + deserialized[key] = self.deserialize_object(value, **kwargs) + except ValueError: + deserialized[key] = None + return deserialized + + if obj_type == list: + deserialized = [] + for obj in attr: + try: + deserialized.append(self.deserialize_object(obj, **kwargs)) + except ValueError: + pass + return deserialized + + error = "Cannot deserialize generic object with type: " + raise TypeError(error + str(obj_type)) + + def deserialize_basic(self, attr, data_type): # pylint: disable=too-many-return-statements + """Deserialize basic builtin data type from string. + Will attempt to convert to str, int, float and bool. + This function will also accept '1', '0', 'true' and 'false' as + valid bool values. + + :param str attr: response string to be deserialized. + :param str data_type: deserialization data type. + :return: Deserialized basic type. + :rtype: str, int, float or bool + :raises TypeError: if string format is not valid. + """ + # If we're here, data is supposed to be a basic type. + # If it's still an XML node, take the text + if isinstance(attr, ET.Element): + attr = attr.text + if not attr: + if data_type == "str": + # None or '', node is empty string. + return "" + # None or '', node with a strong type is None. + # Don't try to model "empty bool" or "empty int" + return None + + if data_type == "bool": + if attr in [True, False, 1, 0]: + return bool(attr) + if isinstance(attr, str): + if attr.lower() in ["true", "1"]: + return True + if attr.lower() in ["false", "0"]: + return False + raise TypeError("Invalid boolean value: {}".format(attr)) + + if data_type == "str": + return self.deserialize_unicode(attr) + return eval(data_type)(attr) # nosec # pylint: disable=eval-used + + @staticmethod + def deserialize_unicode(data): + """Preserve unicode objects in Python 2, otherwise return data + as a string. + + :param str data: response string to be deserialized. + :return: Deserialized string. + :rtype: str or unicode + """ + # We might be here because we have an enum modeled as string, + # and we try to deserialize a partial dict with enum inside + if isinstance(data, Enum): + return data + + # Consider this is real string + try: + if isinstance(data, unicode): # type: ignore + return data + except NameError: + return str(data) + return str(data) + + @staticmethod + def deserialize_enum(data, enum_obj): + """Deserialize string into enum object. + + If the string is not a valid enum value it will be returned as-is + and a warning will be logged. + + :param str data: Response string to be deserialized. If this value is + None or invalid it will be returned as-is. + :param Enum enum_obj: Enum object to deserialize to. + :return: Deserialized enum object. + :rtype: Enum + """ + if isinstance(data, enum_obj) or data is None: + return data + if isinstance(data, Enum): + data = data.value + if isinstance(data, int): + # Workaround. We might consider remove it in the future. + try: + return list(enum_obj.__members__.values())[data] + except IndexError as exc: + error = "{!r} is not a valid index for enum {!r}" + raise DeserializationError(error.format(data, enum_obj)) from exc + try: + return enum_obj(str(data)) + except ValueError: + for enum_value in enum_obj: + if enum_value.value.lower() == str(data).lower(): + return enum_value + # We don't fail anymore for unknown value, we deserialize as a string + _LOGGER.warning("Deserializer is not able to find %s as valid enum in %s", data, enum_obj) + return Deserializer.deserialize_unicode(data) + + @staticmethod + def deserialize_bytearray(attr): + """Deserialize string into bytearray. + + :param str attr: response string to be deserialized. + :return: Deserialized bytearray + :rtype: bytearray + :raises TypeError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + return bytearray(b64decode(attr)) # type: ignore + + @staticmethod + def deserialize_base64(attr): + """Deserialize base64 encoded string into string. + + :param str attr: response string to be deserialized. + :return: Deserialized base64 string + :rtype: bytearray + :raises TypeError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + padding = "=" * (3 - (len(attr) + 3) % 4) # type: ignore + attr = attr + padding # type: ignore + encoded = attr.replace("-", "+").replace("_", "/") + return b64decode(encoded) + + @staticmethod + def deserialize_decimal(attr): + """Deserialize string into Decimal object. + + :param str attr: response string to be deserialized. + :return: Deserialized decimal + :raises DeserializationError: if string format invalid. + :rtype: decimal + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + return decimal.Decimal(str(attr)) # type: ignore + except decimal.DecimalException as err: + msg = "Invalid decimal {}".format(attr) + raise DeserializationError(msg) from err + + @staticmethod + def deserialize_long(attr): + """Deserialize string into long (Py2) or int (Py3). + + :param str attr: response string to be deserialized. + :return: Deserialized int + :rtype: long or int + :raises ValueError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + return _long_type(attr) # type: ignore + + @staticmethod + def deserialize_duration(attr): + """Deserialize ISO-8601 formatted string into TimeDelta object. + + :param str attr: response string to be deserialized. + :return: Deserialized duration + :rtype: TimeDelta + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + duration = isodate.parse_duration(attr) + except (ValueError, OverflowError, AttributeError) as err: + msg = "Cannot deserialize duration object." + raise DeserializationError(msg) from err + return duration + + @staticmethod + def deserialize_date(attr): + """Deserialize ISO-8601 formatted string into Date object. + + :param str attr: response string to be deserialized. + :return: Deserialized date + :rtype: Date + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + if re.search(r"[^\W\d_]", attr, re.I + re.U): # type: ignore + raise DeserializationError("Date must have only digits and -. Received: %s" % attr) + # This must NOT use defaultmonth/defaultday. Using None ensure this raises an exception. + return isodate.parse_date(attr, defaultmonth=0, defaultday=0) + + @staticmethod + def deserialize_time(attr): + """Deserialize ISO-8601 formatted string into time object. + + :param str attr: response string to be deserialized. + :return: Deserialized time + :rtype: datetime.time + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + if re.search(r"[^\W\d_]", attr, re.I + re.U): # type: ignore + raise DeserializationError("Date must have only digits and -. Received: %s" % attr) + return isodate.parse_time(attr) + + @staticmethod + def deserialize_rfc(attr): + """Deserialize RFC-1123 formatted string into Datetime object. + + :param str attr: response string to be deserialized. + :return: Deserialized RFC datetime + :rtype: Datetime + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + parsed_date = email.utils.parsedate_tz(attr) # type: ignore + date_obj = datetime.datetime( + *parsed_date[:6], tzinfo=datetime.timezone(datetime.timedelta(minutes=(parsed_date[9] or 0) / 60)) + ) + if not date_obj.tzinfo: + date_obj = date_obj.astimezone(tz=TZ_UTC) + except ValueError as err: + msg = "Cannot deserialize to rfc datetime object." + raise DeserializationError(msg) from err + return date_obj + + @staticmethod + def deserialize_iso(attr): + """Deserialize ISO-8601 formatted string into Datetime object. + + :param str attr: response string to be deserialized. + :return: Deserialized ISO datetime + :rtype: Datetime + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + attr = attr.upper() # type: ignore + match = Deserializer.valid_date.match(attr) + if not match: + raise ValueError("Invalid datetime string: " + attr) + + check_decimal = attr.split(".") + if len(check_decimal) > 1: + decimal_str = "" + for digit in check_decimal[1]: + if digit.isdigit(): + decimal_str += digit + else: + break + if len(decimal_str) > 6: + attr = attr.replace(decimal_str, decimal_str[0:6]) + + date_obj = isodate.parse_datetime(attr) + test_utc = date_obj.utctimetuple() + if test_utc.tm_year > 9999 or test_utc.tm_year < 1: + raise OverflowError("Hit max or min date") + except (ValueError, OverflowError, AttributeError) as err: + msg = "Cannot deserialize datetime object." + raise DeserializationError(msg) from err + return date_obj + + @staticmethod + def deserialize_unix(attr): + """Serialize Datetime object into IntTime format. + This is represented as seconds. + + :param int attr: Object to be serialized. + :return: Deserialized datetime + :rtype: Datetime + :raises DeserializationError: if format invalid + """ + if isinstance(attr, ET.Element): + attr = int(attr.text) # type: ignore + try: + attr = int(attr) + date_obj = datetime.datetime.fromtimestamp(attr, TZ_UTC) + except ValueError as err: + msg = "Cannot deserialize to unix datetime object." + raise DeserializationError(msg) from err + return date_obj diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiKeywordOnly/multiapikeywordonly/aio/_multiapi_service_client.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiKeywordOnly/multiapikeywordonly/aio/_multiapi_service_client.py index 7d181c0167b..e26236b56e0 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiKeywordOnly/multiapikeywordonly/aio/_multiapi_service_client.py +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiKeywordOnly/multiapikeywordonly/aio/_multiapi_service_client.py @@ -17,7 +17,7 @@ from azure.profiles import KnownProfiles, ProfileDefinition from azure.profiles.multiapiclient import MultiApiClientMixin -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import MultiapiServiceClientConfiguration from ._operations_mixin import MultiapiServiceClientOperationsMixin diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiKeywordOnly/multiapikeywordonly/aio/_operations_mixin.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiKeywordOnly/multiapikeywordonly/aio/_operations_mixin.py index 5d76a53b11c..6a029aa5206 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiKeywordOnly/multiapikeywordonly/aio/_operations_mixin.py +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiKeywordOnly/multiapikeywordonly/aio/_operations_mixin.py @@ -8,7 +8,7 @@ # Changes may cause incorrect behavior and will be lost if the code is # regenerated. # -------------------------------------------------------------------------- -from .._serialization import Serializer, Deserializer +from .._utils.serialization import Serializer, Deserializer from io import IOBase from typing import Any, AsyncIterable, AsyncIterator, IO, Optional, Union diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiKeywordOnly/multiapikeywordonly/v1/_metadata.json b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiKeywordOnly/multiapikeywordonly/v1/_metadata.json index bb512943425..ddb890b56d7 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiKeywordOnly/multiapikeywordonly/v1/_metadata.json +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiKeywordOnly/multiapikeywordonly/v1/_metadata.json @@ -10,8 +10,8 @@ "azure_arm": false, "has_public_lro_operations": true, "client_side_validation": false, - "sync_imports": "{\"conditional\": {\"stdlib\": {\"typing\": [\"Any\", \"Optional\"]}}, \"regular\": {\"sdkcore\": {\"azure.core\": [\"PipelineClient\"], \"azure.core.pipeline\": [\"policies\"], \"azure.profiles\": [\"KnownProfiles\", \"ProfileDefinition\"], \"azure.profiles.multiapiclient\": [\"MultiApiClientMixin\"]}, \"local\": {\"._configuration\": [\"MultiapiServiceClientConfiguration\"], \".._serialization\": [\"Deserializer\", \"Serializer\"], \"._operations_mixin\": [\"MultiapiServiceClientOperationsMixin\"]}, \"stdlib\": {\"typing_extensions\": [\"Self\"]}}, \"typing\": {\"sdkcore\": {\"azure.core.credentials\": [\"TokenCredential\"]}}}", - "async_imports": "{\"conditional\": {\"stdlib\": {\"typing\": [\"Any\", \"Optional\"]}}, \"regular\": {\"sdkcore\": {\"azure.core\": [\"AsyncPipelineClient\"], \"azure.core.pipeline\": [\"policies\"], \"azure.profiles\": [\"KnownProfiles\", \"ProfileDefinition\"], \"azure.profiles.multiapiclient\": [\"MultiApiClientMixin\"]}, \"local\": {\"._configuration\": [\"MultiapiServiceClientConfiguration\"], \"..._serialization\": [\"Deserializer\", \"Serializer\"], \"._operations_mixin\": [\"MultiapiServiceClientOperationsMixin\"]}, \"stdlib\": {\"typing_extensions\": [\"Self\"]}}, \"typing\": {\"sdkcore\": {\"azure.core.credentials_async\": [\"AsyncTokenCredential\"]}}}" + "sync_imports": "{\"conditional\": {\"stdlib\": {\"typing\": [\"Any\", \"Optional\"]}}, \"regular\": {\"sdkcore\": {\"azure.core\": [\"PipelineClient\"], \"azure.core.pipeline\": [\"policies\"], \"azure.profiles\": [\"KnownProfiles\", \"ProfileDefinition\"], \"azure.profiles.multiapiclient\": [\"MultiApiClientMixin\"]}, \"local\": {\"._configuration\": [\"MultiapiServiceClientConfiguration\"], \"._utils.serialization\": [\"Deserializer\", \"Serializer\"], \"._operations_mixin\": [\"MultiapiServiceClientOperationsMixin\"]}, \"stdlib\": {\"typing_extensions\": [\"Self\"]}}, \"typing\": {\"sdkcore\": {\"azure.core.credentials\": [\"TokenCredential\"]}}}", + "async_imports": "{\"conditional\": {\"stdlib\": {\"typing\": [\"Any\", \"Optional\"]}}, \"regular\": {\"sdkcore\": {\"azure.core\": [\"AsyncPipelineClient\"], \"azure.core.pipeline\": [\"policies\"], \"azure.profiles\": [\"KnownProfiles\", \"ProfileDefinition\"], \"azure.profiles.multiapiclient\": [\"MultiApiClientMixin\"]}, \"local\": {\"._configuration\": [\"MultiapiServiceClientConfiguration\"], \".._utils.serialization\": [\"Deserializer\", \"Serializer\"], \"._operations_mixin\": [\"MultiapiServiceClientOperationsMixin\"]}, \"stdlib\": {\"typing_extensions\": [\"Self\"]}}, \"typing\": {\"sdkcore\": {\"azure.core.credentials_async\": [\"AsyncTokenCredential\"]}}}" }, "global_parameters": { "sync": { diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiKeywordOnly/multiapikeywordonly/v1/_multiapi_service_client.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiKeywordOnly/multiapikeywordonly/v1/_multiapi_service_client.py index 5da3e5ac4fd..0835474f3b7 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiKeywordOnly/multiapikeywordonly/v1/_multiapi_service_client.py +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiKeywordOnly/multiapikeywordonly/v1/_multiapi_service_client.py @@ -15,8 +15,8 @@ from azure.core.rest import HttpRequest, HttpResponse from . import models as _models -from .._serialization import Deserializer, Serializer from ._configuration import MultiapiServiceClientConfiguration +from ._utils.serialization import Deserializer, Serializer from .operations import MultiapiServiceClientOperationsMixin, OperationGroupOneOperations if TYPE_CHECKING: diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiKeywordOnly/multiapikeywordonly/v1/_utils/__init__.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiKeywordOnly/multiapikeywordonly/v1/_utils/__init__.py new file mode 100644 index 00000000000..0af9b28f660 --- /dev/null +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiKeywordOnly/multiapikeywordonly/v1/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Header/header/_serialization.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiKeywordOnly/multiapikeywordonly/v1/_utils/serialization.py similarity index 100% rename from packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Header/header/_serialization.py rename to packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiKeywordOnly/multiapikeywordonly/v1/_utils/serialization.py diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiKeywordOnly/multiapikeywordonly/v1/_utils/utils.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiKeywordOnly/multiapikeywordonly/v1/_utils/utils.py new file mode 100644 index 00000000000..39b612f39a9 --- /dev/null +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiKeywordOnly/multiapikeywordonly/v1/_utils/utils.py @@ -0,0 +1,25 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from abc import ABC +from typing import Generic, TYPE_CHECKING, TypeVar + +if TYPE_CHECKING: + from .serialization import Deserializer, Serializer + + +TClient = TypeVar("TClient") +TConfig = TypeVar("TConfig") + + +class ClientMixinABC(ABC, Generic[TClient, TConfig]): + """DO NOT use this class. It is for internal typing use only.""" + + _client: TClient + _config: TConfig + _serialize: "Serializer" + _deserialize: "Deserializer" diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiKeywordOnly/multiapikeywordonly/v1/_vendor.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiKeywordOnly/multiapikeywordonly/v1/_vendor.py deleted file mode 100644 index 70517e0b7af..00000000000 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiKeywordOnly/multiapikeywordonly/v1/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) AutoRest Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import MultiapiServiceClientConfiguration - -if TYPE_CHECKING: - from azure.core import PipelineClient - - from .._serialization import Deserializer, Serializer - - -class MultiapiServiceClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "PipelineClient" - _config: MultiapiServiceClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiKeywordOnly/multiapikeywordonly/v1/aio/_multiapi_service_client.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiKeywordOnly/multiapikeywordonly/v1/aio/_multiapi_service_client.py index 56d449e4ff3..8fcadb39990 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiKeywordOnly/multiapikeywordonly/v1/aio/_multiapi_service_client.py +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiKeywordOnly/multiapikeywordonly/v1/aio/_multiapi_service_client.py @@ -15,7 +15,7 @@ from azure.core.rest import AsyncHttpResponse, HttpRequest from .. import models as _models -from ..._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import MultiapiServiceClientConfiguration from .operations import MultiapiServiceClientOperationsMixin, OperationGroupOneOperations diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiKeywordOnly/multiapikeywordonly/v1/aio/_vendor.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiKeywordOnly/multiapikeywordonly/v1/aio/_vendor.py deleted file mode 100644 index 9c6fd05bb21..00000000000 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiKeywordOnly/multiapikeywordonly/v1/aio/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) AutoRest Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import MultiapiServiceClientConfiguration - -if TYPE_CHECKING: - from azure.core import AsyncPipelineClient - - from ..._serialization import Deserializer, Serializer - - -class MultiapiServiceClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "AsyncPipelineClient" - _config: MultiapiServiceClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiKeywordOnly/multiapikeywordonly/v1/aio/operations/_multiapi_service_client_operations.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiKeywordOnly/multiapikeywordonly/v1/aio/operations/_multiapi_service_client_operations.py index df508921432..abbf6c9e847 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiKeywordOnly/multiapikeywordonly/v1/aio/operations/_multiapi_service_client_operations.py +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiKeywordOnly/multiapikeywordonly/v1/aio/operations/_multiapi_service_client_operations.py @@ -11,6 +11,7 @@ from typing import Any, AsyncIterable, AsyncIterator, Callable, Dict, IO, Optional, TypeVar, Union, cast, overload import urllib.parse +from azure.core import AsyncPipelineClient from azure.core.async_paging import AsyncItemPaged, AsyncList from azure.core.exceptions import ( ClientAuthenticationError, @@ -31,19 +32,20 @@ from azure.core.utils import case_insensitive_dict from ... import models as _models +from ..._utils.utils import ClientMixinABC from ...operations._multiapi_service_client_operations import ( build_test_different_calls_request, build_test_lro_and_paging_request, build_test_lro_request, build_test_one_request, ) -from .._vendor import MultiapiServiceClientMixinABC +from .._configuration import MultiapiServiceClientConfiguration T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, AsyncHttpResponse], T, Dict[str, Any]], Any]] -class MultiapiServiceClientOperationsMixin(MultiapiServiceClientMixinABC): +class MultiapiServiceClientOperationsMixin(ClientMixinABC[AsyncPipelineClient, MultiapiServiceClientConfiguration]): def _api_version(self, op_name: str) -> str: # pylint: disable=unused-argument try: return self._config.api_version diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiKeywordOnly/multiapikeywordonly/v1/aio/operations/_operation_group_one_operations.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiKeywordOnly/multiapikeywordonly/v1/aio/operations/_operation_group_one_operations.py index 80910d13a38..5027fb9df33 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiKeywordOnly/multiapikeywordonly/v1/aio/operations/_operation_group_one_operations.py +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiKeywordOnly/multiapikeywordonly/v1/aio/operations/_operation_group_one_operations.py @@ -23,7 +23,7 @@ from azure.core.utils import case_insensitive_dict from ... import models as _models -from ...._serialization import Deserializer, Serializer +from ..._utils.serialization import Deserializer, Serializer from ...operations._operation_group_one_operations import build_test_two_request from .._configuration import MultiapiServiceClientConfiguration diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiKeywordOnly/multiapikeywordonly/v1/models/_models_py3.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiKeywordOnly/multiapikeywordonly/v1/models/_models_py3.py index 57b29f30605..7b4bec0e8ab 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiKeywordOnly/multiapikeywordonly/v1/models/_models_py3.py +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiKeywordOnly/multiapikeywordonly/v1/models/_models_py3.py @@ -8,7 +8,7 @@ from typing import Any, List, Optional, TYPE_CHECKING -from ... import _serialization +from .._utils import serialization as _serialization if TYPE_CHECKING: from .. import models as _models diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiKeywordOnly/multiapikeywordonly/v1/operations/_multiapi_service_client_operations.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiKeywordOnly/multiapikeywordonly/v1/operations/_multiapi_service_client_operations.py index b680022374c..f065ca1a3da 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiKeywordOnly/multiapikeywordonly/v1/operations/_multiapi_service_client_operations.py +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiKeywordOnly/multiapikeywordonly/v1/operations/_multiapi_service_client_operations.py @@ -10,6 +10,7 @@ from typing import Any, Callable, Dict, IO, Iterable, Iterator, Optional, TypeVar, Union, cast, overload import urllib.parse +from azure.core import PipelineClient from azure.core.exceptions import ( ClientAuthenticationError, HttpResponseError, @@ -29,8 +30,9 @@ from azure.core.utils import case_insensitive_dict from .. import models as _models -from ..._serialization import Serializer -from .._vendor import MultiapiServiceClientMixinABC +from .._configuration import MultiapiServiceClientConfiguration +from .._utils.serialization import Serializer +from .._utils.utils import ClientMixinABC T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] @@ -120,7 +122,7 @@ def build_test_different_calls_request(*, greeting_in_english: str, **kwargs: An return HttpRequest(method="GET", url=_url, params=_params, headers=_headers, **kwargs) -class MultiapiServiceClientOperationsMixin(MultiapiServiceClientMixinABC): +class MultiapiServiceClientOperationsMixin(ClientMixinABC[PipelineClient, MultiapiServiceClientConfiguration]): def _api_version(self, op_name: str) -> str: # pylint: disable=unused-argument try: return self._config.api_version diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiKeywordOnly/multiapikeywordonly/v1/operations/_operation_group_one_operations.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiKeywordOnly/multiapikeywordonly/v1/operations/_operation_group_one_operations.py index 2f406a6f9a9..0f32caa72cb 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiKeywordOnly/multiapikeywordonly/v1/operations/_operation_group_one_operations.py +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiKeywordOnly/multiapikeywordonly/v1/operations/_operation_group_one_operations.py @@ -23,8 +23,8 @@ from azure.core.utils import case_insensitive_dict from .. import models as _models -from ..._serialization import Deserializer, Serializer from .._configuration import MultiapiServiceClientConfiguration +from .._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiKeywordOnly/multiapikeywordonly/v2/_metadata.json b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiKeywordOnly/multiapikeywordonly/v2/_metadata.json index 547d03862f9..19f935c927e 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiKeywordOnly/multiapikeywordonly/v2/_metadata.json +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiKeywordOnly/multiapikeywordonly/v2/_metadata.json @@ -10,8 +10,8 @@ "azure_arm": false, "has_public_lro_operations": false, "client_side_validation": false, - "sync_imports": "{\"conditional\": {\"stdlib\": {\"typing\": [\"Any\", \"Optional\"]}}, \"regular\": {\"sdkcore\": {\"azure.core\": [\"PipelineClient\"], \"azure.core.pipeline\": [\"policies\"], \"azure.profiles\": [\"KnownProfiles\", \"ProfileDefinition\"], \"azure.profiles.multiapiclient\": [\"MultiApiClientMixin\"]}, \"local\": {\"._configuration\": [\"MultiapiServiceClientConfiguration\"], \".._serialization\": [\"Deserializer\", \"Serializer\"], \"._operations_mixin\": [\"MultiapiServiceClientOperationsMixin\"]}, \"stdlib\": {\"typing_extensions\": [\"Self\"]}}, \"typing\": {\"sdkcore\": {\"azure.core.credentials\": [\"TokenCredential\"]}}}", - "async_imports": "{\"conditional\": {\"stdlib\": {\"typing\": [\"Any\", \"Optional\"]}}, \"regular\": {\"sdkcore\": {\"azure.core\": [\"AsyncPipelineClient\"], \"azure.core.pipeline\": [\"policies\"], \"azure.profiles\": [\"KnownProfiles\", \"ProfileDefinition\"], \"azure.profiles.multiapiclient\": [\"MultiApiClientMixin\"]}, \"local\": {\"._configuration\": [\"MultiapiServiceClientConfiguration\"], \"..._serialization\": [\"Deserializer\", \"Serializer\"], \"._operations_mixin\": [\"MultiapiServiceClientOperationsMixin\"]}, \"stdlib\": {\"typing_extensions\": [\"Self\"]}}, \"typing\": {\"sdkcore\": {\"azure.core.credentials_async\": [\"AsyncTokenCredential\"]}}}" + "sync_imports": "{\"conditional\": {\"stdlib\": {\"typing\": [\"Any\", \"Optional\"]}}, \"regular\": {\"sdkcore\": {\"azure.core\": [\"PipelineClient\"], \"azure.core.pipeline\": [\"policies\"], \"azure.profiles\": [\"KnownProfiles\", \"ProfileDefinition\"], \"azure.profiles.multiapiclient\": [\"MultiApiClientMixin\"]}, \"local\": {\"._configuration\": [\"MultiapiServiceClientConfiguration\"], \"._utils.serialization\": [\"Deserializer\", \"Serializer\"], \"._operations_mixin\": [\"MultiapiServiceClientOperationsMixin\"]}, \"stdlib\": {\"typing_extensions\": [\"Self\"]}}, \"typing\": {\"sdkcore\": {\"azure.core.credentials\": [\"TokenCredential\"]}}}", + "async_imports": "{\"conditional\": {\"stdlib\": {\"typing\": [\"Any\", \"Optional\"]}}, \"regular\": {\"sdkcore\": {\"azure.core\": [\"AsyncPipelineClient\"], \"azure.core.pipeline\": [\"policies\"], \"azure.profiles\": [\"KnownProfiles\", \"ProfileDefinition\"], \"azure.profiles.multiapiclient\": [\"MultiApiClientMixin\"]}, \"local\": {\"._configuration\": [\"MultiapiServiceClientConfiguration\"], \".._utils.serialization\": [\"Deserializer\", \"Serializer\"], \"._operations_mixin\": [\"MultiapiServiceClientOperationsMixin\"]}, \"stdlib\": {\"typing_extensions\": [\"Self\"]}}, \"typing\": {\"sdkcore\": {\"azure.core.credentials_async\": [\"AsyncTokenCredential\"]}}}" }, "global_parameters": { "sync": { diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiKeywordOnly/multiapikeywordonly/v2/_multiapi_service_client.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiKeywordOnly/multiapikeywordonly/v2/_multiapi_service_client.py index f0691ac1113..06870d5fb01 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiKeywordOnly/multiapikeywordonly/v2/_multiapi_service_client.py +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiKeywordOnly/multiapikeywordonly/v2/_multiapi_service_client.py @@ -15,8 +15,8 @@ from azure.core.rest import HttpRequest, HttpResponse from . import models as _models -from .._serialization import Deserializer, Serializer from ._configuration import MultiapiServiceClientConfiguration +from ._utils.serialization import Deserializer, Serializer from .operations import MultiapiServiceClientOperationsMixin, OperationGroupOneOperations, OperationGroupTwoOperations if TYPE_CHECKING: diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiKeywordOnly/multiapikeywordonly/v2/_utils/__init__.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiKeywordOnly/multiapikeywordonly/v2/_utils/__init__.py new file mode 100644 index 00000000000..0af9b28f660 --- /dev/null +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiKeywordOnly/multiapikeywordonly/v2/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Http/httpinfrastructure/_serialization.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiKeywordOnly/multiapikeywordonly/v2/_utils/serialization.py similarity index 100% rename from packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Http/httpinfrastructure/_serialization.py rename to packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiKeywordOnly/multiapikeywordonly/v2/_utils/serialization.py diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiKeywordOnly/multiapikeywordonly/v2/_utils/utils.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiKeywordOnly/multiapikeywordonly/v2/_utils/utils.py new file mode 100644 index 00000000000..39b612f39a9 --- /dev/null +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiKeywordOnly/multiapikeywordonly/v2/_utils/utils.py @@ -0,0 +1,25 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from abc import ABC +from typing import Generic, TYPE_CHECKING, TypeVar + +if TYPE_CHECKING: + from .serialization import Deserializer, Serializer + + +TClient = TypeVar("TClient") +TConfig = TypeVar("TConfig") + + +class ClientMixinABC(ABC, Generic[TClient, TConfig]): + """DO NOT use this class. It is for internal typing use only.""" + + _client: TClient + _config: TConfig + _serialize: "Serializer" + _deserialize: "Deserializer" diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiKeywordOnly/multiapikeywordonly/v2/_vendor.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiKeywordOnly/multiapikeywordonly/v2/_vendor.py deleted file mode 100644 index 70517e0b7af..00000000000 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiKeywordOnly/multiapikeywordonly/v2/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) AutoRest Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import MultiapiServiceClientConfiguration - -if TYPE_CHECKING: - from azure.core import PipelineClient - - from .._serialization import Deserializer, Serializer - - -class MultiapiServiceClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "PipelineClient" - _config: MultiapiServiceClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiKeywordOnly/multiapikeywordonly/v2/aio/_multiapi_service_client.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiKeywordOnly/multiapikeywordonly/v2/aio/_multiapi_service_client.py index d5281ac051e..f95c900ea0f 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiKeywordOnly/multiapikeywordonly/v2/aio/_multiapi_service_client.py +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiKeywordOnly/multiapikeywordonly/v2/aio/_multiapi_service_client.py @@ -15,7 +15,7 @@ from azure.core.rest import AsyncHttpResponse, HttpRequest from .. import models as _models -from ..._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import MultiapiServiceClientConfiguration from .operations import MultiapiServiceClientOperationsMixin, OperationGroupOneOperations, OperationGroupTwoOperations diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiKeywordOnly/multiapikeywordonly/v2/aio/_vendor.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiKeywordOnly/multiapikeywordonly/v2/aio/_vendor.py deleted file mode 100644 index 9c6fd05bb21..00000000000 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiKeywordOnly/multiapikeywordonly/v2/aio/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) AutoRest Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import MultiapiServiceClientConfiguration - -if TYPE_CHECKING: - from azure.core import AsyncPipelineClient - - from ..._serialization import Deserializer, Serializer - - -class MultiapiServiceClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "AsyncPipelineClient" - _config: MultiapiServiceClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiKeywordOnly/multiapikeywordonly/v2/aio/operations/_multiapi_service_client_operations.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiKeywordOnly/multiapikeywordonly/v2/aio/operations/_multiapi_service_client_operations.py index d5bd47a9acb..60de0ba7ae5 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiKeywordOnly/multiapikeywordonly/v2/aio/operations/_multiapi_service_client_operations.py +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiKeywordOnly/multiapikeywordonly/v2/aio/operations/_multiapi_service_client_operations.py @@ -9,6 +9,7 @@ from collections.abc import MutableMapping from typing import Any, Callable, Dict, Optional, TypeVar +from azure.core import AsyncPipelineClient from azure.core.exceptions import ( ClientAuthenticationError, HttpResponseError, @@ -23,14 +24,15 @@ from azure.core.utils import case_insensitive_dict from ... import models as _models +from ..._utils.utils import ClientMixinABC from ...operations._multiapi_service_client_operations import build_test_different_calls_request, build_test_one_request -from .._vendor import MultiapiServiceClientMixinABC +from .._configuration import MultiapiServiceClientConfiguration T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, AsyncHttpResponse], T, Dict[str, Any]], Any]] -class MultiapiServiceClientOperationsMixin(MultiapiServiceClientMixinABC): +class MultiapiServiceClientOperationsMixin(ClientMixinABC[AsyncPipelineClient, MultiapiServiceClientConfiguration]): def _api_version(self, op_name: str) -> str: # pylint: disable=unused-argument try: return self._config.api_version diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiKeywordOnly/multiapikeywordonly/v2/aio/operations/_operation_group_one_operations.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiKeywordOnly/multiapikeywordonly/v2/aio/operations/_operation_group_one_operations.py index d5536916a1e..29b61c84d7d 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiKeywordOnly/multiapikeywordonly/v2/aio/operations/_operation_group_one_operations.py +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiKeywordOnly/multiapikeywordonly/v2/aio/operations/_operation_group_one_operations.py @@ -24,7 +24,7 @@ from azure.core.utils import case_insensitive_dict from ... import models as _models -from ...._serialization import Deserializer, Serializer +from ..._utils.serialization import Deserializer, Serializer from ...operations._operation_group_one_operations import build_test_three_request, build_test_two_request from .._configuration import MultiapiServiceClientConfiguration diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiKeywordOnly/multiapikeywordonly/v2/aio/operations/_operation_group_two_operations.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiKeywordOnly/multiapikeywordonly/v2/aio/operations/_operation_group_two_operations.py index c9eea682813..fff2ed46149 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiKeywordOnly/multiapikeywordonly/v2/aio/operations/_operation_group_two_operations.py +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiKeywordOnly/multiapikeywordonly/v2/aio/operations/_operation_group_two_operations.py @@ -23,7 +23,7 @@ from azure.core.utils import case_insensitive_dict from ... import models as _models -from ...._serialization import Deserializer, Serializer +from ..._utils.serialization import Deserializer, Serializer from ...operations._operation_group_two_operations import build_test_four_request from .._configuration import MultiapiServiceClientConfiguration diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiKeywordOnly/multiapikeywordonly/v2/models/_models_py3.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiKeywordOnly/multiapikeywordonly/v2/models/_models_py3.py index 46990252065..a00726a3da2 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiKeywordOnly/multiapikeywordonly/v2/models/_models_py3.py +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiKeywordOnly/multiapikeywordonly/v2/models/_models_py3.py @@ -8,7 +8,7 @@ from typing import Any, Optional -from ... import _serialization +from .._utils import serialization as _serialization class Error(_serialization.Model): diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiKeywordOnly/multiapikeywordonly/v2/operations/_multiapi_service_client_operations.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiKeywordOnly/multiapikeywordonly/v2/operations/_multiapi_service_client_operations.py index 2ad5e361c60..909b6bc8c4c 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiKeywordOnly/multiapikeywordonly/v2/operations/_multiapi_service_client_operations.py +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiKeywordOnly/multiapikeywordonly/v2/operations/_multiapi_service_client_operations.py @@ -8,6 +8,7 @@ from collections.abc import MutableMapping from typing import Any, Callable, Dict, Optional, TypeVar +from azure.core import PipelineClient from azure.core.exceptions import ( ClientAuthenticationError, HttpResponseError, @@ -22,8 +23,9 @@ from azure.core.utils import case_insensitive_dict from .. import models as _models -from ..._serialization import Serializer -from .._vendor import MultiapiServiceClientMixinABC +from .._configuration import MultiapiServiceClientConfiguration +from .._utils.serialization import Serializer +from .._utils.utils import ClientMixinABC T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] @@ -78,7 +80,7 @@ def build_test_different_calls_request( return HttpRequest(method="GET", url=_url, params=_params, headers=_headers, **kwargs) -class MultiapiServiceClientOperationsMixin(MultiapiServiceClientMixinABC): +class MultiapiServiceClientOperationsMixin(ClientMixinABC[PipelineClient, MultiapiServiceClientConfiguration]): def _api_version(self, op_name: str) -> str: # pylint: disable=unused-argument try: return self._config.api_version diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiKeywordOnly/multiapikeywordonly/v2/operations/_operation_group_one_operations.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiKeywordOnly/multiapikeywordonly/v2/operations/_operation_group_one_operations.py index f22d5af73bf..bd570e246e8 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiKeywordOnly/multiapikeywordonly/v2/operations/_operation_group_one_operations.py +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiKeywordOnly/multiapikeywordonly/v2/operations/_operation_group_one_operations.py @@ -24,8 +24,8 @@ from azure.core.utils import case_insensitive_dict from .. import models as _models -from ..._serialization import Deserializer, Serializer from .._configuration import MultiapiServiceClientConfiguration +from .._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiKeywordOnly/multiapikeywordonly/v2/operations/_operation_group_two_operations.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiKeywordOnly/multiapikeywordonly/v2/operations/_operation_group_two_operations.py index b74edd63161..7c77a85df64 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiKeywordOnly/multiapikeywordonly/v2/operations/_operation_group_two_operations.py +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiKeywordOnly/multiapikeywordonly/v2/operations/_operation_group_two_operations.py @@ -23,8 +23,8 @@ from azure.core.utils import case_insensitive_dict from .. import models as _models -from ..._serialization import Deserializer, Serializer from .._configuration import MultiapiServiceClientConfiguration +from .._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiKeywordOnly/multiapikeywordonly/v3/_metadata.json b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiKeywordOnly/multiapikeywordonly/v3/_metadata.json index 93cada4e403..048049ad679 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiKeywordOnly/multiapikeywordonly/v3/_metadata.json +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiKeywordOnly/multiapikeywordonly/v3/_metadata.json @@ -10,8 +10,8 @@ "azure_arm": false, "has_public_lro_operations": false, "client_side_validation": false, - "sync_imports": "{\"conditional\": {\"stdlib\": {\"typing\": [\"Any\", \"Optional\"]}}, \"regular\": {\"sdkcore\": {\"azure.core\": [\"PipelineClient\"], \"azure.core.pipeline\": [\"policies\"], \"azure.profiles\": [\"KnownProfiles\", \"ProfileDefinition\"], \"azure.profiles.multiapiclient\": [\"MultiApiClientMixin\"]}, \"local\": {\"._configuration\": [\"MultiapiServiceClientConfiguration\"], \".._serialization\": [\"Deserializer\", \"Serializer\"], \"._operations_mixin\": [\"MultiapiServiceClientOperationsMixin\"]}, \"stdlib\": {\"typing_extensions\": [\"Self\"]}}, \"typing\": {\"sdkcore\": {\"azure.core.credentials\": [\"TokenCredential\"]}}}", - "async_imports": "{\"conditional\": {\"stdlib\": {\"typing\": [\"Any\", \"Optional\"]}}, \"regular\": {\"sdkcore\": {\"azure.core\": [\"AsyncPipelineClient\"], \"azure.core.pipeline\": [\"policies\"], \"azure.profiles\": [\"KnownProfiles\", \"ProfileDefinition\"], \"azure.profiles.multiapiclient\": [\"MultiApiClientMixin\"]}, \"local\": {\"._configuration\": [\"MultiapiServiceClientConfiguration\"], \"..._serialization\": [\"Deserializer\", \"Serializer\"], \"._operations_mixin\": [\"MultiapiServiceClientOperationsMixin\"]}, \"stdlib\": {\"typing_extensions\": [\"Self\"]}}, \"typing\": {\"sdkcore\": {\"azure.core.credentials_async\": [\"AsyncTokenCredential\"]}}}" + "sync_imports": "{\"conditional\": {\"stdlib\": {\"typing\": [\"Any\", \"Optional\"]}}, \"regular\": {\"sdkcore\": {\"azure.core\": [\"PipelineClient\"], \"azure.core.pipeline\": [\"policies\"], \"azure.profiles\": [\"KnownProfiles\", \"ProfileDefinition\"], \"azure.profiles.multiapiclient\": [\"MultiApiClientMixin\"]}, \"local\": {\"._configuration\": [\"MultiapiServiceClientConfiguration\"], \"._utils.serialization\": [\"Deserializer\", \"Serializer\"], \"._operations_mixin\": [\"MultiapiServiceClientOperationsMixin\"]}, \"stdlib\": {\"typing_extensions\": [\"Self\"]}}, \"typing\": {\"sdkcore\": {\"azure.core.credentials\": [\"TokenCredential\"]}}}", + "async_imports": "{\"conditional\": {\"stdlib\": {\"typing\": [\"Any\", \"Optional\"]}}, \"regular\": {\"sdkcore\": {\"azure.core\": [\"AsyncPipelineClient\"], \"azure.core.pipeline\": [\"policies\"], \"azure.profiles\": [\"KnownProfiles\", \"ProfileDefinition\"], \"azure.profiles.multiapiclient\": [\"MultiApiClientMixin\"]}, \"local\": {\"._configuration\": [\"MultiapiServiceClientConfiguration\"], \".._utils.serialization\": [\"Deserializer\", \"Serializer\"], \"._operations_mixin\": [\"MultiapiServiceClientOperationsMixin\"]}, \"stdlib\": {\"typing_extensions\": [\"Self\"]}}, \"typing\": {\"sdkcore\": {\"azure.core.credentials_async\": [\"AsyncTokenCredential\"]}}}" }, "global_parameters": { "sync": { diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiKeywordOnly/multiapikeywordonly/v3/_multiapi_service_client.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiKeywordOnly/multiapikeywordonly/v3/_multiapi_service_client.py index f18802a8e7e..fa506d30455 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiKeywordOnly/multiapikeywordonly/v3/_multiapi_service_client.py +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiKeywordOnly/multiapikeywordonly/v3/_multiapi_service_client.py @@ -15,8 +15,8 @@ from azure.core.rest import HttpRequest, HttpResponse from . import models as _models -from .._serialization import Deserializer, Serializer from ._configuration import MultiapiServiceClientConfiguration +from ._utils.serialization import Deserializer, Serializer from .operations import MultiapiServiceClientOperationsMixin, OperationGroupOneOperations, OperationGroupTwoOperations if TYPE_CHECKING: diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiKeywordOnly/multiapikeywordonly/v3/_utils/__init__.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiKeywordOnly/multiapikeywordonly/v3/_utils/__init__.py new file mode 100644 index 00000000000..0af9b28f660 --- /dev/null +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiKeywordOnly/multiapikeywordonly/v3/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/IncorrectErrorResponse/incorrecterrorresponse/_serialization.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiKeywordOnly/multiapikeywordonly/v3/_utils/serialization.py similarity index 100% rename from packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/IncorrectErrorResponse/incorrecterrorresponse/_serialization.py rename to packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiKeywordOnly/multiapikeywordonly/v3/_utils/serialization.py diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiKeywordOnly/multiapikeywordonly/v3/_utils/utils.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiKeywordOnly/multiapikeywordonly/v3/_utils/utils.py new file mode 100644 index 00000000000..39b612f39a9 --- /dev/null +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiKeywordOnly/multiapikeywordonly/v3/_utils/utils.py @@ -0,0 +1,25 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from abc import ABC +from typing import Generic, TYPE_CHECKING, TypeVar + +if TYPE_CHECKING: + from .serialization import Deserializer, Serializer + + +TClient = TypeVar("TClient") +TConfig = TypeVar("TConfig") + + +class ClientMixinABC(ABC, Generic[TClient, TConfig]): + """DO NOT use this class. It is for internal typing use only.""" + + _client: TClient + _config: TConfig + _serialize: "Serializer" + _deserialize: "Deserializer" diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiKeywordOnly/multiapikeywordonly/v3/_vendor.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiKeywordOnly/multiapikeywordonly/v3/_vendor.py deleted file mode 100644 index 70517e0b7af..00000000000 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiKeywordOnly/multiapikeywordonly/v3/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) AutoRest Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import MultiapiServiceClientConfiguration - -if TYPE_CHECKING: - from azure.core import PipelineClient - - from .._serialization import Deserializer, Serializer - - -class MultiapiServiceClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "PipelineClient" - _config: MultiapiServiceClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiKeywordOnly/multiapikeywordonly/v3/aio/_multiapi_service_client.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiKeywordOnly/multiapikeywordonly/v3/aio/_multiapi_service_client.py index d2c643af9f8..830e21d4773 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiKeywordOnly/multiapikeywordonly/v3/aio/_multiapi_service_client.py +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiKeywordOnly/multiapikeywordonly/v3/aio/_multiapi_service_client.py @@ -15,7 +15,7 @@ from azure.core.rest import AsyncHttpResponse, HttpRequest from .. import models as _models -from ..._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import MultiapiServiceClientConfiguration from .operations import MultiapiServiceClientOperationsMixin, OperationGroupOneOperations, OperationGroupTwoOperations diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiKeywordOnly/multiapikeywordonly/v3/aio/_vendor.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiKeywordOnly/multiapikeywordonly/v3/aio/_vendor.py deleted file mode 100644 index 9c6fd05bb21..00000000000 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiKeywordOnly/multiapikeywordonly/v3/aio/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) AutoRest Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import MultiapiServiceClientConfiguration - -if TYPE_CHECKING: - from azure.core import AsyncPipelineClient - - from ..._serialization import Deserializer, Serializer - - -class MultiapiServiceClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "AsyncPipelineClient" - _config: MultiapiServiceClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiKeywordOnly/multiapikeywordonly/v3/aio/operations/_multiapi_service_client_operations.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiKeywordOnly/multiapikeywordonly/v3/aio/operations/_multiapi_service_client_operations.py index a7731a31a42..1c163bfec0c 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiKeywordOnly/multiapikeywordonly/v3/aio/operations/_multiapi_service_client_operations.py +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiKeywordOnly/multiapikeywordonly/v3/aio/operations/_multiapi_service_client_operations.py @@ -10,6 +10,7 @@ from typing import Any, AsyncIterable, Callable, Dict, Optional, TypeVar import urllib.parse +from azure.core import AsyncPipelineClient from azure.core.async_paging import AsyncItemPaged, AsyncList from azure.core.exceptions import ( ClientAuthenticationError, @@ -26,17 +27,18 @@ from azure.core.utils import case_insensitive_dict from ... import models as _models +from ..._utils.utils import ClientMixinABC from ...operations._multiapi_service_client_operations import ( build_test_different_calls_request, build_test_paging_request, ) -from .._vendor import MultiapiServiceClientMixinABC +from .._configuration import MultiapiServiceClientConfiguration T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, AsyncHttpResponse], T, Dict[str, Any]], Any]] -class MultiapiServiceClientOperationsMixin(MultiapiServiceClientMixinABC): +class MultiapiServiceClientOperationsMixin(ClientMixinABC[AsyncPipelineClient, MultiapiServiceClientConfiguration]): def _api_version(self, op_name: str) -> str: # pylint: disable=unused-argument try: return self._config.api_version diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiKeywordOnly/multiapikeywordonly/v3/aio/operations/_operation_group_one_operations.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiKeywordOnly/multiapikeywordonly/v3/aio/operations/_operation_group_one_operations.py index 8b95a4e957c..1c4bcfbea99 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiKeywordOnly/multiapikeywordonly/v3/aio/operations/_operation_group_one_operations.py +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiKeywordOnly/multiapikeywordonly/v3/aio/operations/_operation_group_one_operations.py @@ -27,7 +27,7 @@ from azure.core.utils import case_insensitive_dict from ... import models as _models -from ...._serialization import Deserializer, Serializer +from ..._utils.serialization import Deserializer, Serializer from ...operations._operation_group_one_operations import ( build_test_operation_group_paging_request, build_test_two_request, diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiKeywordOnly/multiapikeywordonly/v3/aio/operations/_operation_group_two_operations.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiKeywordOnly/multiapikeywordonly/v3/aio/operations/_operation_group_two_operations.py index e61f2125ca1..36a3a5d4aac 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiKeywordOnly/multiapikeywordonly/v3/aio/operations/_operation_group_two_operations.py +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiKeywordOnly/multiapikeywordonly/v3/aio/operations/_operation_group_two_operations.py @@ -24,7 +24,7 @@ from azure.core.utils import case_insensitive_dict from ... import models as _models -from ...._serialization import Deserializer, Serializer +from ..._utils.serialization import Deserializer, Serializer from ...operations._operation_group_two_operations import build_test_five_request, build_test_four_request from .._configuration import MultiapiServiceClientConfiguration diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiKeywordOnly/multiapikeywordonly/v3/models/_models_py3.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiKeywordOnly/multiapikeywordonly/v3/models/_models_py3.py index 558a0c7c0ca..09275b98e34 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiKeywordOnly/multiapikeywordonly/v3/models/_models_py3.py +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiKeywordOnly/multiapikeywordonly/v3/models/_models_py3.py @@ -8,7 +8,7 @@ from typing import Any, List, Optional, TYPE_CHECKING -from ... import _serialization +from .._utils import serialization as _serialization if TYPE_CHECKING: from .. import models as _models diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiKeywordOnly/multiapikeywordonly/v3/operations/_multiapi_service_client_operations.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiKeywordOnly/multiapikeywordonly/v3/operations/_multiapi_service_client_operations.py index 37cd439de76..7b9358f48b3 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiKeywordOnly/multiapikeywordonly/v3/operations/_multiapi_service_client_operations.py +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiKeywordOnly/multiapikeywordonly/v3/operations/_multiapi_service_client_operations.py @@ -9,6 +9,7 @@ from typing import Any, Callable, Dict, Iterable, Optional, TypeVar import urllib.parse +from azure.core import PipelineClient from azure.core.exceptions import ( ClientAuthenticationError, HttpResponseError, @@ -24,8 +25,9 @@ from azure.core.utils import case_insensitive_dict from .. import models as _models -from ..._serialization import Serializer -from .._vendor import MultiapiServiceClientMixinABC +from .._configuration import MultiapiServiceClientConfiguration +from .._utils.serialization import Serializer +from .._utils.utils import ClientMixinABC T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] @@ -78,7 +80,7 @@ def build_test_different_calls_request( return HttpRequest(method="GET", url=_url, params=_params, headers=_headers, **kwargs) -class MultiapiServiceClientOperationsMixin(MultiapiServiceClientMixinABC): +class MultiapiServiceClientOperationsMixin(ClientMixinABC[PipelineClient, MultiapiServiceClientConfiguration]): def _api_version(self, op_name: str) -> str: # pylint: disable=unused-argument try: return self._config.api_version diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiKeywordOnly/multiapikeywordonly/v3/operations/_operation_group_one_operations.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiKeywordOnly/multiapikeywordonly/v3/operations/_operation_group_one_operations.py index e7a71fe7d1f..641ed51aab2 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiKeywordOnly/multiapikeywordonly/v3/operations/_operation_group_one_operations.py +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiKeywordOnly/multiapikeywordonly/v3/operations/_operation_group_one_operations.py @@ -26,8 +26,8 @@ from azure.core.utils import case_insensitive_dict from .. import models as _models -from ..._serialization import Deserializer, Serializer from .._configuration import MultiapiServiceClientConfiguration +from .._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiKeywordOnly/multiapikeywordonly/v3/operations/_operation_group_two_operations.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiKeywordOnly/multiapikeywordonly/v3/operations/_operation_group_two_operations.py index 3527442d81a..9b97d963362 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiKeywordOnly/multiapikeywordonly/v3/operations/_operation_group_two_operations.py +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiKeywordOnly/multiapikeywordonly/v3/operations/_operation_group_two_operations.py @@ -24,8 +24,8 @@ from azure.core.utils import case_insensitive_dict from .. import models as _models -from ..._serialization import Deserializer, Serializer from .._configuration import MultiapiServiceClientConfiguration +from .._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiNoAsync/multiapinoasync/_multiapi_service_client.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiNoAsync/multiapinoasync/_multiapi_service_client.py index 57929fcd5ab..c5f938de0be 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiNoAsync/multiapinoasync/_multiapi_service_client.py +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiNoAsync/multiapinoasync/_multiapi_service_client.py @@ -22,7 +22,7 @@ from ._configuration import MultiapiServiceClientConfiguration from ._operations_mixin import MultiapiServiceClientOperationsMixin -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer if TYPE_CHECKING: # pylint: disable=unused-import,ungrouped-imports diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiNoAsync/multiapinoasync/_operations_mixin.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiNoAsync/multiapinoasync/_operations_mixin.py index 20d0e76db11..4fd13508d15 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiNoAsync/multiapinoasync/_operations_mixin.py +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiNoAsync/multiapinoasync/_operations_mixin.py @@ -8,7 +8,7 @@ # Changes may cause incorrect behavior and will be lost if the code is # regenerated. # -------------------------------------------------------------------------- -from ._serialization import Serializer, Deserializer +from ._utils.serialization import Serializer, Deserializer from io import IOBase from typing import Any, IO, Iterable, Iterator, Optional, Union diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiNoAsync/multiapinoasync/_utils/__init__.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiNoAsync/multiapinoasync/_utils/__init__.py new file mode 100644 index 00000000000..59333308532 --- /dev/null +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiNoAsync/multiapinoasync/_utils/__init__.py @@ -0,0 +1,10 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is +# regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiNoAsync/multiapinoasync/_utils/serialization.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiNoAsync/multiapinoasync/_utils/serialization.py new file mode 100644 index 00000000000..05bcd7d403a --- /dev/null +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiNoAsync/multiapinoasync/_utils/serialization.py @@ -0,0 +1,2025 @@ +# coding=utf-8 + +# pyright: reportUnnecessaryTypeIgnoreComment=false + +from base64 import b64decode, b64encode +import calendar +import datetime +import decimal +import email +from enum import Enum +import json +import logging +import re +import sys +import codecs +from typing import ( + Dict, + Any, + cast, + Optional, + Union, + AnyStr, + IO, + Mapping, + Callable, + MutableMapping, + List, +) + +try: + from urllib import quote # type: ignore +except ImportError: + from urllib.parse import quote +import xml.etree.ElementTree as ET + +import isodate # type: ignore +from typing_extensions import Self + +from azure.core.exceptions import DeserializationError, SerializationError +from azure.core.serialization import NULL as CoreNull + +_BOM = codecs.BOM_UTF8.decode(encoding="utf-8") + +JSON = MutableMapping[str, Any] + + +class RawDeserializer: + + # Accept "text" because we're open minded people... + JSON_REGEXP = re.compile(r"^(application|text)/([a-z+.]+\+)?json$") + + # Name used in context + CONTEXT_NAME = "deserialized_data" + + @classmethod + def deserialize_from_text(cls, data: Optional[Union[AnyStr, IO]], content_type: Optional[str] = None) -> Any: + """Decode data according to content-type. + + Accept a stream of data as well, but will be load at once in memory for now. + + If no content-type, will return the string version (not bytes, not stream) + + :param data: Input, could be bytes or stream (will be decoded with UTF8) or text + :type data: str or bytes or IO + :param str content_type: The content type. + :return: The deserialized data. + :rtype: object + """ + if hasattr(data, "read"): + # Assume a stream + data = cast(IO, data).read() + + if isinstance(data, bytes): + data_as_str = data.decode(encoding="utf-8-sig") + else: + # Explain to mypy the correct type. + data_as_str = cast(str, data) + + # Remove Byte Order Mark if present in string + data_as_str = data_as_str.lstrip(_BOM) + + if content_type is None: + return data + + if cls.JSON_REGEXP.match(content_type): + try: + return json.loads(data_as_str) + except ValueError as err: + raise DeserializationError("JSON is invalid: {}".format(err), err) from err + elif "xml" in (content_type or []): + try: + + try: + if isinstance(data, unicode): # type: ignore + # If I'm Python 2.7 and unicode XML will scream if I try a "fromstring" on unicode string + data_as_str = data_as_str.encode(encoding="utf-8") # type: ignore + except NameError: + pass + + return ET.fromstring(data_as_str) # nosec + except ET.ParseError as err: + # It might be because the server has an issue, and returned JSON with + # content-type XML.... + # So let's try a JSON load, and if it's still broken + # let's flow the initial exception + def _json_attemp(data): + try: + return True, json.loads(data) + except ValueError: + return False, None # Don't care about this one + + success, json_result = _json_attemp(data) + if success: + return json_result + # If i'm here, it's not JSON, it's not XML, let's scream + # and raise the last context in this block (the XML exception) + # The function hack is because Py2.7 messes up with exception + # context otherwise. + _LOGGER.critical("Wasn't XML not JSON, failing") + raise DeserializationError("XML is invalid") from err + elif content_type.startswith("text/"): + return data_as_str + raise DeserializationError("Cannot deserialize content-type: {}".format(content_type)) + + @classmethod + def deserialize_from_http_generics(cls, body_bytes: Optional[Union[AnyStr, IO]], headers: Mapping) -> Any: + """Deserialize from HTTP response. + + Use bytes and headers to NOT use any requests/aiohttp or whatever + specific implementation. + Headers will tested for "content-type" + + :param bytes body_bytes: The body of the response. + :param dict headers: The headers of the response. + :returns: The deserialized data. + :rtype: object + """ + # Try to use content-type from headers if available + content_type = None + if "content-type" in headers: + content_type = headers["content-type"].split(";")[0].strip().lower() + # Ouch, this server did not declare what it sent... + # Let's guess it's JSON... + # Also, since Autorest was considering that an empty body was a valid JSON, + # need that test as well.... + else: + content_type = "application/json" + + if body_bytes: + return cls.deserialize_from_text(body_bytes, content_type) + return None + + +_LOGGER = logging.getLogger(__name__) + +try: + _long_type = long # type: ignore +except NameError: + _long_type = int + +TZ_UTC = datetime.timezone.utc + +_FLATTEN = re.compile(r"(? None: + self.additional_properties: Optional[Dict[str, Any]] = {} + for k in kwargs: # pylint: disable=consider-using-dict-items + if k not in self._attribute_map: + _LOGGER.warning("%s is not a known attribute of class %s and will be ignored", k, self.__class__) + elif k in self._validation and self._validation[k].get("readonly", False): + _LOGGER.warning("Readonly attribute %s will be ignored in class %s", k, self.__class__) + else: + setattr(self, k, kwargs[k]) + + def __eq__(self, other: Any) -> bool: + """Compare objects by comparing all attributes. + + :param object other: The object to compare + :returns: True if objects are equal + :rtype: bool + """ + if isinstance(other, self.__class__): + return self.__dict__ == other.__dict__ + return False + + def __ne__(self, other: Any) -> bool: + """Compare objects by comparing all attributes. + + :param object other: The object to compare + :returns: True if objects are not equal + :rtype: bool + """ + return not self.__eq__(other) + + def __str__(self) -> str: + return str(self.__dict__) + + @classmethod + def enable_additional_properties_sending(cls) -> None: + cls._attribute_map["additional_properties"] = {"key": "", "type": "{object}"} + + @classmethod + def is_xml_model(cls) -> bool: + try: + cls._xml_map # type: ignore + except AttributeError: + return False + return True + + @classmethod + def _create_xml_node(cls): + """Create XML node. + + :returns: The XML node + :rtype: xml.etree.ElementTree.Element + """ + try: + xml_map = cls._xml_map # type: ignore + except AttributeError: + xml_map = {} + + return _create_xml_node(xml_map.get("name", cls.__name__), xml_map.get("prefix", None), xml_map.get("ns", None)) + + def serialize(self, keep_readonly: bool = False, **kwargs: Any) -> JSON: + """Return the JSON that would be sent to server from this model. + + This is an alias to `as_dict(full_restapi_key_transformer, keep_readonly=False)`. + + If you want XML serialization, you can pass the kwargs is_xml=True. + + :param bool keep_readonly: If you want to serialize the readonly attributes + :returns: A dict JSON compatible object + :rtype: dict + """ + serializer = Serializer(self._infer_class_models()) + return serializer._serialize( # type: ignore # pylint: disable=protected-access + self, keep_readonly=keep_readonly, **kwargs + ) + + def as_dict( + self, + keep_readonly: bool = True, + key_transformer: Callable[[str, Dict[str, Any], Any], Any] = attribute_transformer, + **kwargs: Any + ) -> JSON: + """Return a dict that can be serialized using json.dump. + + Advanced usage might optionally use a callback as parameter: + + .. code::python + + def my_key_transformer(key, attr_desc, value): + return key + + Key is the attribute name used in Python. Attr_desc + is a dict of metadata. Currently contains 'type' with the + msrest type and 'key' with the RestAPI encoded key. + Value is the current value in this object. + + The string returned will be used to serialize the key. + If the return type is a list, this is considered hierarchical + result dict. + + See the three examples in this file: + + - attribute_transformer + - full_restapi_key_transformer + - last_restapi_key_transformer + + If you want XML serialization, you can pass the kwargs is_xml=True. + + :param bool keep_readonly: If you want to serialize the readonly attributes + :param function key_transformer: A key transformer function. + :returns: A dict JSON compatible object + :rtype: dict + """ + serializer = Serializer(self._infer_class_models()) + return serializer._serialize( # type: ignore # pylint: disable=protected-access + self, key_transformer=key_transformer, keep_readonly=keep_readonly, **kwargs + ) + + @classmethod + def _infer_class_models(cls): + try: + str_models = cls.__module__.rsplit(".", 1)[0] + models = sys.modules[str_models] + client_models = {k: v for k, v in models.__dict__.items() if isinstance(v, type)} + if cls.__name__ not in client_models: + raise ValueError("Not Autorest generated code") + except Exception: # pylint: disable=broad-exception-caught + # Assume it's not Autorest generated (tests?). Add ourselves as dependencies. + client_models = {cls.__name__: cls} + return client_models + + @classmethod + def deserialize(cls, data: Any, content_type: Optional[str] = None) -> Self: + """Parse a str using the RestAPI syntax and return a model. + + :param str data: A str using RestAPI structure. JSON by default. + :param str content_type: JSON by default, set application/xml if XML. + :returns: An instance of this model + :raises DeserializationError: if something went wrong + :rtype: Self + """ + deserializer = Deserializer(cls._infer_class_models()) + return deserializer(cls.__name__, data, content_type=content_type) # type: ignore + + @classmethod + def from_dict( + cls, + data: Any, + key_extractors: Optional[Callable[[str, Dict[str, Any], Any], Any]] = None, + content_type: Optional[str] = None, + ) -> Self: + """Parse a dict using given key extractor return a model. + + By default consider key + extractors (rest_key_case_insensitive_extractor, attribute_key_case_insensitive_extractor + and last_rest_key_case_insensitive_extractor) + + :param dict data: A dict using RestAPI structure + :param function key_extractors: A key extractor function. + :param str content_type: JSON by default, set application/xml if XML. + :returns: An instance of this model + :raises DeserializationError: if something went wrong + :rtype: Self + """ + deserializer = Deserializer(cls._infer_class_models()) + deserializer.key_extractors = ( # type: ignore + [ # type: ignore + attribute_key_case_insensitive_extractor, + rest_key_case_insensitive_extractor, + last_rest_key_case_insensitive_extractor, + ] + if key_extractors is None + else key_extractors + ) + return deserializer(cls.__name__, data, content_type=content_type) # type: ignore + + @classmethod + def _flatten_subtype(cls, key, objects): + if "_subtype_map" not in cls.__dict__: + return {} + result = dict(cls._subtype_map[key]) + for valuetype in cls._subtype_map[key].values(): + result.update(objects[valuetype]._flatten_subtype(key, objects)) # pylint: disable=protected-access + return result + + @classmethod + def _classify(cls, response, objects): + """Check the class _subtype_map for any child classes. + We want to ignore any inherited _subtype_maps. + + :param dict response: The initial data + :param dict objects: The class objects + :returns: The class to be used + :rtype: class + """ + for subtype_key in cls.__dict__.get("_subtype_map", {}).keys(): + subtype_value = None + + if not isinstance(response, ET.Element): + rest_api_response_key = cls._get_rest_key_parts(subtype_key)[-1] + subtype_value = response.get(rest_api_response_key, None) or response.get(subtype_key, None) + else: + subtype_value = xml_key_extractor(subtype_key, cls._attribute_map[subtype_key], response) + if subtype_value: + # Try to match base class. Can be class name only + # (bug to fix in Autorest to support x-ms-discriminator-name) + if cls.__name__ == subtype_value: + return cls + flatten_mapping_type = cls._flatten_subtype(subtype_key, objects) + try: + return objects[flatten_mapping_type[subtype_value]] # type: ignore + except KeyError: + _LOGGER.warning( + "Subtype value %s has no mapping, use base class %s.", + subtype_value, + cls.__name__, + ) + break + else: + _LOGGER.warning("Discriminator %s is absent or null, use base class %s.", subtype_key, cls.__name__) + break + return cls + + @classmethod + def _get_rest_key_parts(cls, attr_key): + """Get the RestAPI key of this attr, split it and decode part + :param str attr_key: Attribute key must be in attribute_map. + :returns: A list of RestAPI part + :rtype: list + """ + rest_split_key = _FLATTEN.split(cls._attribute_map[attr_key]["key"]) + return [_decode_attribute_map_key(key_part) for key_part in rest_split_key] + + +def _decode_attribute_map_key(key): + """This decode a key in an _attribute_map to the actual key we want to look at + inside the received data. + + :param str key: A key string from the generated code + :returns: The decoded key + :rtype: str + """ + return key.replace("\\.", ".") + + +class Serializer: # pylint: disable=too-many-public-methods + """Request object model serializer.""" + + basic_types = {str: "str", int: "int", bool: "bool", float: "float"} + + _xml_basic_types_serializers = {"bool": lambda x: str(x).lower()} + days = {0: "Mon", 1: "Tue", 2: "Wed", 3: "Thu", 4: "Fri", 5: "Sat", 6: "Sun"} + months = { + 1: "Jan", + 2: "Feb", + 3: "Mar", + 4: "Apr", + 5: "May", + 6: "Jun", + 7: "Jul", + 8: "Aug", + 9: "Sep", + 10: "Oct", + 11: "Nov", + 12: "Dec", + } + validation = { + "min_length": lambda x, y: len(x) < y, + "max_length": lambda x, y: len(x) > y, + "minimum": lambda x, y: x < y, + "maximum": lambda x, y: x > y, + "minimum_ex": lambda x, y: x <= y, + "maximum_ex": lambda x, y: x >= y, + "min_items": lambda x, y: len(x) < y, + "max_items": lambda x, y: len(x) > y, + "pattern": lambda x, y: not re.match(y, x, re.UNICODE), + "unique": lambda x, y: len(x) != len(set(x)), + "multiple": lambda x, y: x % y != 0, + } + + def __init__(self, classes: Optional[Mapping[str, type]] = None) -> None: + self.serialize_type = { + "iso-8601": Serializer.serialize_iso, + "rfc-1123": Serializer.serialize_rfc, + "unix-time": Serializer.serialize_unix, + "duration": Serializer.serialize_duration, + "date": Serializer.serialize_date, + "time": Serializer.serialize_time, + "decimal": Serializer.serialize_decimal, + "long": Serializer.serialize_long, + "bytearray": Serializer.serialize_bytearray, + "base64": Serializer.serialize_base64, + "object": self.serialize_object, + "[]": self.serialize_iter, + "{}": self.serialize_dict, + } + self.dependencies: Dict[str, type] = dict(classes) if classes else {} + self.key_transformer = full_restapi_key_transformer + self.client_side_validation = True + + def _serialize( # pylint: disable=too-many-nested-blocks, too-many-branches, too-many-statements, too-many-locals + self, target_obj, data_type=None, **kwargs + ): + """Serialize data into a string according to type. + + :param object target_obj: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str, dict + :raises SerializationError: if serialization fails. + :returns: The serialized data. + """ + key_transformer = kwargs.get("key_transformer", self.key_transformer) + keep_readonly = kwargs.get("keep_readonly", False) + if target_obj is None: + return None + + attr_name = None + class_name = target_obj.__class__.__name__ + + if data_type: + return self.serialize_data(target_obj, data_type, **kwargs) + + if not hasattr(target_obj, "_attribute_map"): + data_type = type(target_obj).__name__ + if data_type in self.basic_types.values(): + return self.serialize_data(target_obj, data_type, **kwargs) + + # Force "is_xml" kwargs if we detect a XML model + try: + is_xml_model_serialization = kwargs["is_xml"] + except KeyError: + is_xml_model_serialization = kwargs.setdefault("is_xml", target_obj.is_xml_model()) + + serialized = {} + if is_xml_model_serialization: + serialized = target_obj._create_xml_node() # pylint: disable=protected-access + try: + attributes = target_obj._attribute_map # pylint: disable=protected-access + for attr, attr_desc in attributes.items(): + attr_name = attr + if not keep_readonly and target_obj._validation.get( # pylint: disable=protected-access + attr_name, {} + ).get("readonly", False): + continue + + if attr_name == "additional_properties" and attr_desc["key"] == "": + if target_obj.additional_properties is not None: + serialized.update(target_obj.additional_properties) + continue + try: + + orig_attr = getattr(target_obj, attr) + if is_xml_model_serialization: + pass # Don't provide "transformer" for XML for now. Keep "orig_attr" + else: # JSON + keys, orig_attr = key_transformer(attr, attr_desc.copy(), orig_attr) + keys = keys if isinstance(keys, list) else [keys] + + kwargs["serialization_ctxt"] = attr_desc + new_attr = self.serialize_data(orig_attr, attr_desc["type"], **kwargs) + + if is_xml_model_serialization: + xml_desc = attr_desc.get("xml", {}) + xml_name = xml_desc.get("name", attr_desc["key"]) + xml_prefix = xml_desc.get("prefix", None) + xml_ns = xml_desc.get("ns", None) + if xml_desc.get("attr", False): + if xml_ns: + ET.register_namespace(xml_prefix, xml_ns) + xml_name = "{{{}}}{}".format(xml_ns, xml_name) + serialized.set(xml_name, new_attr) # type: ignore + continue + if xml_desc.get("text", False): + serialized.text = new_attr # type: ignore + continue + if isinstance(new_attr, list): + serialized.extend(new_attr) # type: ignore + elif isinstance(new_attr, ET.Element): + # If the down XML has no XML/Name, + # we MUST replace the tag with the local tag. But keeping the namespaces. + if "name" not in getattr(orig_attr, "_xml_map", {}): + splitted_tag = new_attr.tag.split("}") + if len(splitted_tag) == 2: # Namespace + new_attr.tag = "}".join([splitted_tag[0], xml_name]) + else: + new_attr.tag = xml_name + serialized.append(new_attr) # type: ignore + else: # That's a basic type + # Integrate namespace if necessary + local_node = _create_xml_node(xml_name, xml_prefix, xml_ns) + local_node.text = str(new_attr) + serialized.append(local_node) # type: ignore + else: # JSON + for k in reversed(keys): # type: ignore + new_attr = {k: new_attr} + + _new_attr = new_attr + _serialized = serialized + for k in keys: # type: ignore + if k not in _serialized: + _serialized.update(_new_attr) # type: ignore + _new_attr = _new_attr[k] # type: ignore + _serialized = _serialized[k] + except ValueError as err: + if isinstance(err, SerializationError): + raise + + except (AttributeError, KeyError, TypeError) as err: + msg = "Attribute {} in object {} cannot be serialized.\n{}".format(attr_name, class_name, str(target_obj)) + raise SerializationError(msg) from err + return serialized + + def body(self, data, data_type, **kwargs): + """Serialize data intended for a request body. + + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: dict + :raises SerializationError: if serialization fails. + :raises ValueError: if data is None + :returns: The serialized request body + """ + + # Just in case this is a dict + internal_data_type_str = data_type.strip("[]{}") + internal_data_type = self.dependencies.get(internal_data_type_str, None) + try: + is_xml_model_serialization = kwargs["is_xml"] + except KeyError: + if internal_data_type and issubclass(internal_data_type, Model): + is_xml_model_serialization = kwargs.setdefault("is_xml", internal_data_type.is_xml_model()) + else: + is_xml_model_serialization = False + if internal_data_type and not isinstance(internal_data_type, Enum): + try: + deserializer = Deserializer(self.dependencies) + # Since it's on serialization, it's almost sure that format is not JSON REST + # We're not able to deal with additional properties for now. + deserializer.additional_properties_detection = False + if is_xml_model_serialization: + deserializer.key_extractors = [ # type: ignore + attribute_key_case_insensitive_extractor, + ] + else: + deserializer.key_extractors = [ + rest_key_case_insensitive_extractor, + attribute_key_case_insensitive_extractor, + last_rest_key_case_insensitive_extractor, + ] + data = deserializer._deserialize(data_type, data) # pylint: disable=protected-access + except DeserializationError as err: + raise SerializationError("Unable to build a model: " + str(err)) from err + + return self._serialize(data, data_type, **kwargs) + + def url(self, name, data, data_type, **kwargs): + """Serialize data intended for a URL path. + + :param str name: The name of the URL path parameter. + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str + :returns: The serialized URL path + :raises TypeError: if serialization fails. + :raises ValueError: if data is None + """ + try: + output = self.serialize_data(data, data_type, **kwargs) + if data_type == "bool": + output = json.dumps(output) + + if kwargs.get("skip_quote") is True: + output = str(output) + output = output.replace("{", quote("{")).replace("}", quote("}")) + else: + output = quote(str(output), safe="") + except SerializationError as exc: + raise TypeError("{} must be type {}.".format(name, data_type)) from exc + return output + + def query(self, name, data, data_type, **kwargs): + """Serialize data intended for a URL query. + + :param str name: The name of the query parameter. + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str, list + :raises TypeError: if serialization fails. + :raises ValueError: if data is None + :returns: The serialized query parameter + """ + try: + # Treat the list aside, since we don't want to encode the div separator + if data_type.startswith("["): + internal_data_type = data_type[1:-1] + do_quote = not kwargs.get("skip_quote", False) + return self.serialize_iter(data, internal_data_type, do_quote=do_quote, **kwargs) + + # Not a list, regular serialization + output = self.serialize_data(data, data_type, **kwargs) + if data_type == "bool": + output = json.dumps(output) + if kwargs.get("skip_quote") is True: + output = str(output) + else: + output = quote(str(output), safe="") + except SerializationError as exc: + raise TypeError("{} must be type {}.".format(name, data_type)) from exc + return str(output) + + def header(self, name, data, data_type, **kwargs): + """Serialize data intended for a request header. + + :param str name: The name of the header. + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str + :raises TypeError: if serialization fails. + :raises ValueError: if data is None + :returns: The serialized header + """ + try: + if data_type in ["[str]"]: + data = ["" if d is None else d for d in data] + + output = self.serialize_data(data, data_type, **kwargs) + if data_type == "bool": + output = json.dumps(output) + except SerializationError as exc: + raise TypeError("{} must be type {}.".format(name, data_type)) from exc + return str(output) + + def serialize_data(self, data, data_type, **kwargs): + """Serialize generic data according to supplied data type. + + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :raises AttributeError: if required data is None. + :raises ValueError: if data is None + :raises SerializationError: if serialization fails. + :returns: The serialized data. + :rtype: str, int, float, bool, dict, list + """ + if data is None: + raise ValueError("No value for given attribute") + + try: + if data is CoreNull: + return None + if data_type in self.basic_types.values(): + return self.serialize_basic(data, data_type, **kwargs) + + if data_type in self.serialize_type: + return self.serialize_type[data_type](data, **kwargs) + + # If dependencies is empty, try with current data class + # It has to be a subclass of Enum anyway + enum_type = self.dependencies.get(data_type, data.__class__) + if issubclass(enum_type, Enum): + return Serializer.serialize_enum(data, enum_obj=enum_type) + + iter_type = data_type[0] + data_type[-1] + if iter_type in self.serialize_type: + return self.serialize_type[iter_type](data, data_type[1:-1], **kwargs) + + except (ValueError, TypeError) as err: + msg = "Unable to serialize value: {!r} as type: {!r}." + raise SerializationError(msg.format(data, data_type)) from err + return self._serialize(data, **kwargs) + + @classmethod + def _get_custom_serializers(cls, data_type, **kwargs): # pylint: disable=inconsistent-return-statements + custom_serializer = kwargs.get("basic_types_serializers", {}).get(data_type) + if custom_serializer: + return custom_serializer + if kwargs.get("is_xml", False): + return cls._xml_basic_types_serializers.get(data_type) + + @classmethod + def serialize_basic(cls, data, data_type, **kwargs): + """Serialize basic builting data type. + Serializes objects to str, int, float or bool. + + Possible kwargs: + - basic_types_serializers dict[str, callable] : If set, use the callable as serializer + - is_xml bool : If set, use xml_basic_types_serializers + + :param obj data: Object to be serialized. + :param str data_type: Type of object in the iterable. + :rtype: str, int, float, bool + :return: serialized object + """ + custom_serializer = cls._get_custom_serializers(data_type, **kwargs) + if custom_serializer: + return custom_serializer(data) + if data_type == "str": + return cls.serialize_unicode(data) + return eval(data_type)(data) # nosec # pylint: disable=eval-used + + @classmethod + def serialize_unicode(cls, data): + """Special handling for serializing unicode strings in Py2. + Encode to UTF-8 if unicode, otherwise handle as a str. + + :param str data: Object to be serialized. + :rtype: str + :return: serialized object + """ + try: # If I received an enum, return its value + return data.value + except AttributeError: + pass + + try: + if isinstance(data, unicode): # type: ignore + # Don't change it, JSON and XML ElementTree are totally able + # to serialize correctly u'' strings + return data + except NameError: + return str(data) + return str(data) + + def serialize_iter(self, data, iter_type, div=None, **kwargs): + """Serialize iterable. + + Supported kwargs: + - serialization_ctxt dict : The current entry of _attribute_map, or same format. + serialization_ctxt['type'] should be same as data_type. + - is_xml bool : If set, serialize as XML + + :param list data: Object to be serialized. + :param str iter_type: Type of object in the iterable. + :param str div: If set, this str will be used to combine the elements + in the iterable into a combined string. Default is 'None'. + Defaults to False. + :rtype: list, str + :return: serialized iterable + """ + if isinstance(data, str): + raise SerializationError("Refuse str type as a valid iter type.") + + serialization_ctxt = kwargs.get("serialization_ctxt", {}) + is_xml = kwargs.get("is_xml", False) + + serialized = [] + for d in data: + try: + serialized.append(self.serialize_data(d, iter_type, **kwargs)) + except ValueError as err: + if isinstance(err, SerializationError): + raise + serialized.append(None) + + if kwargs.get("do_quote", False): + serialized = ["" if s is None else quote(str(s), safe="") for s in serialized] + + if div: + serialized = ["" if s is None else str(s) for s in serialized] + serialized = div.join(serialized) + + if "xml" in serialization_ctxt or is_xml: + # XML serialization is more complicated + xml_desc = serialization_ctxt.get("xml", {}) + xml_name = xml_desc.get("name") + if not xml_name: + xml_name = serialization_ctxt["key"] + + # Create a wrap node if necessary (use the fact that Element and list have "append") + is_wrapped = xml_desc.get("wrapped", False) + node_name = xml_desc.get("itemsName", xml_name) + if is_wrapped: + final_result = _create_xml_node(xml_name, xml_desc.get("prefix", None), xml_desc.get("ns", None)) + else: + final_result = [] + # All list elements to "local_node" + for el in serialized: + if isinstance(el, ET.Element): + el_node = el + else: + el_node = _create_xml_node(node_name, xml_desc.get("prefix", None), xml_desc.get("ns", None)) + if el is not None: # Otherwise it writes "None" :-p + el_node.text = str(el) + final_result.append(el_node) + return final_result + return serialized + + def serialize_dict(self, attr, dict_type, **kwargs): + """Serialize a dictionary of objects. + + :param dict attr: Object to be serialized. + :param str dict_type: Type of object in the dictionary. + :rtype: dict + :return: serialized dictionary + """ + serialization_ctxt = kwargs.get("serialization_ctxt", {}) + serialized = {} + for key, value in attr.items(): + try: + serialized[self.serialize_unicode(key)] = self.serialize_data(value, dict_type, **kwargs) + except ValueError as err: + if isinstance(err, SerializationError): + raise + serialized[self.serialize_unicode(key)] = None + + if "xml" in serialization_ctxt: + # XML serialization is more complicated + xml_desc = serialization_ctxt["xml"] + xml_name = xml_desc["name"] + + final_result = _create_xml_node(xml_name, xml_desc.get("prefix", None), xml_desc.get("ns", None)) + for key, value in serialized.items(): + ET.SubElement(final_result, key).text = value + return final_result + + return serialized + + def serialize_object(self, attr, **kwargs): # pylint: disable=too-many-return-statements + """Serialize a generic object. + This will be handled as a dictionary. If object passed in is not + a basic type (str, int, float, dict, list) it will simply be + cast to str. + + :param dict attr: Object to be serialized. + :rtype: dict or str + :return: serialized object + """ + if attr is None: + return None + if isinstance(attr, ET.Element): + return attr + obj_type = type(attr) + if obj_type in self.basic_types: + return self.serialize_basic(attr, self.basic_types[obj_type], **kwargs) + if obj_type is _long_type: + return self.serialize_long(attr) + if obj_type is str: + return self.serialize_unicode(attr) + if obj_type is datetime.datetime: + return self.serialize_iso(attr) + if obj_type is datetime.date: + return self.serialize_date(attr) + if obj_type is datetime.time: + return self.serialize_time(attr) + if obj_type is datetime.timedelta: + return self.serialize_duration(attr) + if obj_type is decimal.Decimal: + return self.serialize_decimal(attr) + + # If it's a model or I know this dependency, serialize as a Model + if obj_type in self.dependencies.values() or isinstance(attr, Model): + return self._serialize(attr) + + if obj_type == dict: + serialized = {} + for key, value in attr.items(): + try: + serialized[self.serialize_unicode(key)] = self.serialize_object(value, **kwargs) + except ValueError: + serialized[self.serialize_unicode(key)] = None + return serialized + + if obj_type == list: + serialized = [] + for obj in attr: + try: + serialized.append(self.serialize_object(obj, **kwargs)) + except ValueError: + pass + return serialized + return str(attr) + + @staticmethod + def serialize_enum(attr, enum_obj=None): + try: + result = attr.value + except AttributeError: + result = attr + try: + enum_obj(result) # type: ignore + return result + except ValueError as exc: + for enum_value in enum_obj: # type: ignore + if enum_value.value.lower() == str(attr).lower(): + return enum_value.value + error = "{!r} is not valid value for enum {!r}" + raise SerializationError(error.format(attr, enum_obj)) from exc + + @staticmethod + def serialize_bytearray(attr, **kwargs): # pylint: disable=unused-argument + """Serialize bytearray into base-64 string. + + :param str attr: Object to be serialized. + :rtype: str + :return: serialized base64 + """ + return b64encode(attr).decode() + + @staticmethod + def serialize_base64(attr, **kwargs): # pylint: disable=unused-argument + """Serialize str into base-64 string. + + :param str attr: Object to be serialized. + :rtype: str + :return: serialized base64 + """ + encoded = b64encode(attr).decode("ascii") + return encoded.strip("=").replace("+", "-").replace("/", "_") + + @staticmethod + def serialize_decimal(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Decimal object to float. + + :param decimal attr: Object to be serialized. + :rtype: float + :return: serialized decimal + """ + return float(attr) + + @staticmethod + def serialize_long(attr, **kwargs): # pylint: disable=unused-argument + """Serialize long (Py2) or int (Py3). + + :param int attr: Object to be serialized. + :rtype: int/long + :return: serialized long + """ + return _long_type(attr) + + @staticmethod + def serialize_date(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Date object into ISO-8601 formatted string. + + :param Date attr: Object to be serialized. + :rtype: str + :return: serialized date + """ + if isinstance(attr, str): + attr = isodate.parse_date(attr) + t = "{:04}-{:02}-{:02}".format(attr.year, attr.month, attr.day) + return t + + @staticmethod + def serialize_time(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Time object into ISO-8601 formatted string. + + :param datetime.time attr: Object to be serialized. + :rtype: str + :return: serialized time + """ + if isinstance(attr, str): + attr = isodate.parse_time(attr) + t = "{:02}:{:02}:{:02}".format(attr.hour, attr.minute, attr.second) + if attr.microsecond: + t += ".{:02}".format(attr.microsecond) + return t + + @staticmethod + def serialize_duration(attr, **kwargs): # pylint: disable=unused-argument + """Serialize TimeDelta object into ISO-8601 formatted string. + + :param TimeDelta attr: Object to be serialized. + :rtype: str + :return: serialized duration + """ + if isinstance(attr, str): + attr = isodate.parse_duration(attr) + return isodate.duration_isoformat(attr) + + @staticmethod + def serialize_rfc(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Datetime object into RFC-1123 formatted string. + + :param Datetime attr: Object to be serialized. + :rtype: str + :raises TypeError: if format invalid. + :return: serialized rfc + """ + try: + if not attr.tzinfo: + _LOGGER.warning("Datetime with no tzinfo will be considered UTC.") + utc = attr.utctimetuple() + except AttributeError as exc: + raise TypeError("RFC1123 object must be valid Datetime object.") from exc + + return "{}, {:02} {} {:04} {:02}:{:02}:{:02} GMT".format( + Serializer.days[utc.tm_wday], + utc.tm_mday, + Serializer.months[utc.tm_mon], + utc.tm_year, + utc.tm_hour, + utc.tm_min, + utc.tm_sec, + ) + + @staticmethod + def serialize_iso(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Datetime object into ISO-8601 formatted string. + + :param Datetime attr: Object to be serialized. + :rtype: str + :raises SerializationError: if format invalid. + :return: serialized iso + """ + if isinstance(attr, str): + attr = isodate.parse_datetime(attr) + try: + if not attr.tzinfo: + _LOGGER.warning("Datetime with no tzinfo will be considered UTC.") + utc = attr.utctimetuple() + if utc.tm_year > 9999 or utc.tm_year < 1: + raise OverflowError("Hit max or min date") + + microseconds = str(attr.microsecond).rjust(6, "0").rstrip("0").ljust(3, "0") + if microseconds: + microseconds = "." + microseconds + date = "{:04}-{:02}-{:02}T{:02}:{:02}:{:02}".format( + utc.tm_year, utc.tm_mon, utc.tm_mday, utc.tm_hour, utc.tm_min, utc.tm_sec + ) + return date + microseconds + "Z" + except (ValueError, OverflowError) as err: + msg = "Unable to serialize datetime object." + raise SerializationError(msg) from err + except AttributeError as err: + msg = "ISO-8601 object must be valid Datetime object." + raise TypeError(msg) from err + + @staticmethod + def serialize_unix(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Datetime object into IntTime format. + This is represented as seconds. + + :param Datetime attr: Object to be serialized. + :rtype: int + :raises SerializationError: if format invalid + :return: serialied unix + """ + if isinstance(attr, int): + return attr + try: + if not attr.tzinfo: + _LOGGER.warning("Datetime with no tzinfo will be considered UTC.") + return int(calendar.timegm(attr.utctimetuple())) + except AttributeError as exc: + raise TypeError("Unix time object must be valid Datetime object.") from exc + + +def rest_key_extractor(attr, attr_desc, data): # pylint: disable=unused-argument + key = attr_desc["key"] + working_data = data + + while "." in key: + # Need the cast, as for some reasons "split" is typed as list[str | Any] + dict_keys = cast(List[str], _FLATTEN.split(key)) + if len(dict_keys) == 1: + key = _decode_attribute_map_key(dict_keys[0]) + break + working_key = _decode_attribute_map_key(dict_keys[0]) + working_data = working_data.get(working_key, data) + if working_data is None: + # If at any point while following flatten JSON path see None, it means + # that all properties under are None as well + return None + key = ".".join(dict_keys[1:]) + + return working_data.get(key) + + +def rest_key_case_insensitive_extractor( # pylint: disable=unused-argument, inconsistent-return-statements + attr, attr_desc, data +): + key = attr_desc["key"] + working_data = data + + while "." in key: + dict_keys = _FLATTEN.split(key) + if len(dict_keys) == 1: + key = _decode_attribute_map_key(dict_keys[0]) + break + working_key = _decode_attribute_map_key(dict_keys[0]) + working_data = attribute_key_case_insensitive_extractor(working_key, None, working_data) + if working_data is None: + # If at any point while following flatten JSON path see None, it means + # that all properties under are None as well + return None + key = ".".join(dict_keys[1:]) + + if working_data: + return attribute_key_case_insensitive_extractor(key, None, working_data) + + +def last_rest_key_extractor(attr, attr_desc, data): # pylint: disable=unused-argument + """Extract the attribute in "data" based on the last part of the JSON path key. + + :param str attr: The attribute to extract + :param dict attr_desc: The attribute description + :param dict data: The data to extract from + :rtype: object + :returns: The extracted attribute + """ + key = attr_desc["key"] + dict_keys = _FLATTEN.split(key) + return attribute_key_extractor(dict_keys[-1], None, data) + + +def last_rest_key_case_insensitive_extractor(attr, attr_desc, data): # pylint: disable=unused-argument + """Extract the attribute in "data" based on the last part of the JSON path key. + + This is the case insensitive version of "last_rest_key_extractor" + :param str attr: The attribute to extract + :param dict attr_desc: The attribute description + :param dict data: The data to extract from + :rtype: object + :returns: The extracted attribute + """ + key = attr_desc["key"] + dict_keys = _FLATTEN.split(key) + return attribute_key_case_insensitive_extractor(dict_keys[-1], None, data) + + +def attribute_key_extractor(attr, _, data): + return data.get(attr) + + +def attribute_key_case_insensitive_extractor(attr, _, data): + found_key = None + lower_attr = attr.lower() + for key in data: + if lower_attr == key.lower(): + found_key = key + break + + return data.get(found_key) + + +def _extract_name_from_internal_type(internal_type): + """Given an internal type XML description, extract correct XML name with namespace. + + :param dict internal_type: An model type + :rtype: tuple + :returns: A tuple XML name + namespace dict + """ + internal_type_xml_map = getattr(internal_type, "_xml_map", {}) + xml_name = internal_type_xml_map.get("name", internal_type.__name__) + xml_ns = internal_type_xml_map.get("ns", None) + if xml_ns: + xml_name = "{{{}}}{}".format(xml_ns, xml_name) + return xml_name + + +def xml_key_extractor(attr, attr_desc, data): # pylint: disable=unused-argument,too-many-return-statements + if isinstance(data, dict): + return None + + # Test if this model is XML ready first + if not isinstance(data, ET.Element): + return None + + xml_desc = attr_desc.get("xml", {}) + xml_name = xml_desc.get("name", attr_desc["key"]) + + # Look for a children + is_iter_type = attr_desc["type"].startswith("[") + is_wrapped = xml_desc.get("wrapped", False) + internal_type = attr_desc.get("internalType", None) + internal_type_xml_map = getattr(internal_type, "_xml_map", {}) + + # Integrate namespace if necessary + xml_ns = xml_desc.get("ns", internal_type_xml_map.get("ns", None)) + if xml_ns: + xml_name = "{{{}}}{}".format(xml_ns, xml_name) + + # If it's an attribute, that's simple + if xml_desc.get("attr", False): + return data.get(xml_name) + + # If it's x-ms-text, that's simple too + if xml_desc.get("text", False): + return data.text + + # Scenario where I take the local name: + # - Wrapped node + # - Internal type is an enum (considered basic types) + # - Internal type has no XML/Name node + if is_wrapped or (internal_type and (issubclass(internal_type, Enum) or "name" not in internal_type_xml_map)): + children = data.findall(xml_name) + # If internal type has a local name and it's not a list, I use that name + elif not is_iter_type and internal_type and "name" in internal_type_xml_map: + xml_name = _extract_name_from_internal_type(internal_type) + children = data.findall(xml_name) + # That's an array + else: + if internal_type: # Complex type, ignore itemsName and use the complex type name + items_name = _extract_name_from_internal_type(internal_type) + else: + items_name = xml_desc.get("itemsName", xml_name) + children = data.findall(items_name) + + if len(children) == 0: + if is_iter_type: + if is_wrapped: + return None # is_wrapped no node, we want None + return [] # not wrapped, assume empty list + return None # Assume it's not there, maybe an optional node. + + # If is_iter_type and not wrapped, return all found children + if is_iter_type: + if not is_wrapped: + return children + # Iter and wrapped, should have found one node only (the wrap one) + if len(children) != 1: + raise DeserializationError( + "Tried to deserialize an array not wrapped, and found several nodes '{}'. Maybe you should declare this array as wrapped?".format( + xml_name + ) + ) + return list(children[0]) # Might be empty list and that's ok. + + # Here it's not a itertype, we should have found one element only or empty + if len(children) > 1: + raise DeserializationError("Find several XML '{}' where it was not expected".format(xml_name)) + return children[0] + + +class Deserializer: + """Response object model deserializer. + + :param dict classes: Class type dictionary for deserializing complex types. + :ivar list key_extractors: Ordered list of extractors to be used by this deserializer. + """ + + basic_types = {str: "str", int: "int", bool: "bool", float: "float"} + + valid_date = re.compile(r"\d{4}[-]\d{2}[-]\d{2}T\d{2}:\d{2}:\d{2}\.?\d*Z?[-+]?[\d{2}]?:?[\d{2}]?") + + def __init__(self, classes: Optional[Mapping[str, type]] = None) -> None: + self.deserialize_type = { + "iso-8601": Deserializer.deserialize_iso, + "rfc-1123": Deserializer.deserialize_rfc, + "unix-time": Deserializer.deserialize_unix, + "duration": Deserializer.deserialize_duration, + "date": Deserializer.deserialize_date, + "time": Deserializer.deserialize_time, + "decimal": Deserializer.deserialize_decimal, + "long": Deserializer.deserialize_long, + "bytearray": Deserializer.deserialize_bytearray, + "base64": Deserializer.deserialize_base64, + "object": self.deserialize_object, + "[]": self.deserialize_iter, + "{}": self.deserialize_dict, + } + self.deserialize_expected_types = { + "duration": (isodate.Duration, datetime.timedelta), + "iso-8601": (datetime.datetime), + } + self.dependencies: Dict[str, type] = dict(classes) if classes else {} + self.key_extractors = [rest_key_extractor, xml_key_extractor] + # Additional properties only works if the "rest_key_extractor" is used to + # extract the keys. Making it to work whatever the key extractor is too much + # complicated, with no real scenario for now. + # So adding a flag to disable additional properties detection. This flag should be + # used if your expect the deserialization to NOT come from a JSON REST syntax. + # Otherwise, result are unexpected + self.additional_properties_detection = True + + def __call__(self, target_obj, response_data, content_type=None): + """Call the deserializer to process a REST response. + + :param str target_obj: Target data type to deserialize to. + :param requests.Response response_data: REST response object. + :param str content_type: Swagger "produces" if available. + :raises DeserializationError: if deserialization fails. + :return: Deserialized object. + :rtype: object + """ + data = self._unpack_content(response_data, content_type) + return self._deserialize(target_obj, data) + + def _deserialize(self, target_obj, data): # pylint: disable=inconsistent-return-statements + """Call the deserializer on a model. + + Data needs to be already deserialized as JSON or XML ElementTree + + :param str target_obj: Target data type to deserialize to. + :param object data: Object to deserialize. + :raises DeserializationError: if deserialization fails. + :return: Deserialized object. + :rtype: object + """ + # This is already a model, go recursive just in case + if hasattr(data, "_attribute_map"): + constants = [name for name, config in getattr(data, "_validation", {}).items() if config.get("constant")] + try: + for attr, mapconfig in data._attribute_map.items(): # pylint: disable=protected-access + if attr in constants: + continue + value = getattr(data, attr) + if value is None: + continue + local_type = mapconfig["type"] + internal_data_type = local_type.strip("[]{}") + if internal_data_type not in self.dependencies or isinstance(internal_data_type, Enum): + continue + setattr(data, attr, self._deserialize(local_type, value)) + return data + except AttributeError: + return + + response, class_name = self._classify_target(target_obj, data) + + if isinstance(response, str): + return self.deserialize_data(data, response) + if isinstance(response, type) and issubclass(response, Enum): + return self.deserialize_enum(data, response) + + if data is None or data is CoreNull: + return data + try: + attributes = response._attribute_map # type: ignore # pylint: disable=protected-access + d_attrs = {} + for attr, attr_desc in attributes.items(): + # Check empty string. If it's not empty, someone has a real "additionalProperties"... + if attr == "additional_properties" and attr_desc["key"] == "": + continue + raw_value = None + # Enhance attr_desc with some dynamic data + attr_desc = attr_desc.copy() # Do a copy, do not change the real one + internal_data_type = attr_desc["type"].strip("[]{}") + if internal_data_type in self.dependencies: + attr_desc["internalType"] = self.dependencies[internal_data_type] + + for key_extractor in self.key_extractors: + found_value = key_extractor(attr, attr_desc, data) + if found_value is not None: + if raw_value is not None and raw_value != found_value: + msg = ( + "Ignoring extracted value '%s' from %s for key '%s'" + " (duplicate extraction, follow extractors order)" + ) + _LOGGER.warning(msg, found_value, key_extractor, attr) + continue + raw_value = found_value + + value = self.deserialize_data(raw_value, attr_desc["type"]) + d_attrs[attr] = value + except (AttributeError, TypeError, KeyError) as err: + msg = "Unable to deserialize to object: " + class_name # type: ignore + raise DeserializationError(msg) from err + additional_properties = self._build_additional_properties(attributes, data) + return self._instantiate_model(response, d_attrs, additional_properties) + + def _build_additional_properties(self, attribute_map, data): + if not self.additional_properties_detection: + return None + if "additional_properties" in attribute_map and attribute_map.get("additional_properties", {}).get("key") != "": + # Check empty string. If it's not empty, someone has a real "additionalProperties" + return None + if isinstance(data, ET.Element): + data = {el.tag: el.text for el in data} + + known_keys = { + _decode_attribute_map_key(_FLATTEN.split(desc["key"])[0]) + for desc in attribute_map.values() + if desc["key"] != "" + } + present_keys = set(data.keys()) + missing_keys = present_keys - known_keys + return {key: data[key] for key in missing_keys} + + def _classify_target(self, target, data): + """Check to see whether the deserialization target object can + be classified into a subclass. + Once classification has been determined, initialize object. + + :param str target: The target object type to deserialize to. + :param str/dict data: The response data to deserialize. + :return: The classified target object and its class name. + :rtype: tuple + """ + if target is None: + return None, None + + if isinstance(target, str): + try: + target = self.dependencies[target] + except KeyError: + return target, target + + try: + target = target._classify(data, self.dependencies) # type: ignore # pylint: disable=protected-access + except AttributeError: + pass # Target is not a Model, no classify + return target, target.__class__.__name__ # type: ignore + + def failsafe_deserialize(self, target_obj, data, content_type=None): + """Ignores any errors encountered in deserialization, + and falls back to not deserializing the object. Recommended + for use in error deserialization, as we want to return the + HttpResponseError to users, and not have them deal with + a deserialization error. + + :param str target_obj: The target object type to deserialize to. + :param str/dict data: The response data to deserialize. + :param str content_type: Swagger "produces" if available. + :return: Deserialized object. + :rtype: object + """ + try: + return self(target_obj, data, content_type=content_type) + except: # pylint: disable=bare-except + _LOGGER.debug( + "Ran into a deserialization error. Ignoring since this is failsafe deserialization", exc_info=True + ) + return None + + @staticmethod + def _unpack_content(raw_data, content_type=None): + """Extract the correct structure for deserialization. + + If raw_data is a PipelineResponse, try to extract the result of RawDeserializer. + if we can't, raise. Your Pipeline should have a RawDeserializer. + + If not a pipeline response and raw_data is bytes or string, use content-type + to decode it. If no content-type, try JSON. + + If raw_data is something else, bypass all logic and return it directly. + + :param obj raw_data: Data to be processed. + :param str content_type: How to parse if raw_data is a string/bytes. + :raises JSONDecodeError: If JSON is requested and parsing is impossible. + :raises UnicodeDecodeError: If bytes is not UTF8 + :rtype: object + :return: Unpacked content. + """ + # Assume this is enough to detect a Pipeline Response without importing it + context = getattr(raw_data, "context", {}) + if context: + if RawDeserializer.CONTEXT_NAME in context: + return context[RawDeserializer.CONTEXT_NAME] + raise ValueError("This pipeline didn't have the RawDeserializer policy; can't deserialize") + + # Assume this is enough to recognize universal_http.ClientResponse without importing it + if hasattr(raw_data, "body"): + return RawDeserializer.deserialize_from_http_generics(raw_data.text(), raw_data.headers) + + # Assume this enough to recognize requests.Response without importing it. + if hasattr(raw_data, "_content_consumed"): + return RawDeserializer.deserialize_from_http_generics(raw_data.text, raw_data.headers) + + if isinstance(raw_data, (str, bytes)) or hasattr(raw_data, "read"): + return RawDeserializer.deserialize_from_text(raw_data, content_type) # type: ignore + return raw_data + + def _instantiate_model(self, response, attrs, additional_properties=None): + """Instantiate a response model passing in deserialized args. + + :param Response response: The response model class. + :param dict attrs: The deserialized response attributes. + :param dict additional_properties: Additional properties to be set. + :rtype: Response + :return: The instantiated response model. + """ + if callable(response): + subtype = getattr(response, "_subtype_map", {}) + try: + readonly = [ + k + for k, v in response._validation.items() # pylint: disable=protected-access # type: ignore + if v.get("readonly") + ] + const = [ + k + for k, v in response._validation.items() # pylint: disable=protected-access # type: ignore + if v.get("constant") + ] + kwargs = {k: v for k, v in attrs.items() if k not in subtype and k not in readonly + const} + response_obj = response(**kwargs) + for attr in readonly: + setattr(response_obj, attr, attrs.get(attr)) + if additional_properties: + response_obj.additional_properties = additional_properties # type: ignore + return response_obj + except TypeError as err: + msg = "Unable to deserialize {} into model {}. ".format(kwargs, response) # type: ignore + raise DeserializationError(msg + str(err)) from err + else: + try: + for attr, value in attrs.items(): + setattr(response, attr, value) + return response + except Exception as exp: + msg = "Unable to populate response model. " + msg += "Type: {}, Error: {}".format(type(response), exp) + raise DeserializationError(msg) from exp + + def deserialize_data(self, data, data_type): # pylint: disable=too-many-return-statements + """Process data for deserialization according to data type. + + :param str data: The response string to be deserialized. + :param str data_type: The type to deserialize to. + :raises DeserializationError: if deserialization fails. + :return: Deserialized object. + :rtype: object + """ + if data is None: + return data + + try: + if not data_type: + return data + if data_type in self.basic_types.values(): + return self.deserialize_basic(data, data_type) + if data_type in self.deserialize_type: + if isinstance(data, self.deserialize_expected_types.get(data_type, tuple())): + return data + + is_a_text_parsing_type = lambda x: x not in [ # pylint: disable=unnecessary-lambda-assignment + "object", + "[]", + r"{}", + ] + if isinstance(data, ET.Element) and is_a_text_parsing_type(data_type) and not data.text: + return None + data_val = self.deserialize_type[data_type](data) + return data_val + + iter_type = data_type[0] + data_type[-1] + if iter_type in self.deserialize_type: + return self.deserialize_type[iter_type](data, data_type[1:-1]) + + obj_type = self.dependencies[data_type] + if issubclass(obj_type, Enum): + if isinstance(data, ET.Element): + data = data.text + return self.deserialize_enum(data, obj_type) + + except (ValueError, TypeError, AttributeError) as err: + msg = "Unable to deserialize response data." + msg += " Data: {}, {}".format(data, data_type) + raise DeserializationError(msg) from err + return self._deserialize(obj_type, data) + + def deserialize_iter(self, attr, iter_type): + """Deserialize an iterable. + + :param list attr: Iterable to be deserialized. + :param str iter_type: The type of object in the iterable. + :return: Deserialized iterable. + :rtype: list + """ + if attr is None: + return None + if isinstance(attr, ET.Element): # If I receive an element here, get the children + attr = list(attr) + if not isinstance(attr, (list, set)): + raise DeserializationError("Cannot deserialize as [{}] an object of type {}".format(iter_type, type(attr))) + return [self.deserialize_data(a, iter_type) for a in attr] + + def deserialize_dict(self, attr, dict_type): + """Deserialize a dictionary. + + :param dict/list attr: Dictionary to be deserialized. Also accepts + a list of key, value pairs. + :param str dict_type: The object type of the items in the dictionary. + :return: Deserialized dictionary. + :rtype: dict + """ + if isinstance(attr, list): + return {x["key"]: self.deserialize_data(x["value"], dict_type) for x in attr} + + if isinstance(attr, ET.Element): + # Transform value into {"Key": "value"} + attr = {el.tag: el.text for el in attr} + return {k: self.deserialize_data(v, dict_type) for k, v in attr.items()} + + def deserialize_object(self, attr, **kwargs): # pylint: disable=too-many-return-statements + """Deserialize a generic object. + This will be handled as a dictionary. + + :param dict attr: Dictionary to be deserialized. + :return: Deserialized object. + :rtype: dict + :raises TypeError: if non-builtin datatype encountered. + """ + if attr is None: + return None + if isinstance(attr, ET.Element): + # Do no recurse on XML, just return the tree as-is + return attr + if isinstance(attr, str): + return self.deserialize_basic(attr, "str") + obj_type = type(attr) + if obj_type in self.basic_types: + return self.deserialize_basic(attr, self.basic_types[obj_type]) + if obj_type is _long_type: + return self.deserialize_long(attr) + + if obj_type == dict: + deserialized = {} + for key, value in attr.items(): + try: + deserialized[key] = self.deserialize_object(value, **kwargs) + except ValueError: + deserialized[key] = None + return deserialized + + if obj_type == list: + deserialized = [] + for obj in attr: + try: + deserialized.append(self.deserialize_object(obj, **kwargs)) + except ValueError: + pass + return deserialized + + error = "Cannot deserialize generic object with type: " + raise TypeError(error + str(obj_type)) + + def deserialize_basic(self, attr, data_type): # pylint: disable=too-many-return-statements + """Deserialize basic builtin data type from string. + Will attempt to convert to str, int, float and bool. + This function will also accept '1', '0', 'true' and 'false' as + valid bool values. + + :param str attr: response string to be deserialized. + :param str data_type: deserialization data type. + :return: Deserialized basic type. + :rtype: str, int, float or bool + :raises TypeError: if string format is not valid. + """ + # If we're here, data is supposed to be a basic type. + # If it's still an XML node, take the text + if isinstance(attr, ET.Element): + attr = attr.text + if not attr: + if data_type == "str": + # None or '', node is empty string. + return "" + # None or '', node with a strong type is None. + # Don't try to model "empty bool" or "empty int" + return None + + if data_type == "bool": + if attr in [True, False, 1, 0]: + return bool(attr) + if isinstance(attr, str): + if attr.lower() in ["true", "1"]: + return True + if attr.lower() in ["false", "0"]: + return False + raise TypeError("Invalid boolean value: {}".format(attr)) + + if data_type == "str": + return self.deserialize_unicode(attr) + return eval(data_type)(attr) # nosec # pylint: disable=eval-used + + @staticmethod + def deserialize_unicode(data): + """Preserve unicode objects in Python 2, otherwise return data + as a string. + + :param str data: response string to be deserialized. + :return: Deserialized string. + :rtype: str or unicode + """ + # We might be here because we have an enum modeled as string, + # and we try to deserialize a partial dict with enum inside + if isinstance(data, Enum): + return data + + # Consider this is real string + try: + if isinstance(data, unicode): # type: ignore + return data + except NameError: + return str(data) + return str(data) + + @staticmethod + def deserialize_enum(data, enum_obj): + """Deserialize string into enum object. + + If the string is not a valid enum value it will be returned as-is + and a warning will be logged. + + :param str data: Response string to be deserialized. If this value is + None or invalid it will be returned as-is. + :param Enum enum_obj: Enum object to deserialize to. + :return: Deserialized enum object. + :rtype: Enum + """ + if isinstance(data, enum_obj) or data is None: + return data + if isinstance(data, Enum): + data = data.value + if isinstance(data, int): + # Workaround. We might consider remove it in the future. + try: + return list(enum_obj.__members__.values())[data] + except IndexError as exc: + error = "{!r} is not a valid index for enum {!r}" + raise DeserializationError(error.format(data, enum_obj)) from exc + try: + return enum_obj(str(data)) + except ValueError: + for enum_value in enum_obj: + if enum_value.value.lower() == str(data).lower(): + return enum_value + # We don't fail anymore for unknown value, we deserialize as a string + _LOGGER.warning("Deserializer is not able to find %s as valid enum in %s", data, enum_obj) + return Deserializer.deserialize_unicode(data) + + @staticmethod + def deserialize_bytearray(attr): + """Deserialize string into bytearray. + + :param str attr: response string to be deserialized. + :return: Deserialized bytearray + :rtype: bytearray + :raises TypeError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + return bytearray(b64decode(attr)) # type: ignore + + @staticmethod + def deserialize_base64(attr): + """Deserialize base64 encoded string into string. + + :param str attr: response string to be deserialized. + :return: Deserialized base64 string + :rtype: bytearray + :raises TypeError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + padding = "=" * (3 - (len(attr) + 3) % 4) # type: ignore + attr = attr + padding # type: ignore + encoded = attr.replace("-", "+").replace("_", "/") + return b64decode(encoded) + + @staticmethod + def deserialize_decimal(attr): + """Deserialize string into Decimal object. + + :param str attr: response string to be deserialized. + :return: Deserialized decimal + :raises DeserializationError: if string format invalid. + :rtype: decimal + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + return decimal.Decimal(str(attr)) # type: ignore + except decimal.DecimalException as err: + msg = "Invalid decimal {}".format(attr) + raise DeserializationError(msg) from err + + @staticmethod + def deserialize_long(attr): + """Deserialize string into long (Py2) or int (Py3). + + :param str attr: response string to be deserialized. + :return: Deserialized int + :rtype: long or int + :raises ValueError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + return _long_type(attr) # type: ignore + + @staticmethod + def deserialize_duration(attr): + """Deserialize ISO-8601 formatted string into TimeDelta object. + + :param str attr: response string to be deserialized. + :return: Deserialized duration + :rtype: TimeDelta + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + duration = isodate.parse_duration(attr) + except (ValueError, OverflowError, AttributeError) as err: + msg = "Cannot deserialize duration object." + raise DeserializationError(msg) from err + return duration + + @staticmethod + def deserialize_date(attr): + """Deserialize ISO-8601 formatted string into Date object. + + :param str attr: response string to be deserialized. + :return: Deserialized date + :rtype: Date + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + if re.search(r"[^\W\d_]", attr, re.I + re.U): # type: ignore + raise DeserializationError("Date must have only digits and -. Received: %s" % attr) + # This must NOT use defaultmonth/defaultday. Using None ensure this raises an exception. + return isodate.parse_date(attr, defaultmonth=0, defaultday=0) + + @staticmethod + def deserialize_time(attr): + """Deserialize ISO-8601 formatted string into time object. + + :param str attr: response string to be deserialized. + :return: Deserialized time + :rtype: datetime.time + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + if re.search(r"[^\W\d_]", attr, re.I + re.U): # type: ignore + raise DeserializationError("Date must have only digits and -. Received: %s" % attr) + return isodate.parse_time(attr) + + @staticmethod + def deserialize_rfc(attr): + """Deserialize RFC-1123 formatted string into Datetime object. + + :param str attr: response string to be deserialized. + :return: Deserialized RFC datetime + :rtype: Datetime + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + parsed_date = email.utils.parsedate_tz(attr) # type: ignore + date_obj = datetime.datetime( + *parsed_date[:6], tzinfo=datetime.timezone(datetime.timedelta(minutes=(parsed_date[9] or 0) / 60)) + ) + if not date_obj.tzinfo: + date_obj = date_obj.astimezone(tz=TZ_UTC) + except ValueError as err: + msg = "Cannot deserialize to rfc datetime object." + raise DeserializationError(msg) from err + return date_obj + + @staticmethod + def deserialize_iso(attr): + """Deserialize ISO-8601 formatted string into Datetime object. + + :param str attr: response string to be deserialized. + :return: Deserialized ISO datetime + :rtype: Datetime + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + attr = attr.upper() # type: ignore + match = Deserializer.valid_date.match(attr) + if not match: + raise ValueError("Invalid datetime string: " + attr) + + check_decimal = attr.split(".") + if len(check_decimal) > 1: + decimal_str = "" + for digit in check_decimal[1]: + if digit.isdigit(): + decimal_str += digit + else: + break + if len(decimal_str) > 6: + attr = attr.replace(decimal_str, decimal_str[0:6]) + + date_obj = isodate.parse_datetime(attr) + test_utc = date_obj.utctimetuple() + if test_utc.tm_year > 9999 or test_utc.tm_year < 1: + raise OverflowError("Hit max or min date") + except (ValueError, OverflowError, AttributeError) as err: + msg = "Cannot deserialize datetime object." + raise DeserializationError(msg) from err + return date_obj + + @staticmethod + def deserialize_unix(attr): + """Serialize Datetime object into IntTime format. + This is represented as seconds. + + :param int attr: Object to be serialized. + :return: Deserialized datetime + :rtype: Datetime + :raises DeserializationError: if format invalid + """ + if isinstance(attr, ET.Element): + attr = int(attr.text) # type: ignore + try: + attr = int(attr) + date_obj = datetime.datetime.fromtimestamp(attr, TZ_UTC) + except ValueError as err: + msg = "Cannot deserialize to unix datetime object." + raise DeserializationError(msg) from err + return date_obj diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiNoAsync/multiapinoasync/v1/_metadata.json b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiNoAsync/multiapinoasync/v1/_metadata.json index 8cf857a945e..f98e2fbb18a 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiNoAsync/multiapinoasync/v1/_metadata.json +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiNoAsync/multiapinoasync/v1/_metadata.json @@ -10,8 +10,8 @@ "azure_arm": true, "has_public_lro_operations": true, "client_side_validation": false, - "sync_imports": "{\"conditional\": {\"stdlib\": {\"typing\": [\"Any\", \"Optional\"]}}, \"regular\": {\"sdkcore\": {\"azure.mgmt.core\": [\"ARMPipelineClient\"], \"azure.core.pipeline\": [\"policies\"], \"azure.mgmt.core.policies\": [\"ARMAutoResourceProviderRegistrationPolicy\"], \"azure.core.settings\": [\"settings\"], \"azure.mgmt.core.tools\": [\"get_arm_endpoints\"], \"azure.profiles\": [\"KnownProfiles\", \"ProfileDefinition\"], \"azure.profiles.multiapiclient\": [\"MultiApiClientMixin\"]}, \"stdlib\": {\"typing\": [\"Optional\", \"cast\"], \"typing_extensions\": [\"Self\"]}, \"local\": {\"._configuration\": [\"MultiapiServiceClientConfiguration\"], \".._serialization\": [\"Deserializer\", \"Serializer\"], \"._operations_mixin\": [\"MultiapiServiceClientOperationsMixin\"]}}, \"typing\": {\"sdkcore\": {\"azure.core.credentials\": [\"TokenCredential\"]}}}", - "async_imports": "{\"conditional\": {\"stdlib\": {\"typing\": [\"Any\", \"Optional\"]}}, \"regular\": {\"sdkcore\": {\"azure.mgmt.core\": [\"AsyncARMPipelineClient\"], \"azure.core.pipeline\": [\"policies\"], \"azure.mgmt.core.policies\": [\"AsyncARMAutoResourceProviderRegistrationPolicy\"], \"azure.core.settings\": [\"settings\"], \"azure.mgmt.core.tools\": [\"get_arm_endpoints\"], \"azure.profiles\": [\"KnownProfiles\", \"ProfileDefinition\"], \"azure.profiles.multiapiclient\": [\"MultiApiClientMixin\"]}, \"stdlib\": {\"typing\": [\"Optional\", \"cast\"], \"typing_extensions\": [\"Self\"]}, \"local\": {\"._configuration\": [\"MultiapiServiceClientConfiguration\"], \"..._serialization\": [\"Deserializer\", \"Serializer\"], \"._operations_mixin\": [\"MultiapiServiceClientOperationsMixin\"]}}, \"typing\": {\"sdkcore\": {\"azure.core.credentials_async\": [\"AsyncTokenCredential\"]}}}" + "sync_imports": "{\"conditional\": {\"stdlib\": {\"typing\": [\"Any\", \"Optional\"]}}, \"regular\": {\"sdkcore\": {\"azure.mgmt.core\": [\"ARMPipelineClient\"], \"azure.core.pipeline\": [\"policies\"], \"azure.mgmt.core.policies\": [\"ARMAutoResourceProviderRegistrationPolicy\"], \"azure.core.settings\": [\"settings\"], \"azure.mgmt.core.tools\": [\"get_arm_endpoints\"], \"azure.profiles\": [\"KnownProfiles\", \"ProfileDefinition\"], \"azure.profiles.multiapiclient\": [\"MultiApiClientMixin\"]}, \"stdlib\": {\"typing\": [\"Optional\", \"cast\"], \"typing_extensions\": [\"Self\"]}, \"local\": {\"._configuration\": [\"MultiapiServiceClientConfiguration\"], \"._utils.serialization\": [\"Deserializer\", \"Serializer\"], \"._operations_mixin\": [\"MultiapiServiceClientOperationsMixin\"]}}, \"typing\": {\"sdkcore\": {\"azure.core.credentials\": [\"TokenCredential\"]}}}", + "async_imports": "{\"conditional\": {\"stdlib\": {\"typing\": [\"Any\", \"Optional\"]}}, \"regular\": {\"sdkcore\": {\"azure.mgmt.core\": [\"AsyncARMPipelineClient\"], \"azure.core.pipeline\": [\"policies\"], \"azure.mgmt.core.policies\": [\"AsyncARMAutoResourceProviderRegistrationPolicy\"], \"azure.core.settings\": [\"settings\"], \"azure.mgmt.core.tools\": [\"get_arm_endpoints\"], \"azure.profiles\": [\"KnownProfiles\", \"ProfileDefinition\"], \"azure.profiles.multiapiclient\": [\"MultiApiClientMixin\"]}, \"stdlib\": {\"typing\": [\"Optional\", \"cast\"], \"typing_extensions\": [\"Self\"]}, \"local\": {\"._configuration\": [\"MultiapiServiceClientConfiguration\"], \".._utils.serialization\": [\"Deserializer\", \"Serializer\"], \"._operations_mixin\": [\"MultiapiServiceClientOperationsMixin\"]}}, \"typing\": {\"sdkcore\": {\"azure.core.credentials_async\": [\"AsyncTokenCredential\"]}}}" }, "global_parameters": { "sync": { diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiNoAsync/multiapinoasync/v1/_multiapi_service_client.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiNoAsync/multiapinoasync/v1/_multiapi_service_client.py index 6e000706495..91ed3a89637 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiNoAsync/multiapinoasync/v1/_multiapi_service_client.py +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiNoAsync/multiapinoasync/v1/_multiapi_service_client.py @@ -18,8 +18,8 @@ from azure.mgmt.core.tools import get_arm_endpoints from . import models as _models -from .._serialization import Deserializer, Serializer from ._configuration import MultiapiServiceClientConfiguration +from ._utils.serialization import Deserializer, Serializer from .operations import MultiapiServiceClientOperationsMixin, OperationGroupOneOperations if TYPE_CHECKING: diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiNoAsync/multiapinoasync/v1/_utils/__init__.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiNoAsync/multiapinoasync/v1/_utils/__init__.py new file mode 100644 index 00000000000..0af9b28f660 --- /dev/null +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiNoAsync/multiapinoasync/v1/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/MediaTypes/mediatypes/_serialization.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiNoAsync/multiapinoasync/v1/_utils/serialization.py similarity index 100% rename from packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/MediaTypes/mediatypes/_serialization.py rename to packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiNoAsync/multiapinoasync/v1/_utils/serialization.py diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiNoAsync/multiapinoasync/v1/_utils/utils.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiNoAsync/multiapinoasync/v1/_utils/utils.py new file mode 100644 index 00000000000..39b612f39a9 --- /dev/null +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiNoAsync/multiapinoasync/v1/_utils/utils.py @@ -0,0 +1,25 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from abc import ABC +from typing import Generic, TYPE_CHECKING, TypeVar + +if TYPE_CHECKING: + from .serialization import Deserializer, Serializer + + +TClient = TypeVar("TClient") +TConfig = TypeVar("TConfig") + + +class ClientMixinABC(ABC, Generic[TClient, TConfig]): + """DO NOT use this class. It is for internal typing use only.""" + + _client: TClient + _config: TConfig + _serialize: "Serializer" + _deserialize: "Deserializer" diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiNoAsync/multiapinoasync/v1/_vendor.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiNoAsync/multiapinoasync/v1/_vendor.py deleted file mode 100644 index 70517e0b7af..00000000000 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiNoAsync/multiapinoasync/v1/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) AutoRest Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import MultiapiServiceClientConfiguration - -if TYPE_CHECKING: - from azure.core import PipelineClient - - from .._serialization import Deserializer, Serializer - - -class MultiapiServiceClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "PipelineClient" - _config: MultiapiServiceClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiNoAsync/multiapinoasync/v1/models/_models_py3.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiNoAsync/multiapinoasync/v1/models/_models_py3.py index 3379281e03e..0e6ca3b3c37 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiNoAsync/multiapinoasync/v1/models/_models_py3.py +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiNoAsync/multiapinoasync/v1/models/_models_py3.py @@ -8,7 +8,7 @@ from typing import Any, List, Optional, TYPE_CHECKING -from ... import _serialization +from .._utils import serialization as _serialization if TYPE_CHECKING: from .. import models as _models diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiNoAsync/multiapinoasync/v1/operations/_multiapi_service_client_operations.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiNoAsync/multiapinoasync/v1/operations/_multiapi_service_client_operations.py index f59930bc749..fc0da60eeb3 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiNoAsync/multiapinoasync/v1/operations/_multiapi_service_client_operations.py +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiNoAsync/multiapinoasync/v1/operations/_multiapi_service_client_operations.py @@ -10,6 +10,7 @@ from typing import Any, Callable, Dict, IO, Iterable, Iterator, Optional, TypeVar, Union, cast, overload import urllib.parse +from azure.core import PipelineClient from azure.core.exceptions import ( ClientAuthenticationError, HttpResponseError, @@ -30,8 +31,9 @@ from azure.mgmt.core.polling.arm_polling import ARMPolling from .. import models as _models -from ..._serialization import Serializer -from .._vendor import MultiapiServiceClientMixinABC +from .._configuration import MultiapiServiceClientConfiguration +from .._utils.serialization import Serializer +from .._utils.utils import ClientMixinABC T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] @@ -121,7 +123,7 @@ def build_test_different_calls_request(*, greeting_in_english: str, **kwargs: An return HttpRequest(method="GET", url=_url, params=_params, headers=_headers, **kwargs) -class MultiapiServiceClientOperationsMixin(MultiapiServiceClientMixinABC): +class MultiapiServiceClientOperationsMixin(ClientMixinABC[PipelineClient, MultiapiServiceClientConfiguration]): def _api_version(self, op_name: str) -> str: # pylint: disable=unused-argument try: return self._config.api_version diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiNoAsync/multiapinoasync/v1/operations/_operation_group_one_operations.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiNoAsync/multiapinoasync/v1/operations/_operation_group_one_operations.py index 7d0523ea236..34633bfc356 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiNoAsync/multiapinoasync/v1/operations/_operation_group_one_operations.py +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiNoAsync/multiapinoasync/v1/operations/_operation_group_one_operations.py @@ -24,8 +24,8 @@ from azure.mgmt.core.exceptions import ARMErrorFormat from .. import models as _models -from ..._serialization import Deserializer, Serializer from .._configuration import MultiapiServiceClientConfiguration +from .._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiNoAsync/multiapinoasync/v2/_metadata.json b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiNoAsync/multiapinoasync/v2/_metadata.json index aa1e3135b41..4112e0597e3 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiNoAsync/multiapinoasync/v2/_metadata.json +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiNoAsync/multiapinoasync/v2/_metadata.json @@ -10,8 +10,8 @@ "azure_arm": true, "has_public_lro_operations": false, "client_side_validation": false, - "sync_imports": "{\"conditional\": {\"stdlib\": {\"typing\": [\"Any\", \"Optional\"]}}, \"regular\": {\"sdkcore\": {\"azure.mgmt.core\": [\"ARMPipelineClient\"], \"azure.core.pipeline\": [\"policies\"], \"azure.mgmt.core.policies\": [\"ARMAutoResourceProviderRegistrationPolicy\"], \"azure.core.settings\": [\"settings\"], \"azure.mgmt.core.tools\": [\"get_arm_endpoints\"], \"azure.profiles\": [\"KnownProfiles\", \"ProfileDefinition\"], \"azure.profiles.multiapiclient\": [\"MultiApiClientMixin\"]}, \"stdlib\": {\"typing\": [\"Optional\", \"cast\"], \"typing_extensions\": [\"Self\"]}, \"local\": {\"._configuration\": [\"MultiapiServiceClientConfiguration\"], \".._serialization\": [\"Deserializer\", \"Serializer\"], \"._operations_mixin\": [\"MultiapiServiceClientOperationsMixin\"]}}, \"typing\": {\"sdkcore\": {\"azure.core.credentials\": [\"TokenCredential\"]}}}", - "async_imports": "{\"conditional\": {\"stdlib\": {\"typing\": [\"Any\", \"Optional\"]}}, \"regular\": {\"sdkcore\": {\"azure.mgmt.core\": [\"AsyncARMPipelineClient\"], \"azure.core.pipeline\": [\"policies\"], \"azure.mgmt.core.policies\": [\"AsyncARMAutoResourceProviderRegistrationPolicy\"], \"azure.core.settings\": [\"settings\"], \"azure.mgmt.core.tools\": [\"get_arm_endpoints\"], \"azure.profiles\": [\"KnownProfiles\", \"ProfileDefinition\"], \"azure.profiles.multiapiclient\": [\"MultiApiClientMixin\"]}, \"stdlib\": {\"typing\": [\"Optional\", \"cast\"], \"typing_extensions\": [\"Self\"]}, \"local\": {\"._configuration\": [\"MultiapiServiceClientConfiguration\"], \"..._serialization\": [\"Deserializer\", \"Serializer\"], \"._operations_mixin\": [\"MultiapiServiceClientOperationsMixin\"]}}, \"typing\": {\"sdkcore\": {\"azure.core.credentials_async\": [\"AsyncTokenCredential\"]}}}" + "sync_imports": "{\"conditional\": {\"stdlib\": {\"typing\": [\"Any\", \"Optional\"]}}, \"regular\": {\"sdkcore\": {\"azure.mgmt.core\": [\"ARMPipelineClient\"], \"azure.core.pipeline\": [\"policies\"], \"azure.mgmt.core.policies\": [\"ARMAutoResourceProviderRegistrationPolicy\"], \"azure.core.settings\": [\"settings\"], \"azure.mgmt.core.tools\": [\"get_arm_endpoints\"], \"azure.profiles\": [\"KnownProfiles\", \"ProfileDefinition\"], \"azure.profiles.multiapiclient\": [\"MultiApiClientMixin\"]}, \"stdlib\": {\"typing\": [\"Optional\", \"cast\"], \"typing_extensions\": [\"Self\"]}, \"local\": {\"._configuration\": [\"MultiapiServiceClientConfiguration\"], \"._utils.serialization\": [\"Deserializer\", \"Serializer\"], \"._operations_mixin\": [\"MultiapiServiceClientOperationsMixin\"]}}, \"typing\": {\"sdkcore\": {\"azure.core.credentials\": [\"TokenCredential\"]}}}", + "async_imports": "{\"conditional\": {\"stdlib\": {\"typing\": [\"Any\", \"Optional\"]}}, \"regular\": {\"sdkcore\": {\"azure.mgmt.core\": [\"AsyncARMPipelineClient\"], \"azure.core.pipeline\": [\"policies\"], \"azure.mgmt.core.policies\": [\"AsyncARMAutoResourceProviderRegistrationPolicy\"], \"azure.core.settings\": [\"settings\"], \"azure.mgmt.core.tools\": [\"get_arm_endpoints\"], \"azure.profiles\": [\"KnownProfiles\", \"ProfileDefinition\"], \"azure.profiles.multiapiclient\": [\"MultiApiClientMixin\"]}, \"stdlib\": {\"typing\": [\"Optional\", \"cast\"], \"typing_extensions\": [\"Self\"]}, \"local\": {\"._configuration\": [\"MultiapiServiceClientConfiguration\"], \".._utils.serialization\": [\"Deserializer\", \"Serializer\"], \"._operations_mixin\": [\"MultiapiServiceClientOperationsMixin\"]}}, \"typing\": {\"sdkcore\": {\"azure.core.credentials_async\": [\"AsyncTokenCredential\"]}}}" }, "global_parameters": { "sync": { diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiNoAsync/multiapinoasync/v2/_multiapi_service_client.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiNoAsync/multiapinoasync/v2/_multiapi_service_client.py index 986388d2254..3078039d868 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiNoAsync/multiapinoasync/v2/_multiapi_service_client.py +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiNoAsync/multiapinoasync/v2/_multiapi_service_client.py @@ -18,8 +18,8 @@ from azure.mgmt.core.tools import get_arm_endpoints from . import models as _models -from .._serialization import Deserializer, Serializer from ._configuration import MultiapiServiceClientConfiguration +from ._utils.serialization import Deserializer, Serializer from .operations import MultiapiServiceClientOperationsMixin, OperationGroupOneOperations, OperationGroupTwoOperations if TYPE_CHECKING: diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiNoAsync/multiapinoasync/v2/_utils/__init__.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiNoAsync/multiapinoasync/v2/_utils/__init__.py new file mode 100644 index 00000000000..0af9b28f660 --- /dev/null +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiNoAsync/multiapinoasync/v2/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/MergePatchJson/mergepatchjson/_serialization.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiNoAsync/multiapinoasync/v2/_utils/serialization.py similarity index 100% rename from packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/MergePatchJson/mergepatchjson/_serialization.py rename to packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiNoAsync/multiapinoasync/v2/_utils/serialization.py diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiNoAsync/multiapinoasync/v2/_utils/utils.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiNoAsync/multiapinoasync/v2/_utils/utils.py new file mode 100644 index 00000000000..39b612f39a9 --- /dev/null +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiNoAsync/multiapinoasync/v2/_utils/utils.py @@ -0,0 +1,25 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from abc import ABC +from typing import Generic, TYPE_CHECKING, TypeVar + +if TYPE_CHECKING: + from .serialization import Deserializer, Serializer + + +TClient = TypeVar("TClient") +TConfig = TypeVar("TConfig") + + +class ClientMixinABC(ABC, Generic[TClient, TConfig]): + """DO NOT use this class. It is for internal typing use only.""" + + _client: TClient + _config: TConfig + _serialize: "Serializer" + _deserialize: "Deserializer" diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiNoAsync/multiapinoasync/v2/_vendor.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiNoAsync/multiapinoasync/v2/_vendor.py deleted file mode 100644 index 70517e0b7af..00000000000 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiNoAsync/multiapinoasync/v2/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) AutoRest Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import MultiapiServiceClientConfiguration - -if TYPE_CHECKING: - from azure.core import PipelineClient - - from .._serialization import Deserializer, Serializer - - -class MultiapiServiceClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "PipelineClient" - _config: MultiapiServiceClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiNoAsync/multiapinoasync/v2/models/_models_py3.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiNoAsync/multiapinoasync/v2/models/_models_py3.py index 46990252065..a00726a3da2 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiNoAsync/multiapinoasync/v2/models/_models_py3.py +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiNoAsync/multiapinoasync/v2/models/_models_py3.py @@ -8,7 +8,7 @@ from typing import Any, Optional -from ... import _serialization +from .._utils import serialization as _serialization class Error(_serialization.Model): diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiNoAsync/multiapinoasync/v2/operations/_multiapi_service_client_operations.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiNoAsync/multiapinoasync/v2/operations/_multiapi_service_client_operations.py index b0d73815619..634a5619946 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiNoAsync/multiapinoasync/v2/operations/_multiapi_service_client_operations.py +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiNoAsync/multiapinoasync/v2/operations/_multiapi_service_client_operations.py @@ -8,6 +8,7 @@ from collections.abc import MutableMapping from typing import Any, Callable, Dict, Optional, TypeVar +from azure.core import PipelineClient from azure.core.exceptions import ( ClientAuthenticationError, HttpResponseError, @@ -23,8 +24,9 @@ from azure.mgmt.core.exceptions import ARMErrorFormat from .. import models as _models -from ..._serialization import Serializer -from .._vendor import MultiapiServiceClientMixinABC +from .._configuration import MultiapiServiceClientConfiguration +from .._utils.serialization import Serializer +from .._utils.utils import ClientMixinABC T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] @@ -79,7 +81,7 @@ def build_test_different_calls_request( return HttpRequest(method="GET", url=_url, params=_params, headers=_headers, **kwargs) -class MultiapiServiceClientOperationsMixin(MultiapiServiceClientMixinABC): +class MultiapiServiceClientOperationsMixin(ClientMixinABC[PipelineClient, MultiapiServiceClientConfiguration]): def _api_version(self, op_name: str) -> str: # pylint: disable=unused-argument try: return self._config.api_version diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiNoAsync/multiapinoasync/v2/operations/_operation_group_one_operations.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiNoAsync/multiapinoasync/v2/operations/_operation_group_one_operations.py index 1ddeb645152..676131b74b9 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiNoAsync/multiapinoasync/v2/operations/_operation_group_one_operations.py +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiNoAsync/multiapinoasync/v2/operations/_operation_group_one_operations.py @@ -25,8 +25,8 @@ from azure.mgmt.core.exceptions import ARMErrorFormat from .. import models as _models -from ..._serialization import Deserializer, Serializer from .._configuration import MultiapiServiceClientConfiguration +from .._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiNoAsync/multiapinoasync/v2/operations/_operation_group_two_operations.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiNoAsync/multiapinoasync/v2/operations/_operation_group_two_operations.py index 3085e784a81..3505c146afa 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiNoAsync/multiapinoasync/v2/operations/_operation_group_two_operations.py +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiNoAsync/multiapinoasync/v2/operations/_operation_group_two_operations.py @@ -24,8 +24,8 @@ from azure.mgmt.core.exceptions import ARMErrorFormat from .. import models as _models -from ..._serialization import Deserializer, Serializer from .._configuration import MultiapiServiceClientConfiguration +from .._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiNoAsync/multiapinoasync/v3/_metadata.json b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiNoAsync/multiapinoasync/v3/_metadata.json index 89cd8c6ff8f..53721a45ace 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiNoAsync/multiapinoasync/v3/_metadata.json +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiNoAsync/multiapinoasync/v3/_metadata.json @@ -10,8 +10,8 @@ "azure_arm": true, "has_public_lro_operations": false, "client_side_validation": false, - "sync_imports": "{\"conditional\": {\"stdlib\": {\"typing\": [\"Any\", \"Optional\"]}}, \"regular\": {\"sdkcore\": {\"azure.mgmt.core\": [\"ARMPipelineClient\"], \"azure.core.pipeline\": [\"policies\"], \"azure.mgmt.core.policies\": [\"ARMAutoResourceProviderRegistrationPolicy\"], \"azure.core.settings\": [\"settings\"], \"azure.mgmt.core.tools\": [\"get_arm_endpoints\"], \"azure.profiles\": [\"KnownProfiles\", \"ProfileDefinition\"], \"azure.profiles.multiapiclient\": [\"MultiApiClientMixin\"]}, \"stdlib\": {\"typing\": [\"Optional\", \"cast\"], \"typing_extensions\": [\"Self\"]}, \"local\": {\"._configuration\": [\"MultiapiServiceClientConfiguration\"], \".._serialization\": [\"Deserializer\", \"Serializer\"], \"._operations_mixin\": [\"MultiapiServiceClientOperationsMixin\"]}}, \"typing\": {\"sdkcore\": {\"azure.core.credentials\": [\"TokenCredential\"]}}}", - "async_imports": "{\"conditional\": {\"stdlib\": {\"typing\": [\"Any\", \"Optional\"]}}, \"regular\": {\"sdkcore\": {\"azure.mgmt.core\": [\"AsyncARMPipelineClient\"], \"azure.core.pipeline\": [\"policies\"], \"azure.mgmt.core.policies\": [\"AsyncARMAutoResourceProviderRegistrationPolicy\"], \"azure.core.settings\": [\"settings\"], \"azure.mgmt.core.tools\": [\"get_arm_endpoints\"], \"azure.profiles\": [\"KnownProfiles\", \"ProfileDefinition\"], \"azure.profiles.multiapiclient\": [\"MultiApiClientMixin\"]}, \"stdlib\": {\"typing\": [\"Optional\", \"cast\"], \"typing_extensions\": [\"Self\"]}, \"local\": {\"._configuration\": [\"MultiapiServiceClientConfiguration\"], \"..._serialization\": [\"Deserializer\", \"Serializer\"], \"._operations_mixin\": [\"MultiapiServiceClientOperationsMixin\"]}}, \"typing\": {\"sdkcore\": {\"azure.core.credentials_async\": [\"AsyncTokenCredential\"]}}}" + "sync_imports": "{\"conditional\": {\"stdlib\": {\"typing\": [\"Any\", \"Optional\"]}}, \"regular\": {\"sdkcore\": {\"azure.mgmt.core\": [\"ARMPipelineClient\"], \"azure.core.pipeline\": [\"policies\"], \"azure.mgmt.core.policies\": [\"ARMAutoResourceProviderRegistrationPolicy\"], \"azure.core.settings\": [\"settings\"], \"azure.mgmt.core.tools\": [\"get_arm_endpoints\"], \"azure.profiles\": [\"KnownProfiles\", \"ProfileDefinition\"], \"azure.profiles.multiapiclient\": [\"MultiApiClientMixin\"]}, \"stdlib\": {\"typing\": [\"Optional\", \"cast\"], \"typing_extensions\": [\"Self\"]}, \"local\": {\"._configuration\": [\"MultiapiServiceClientConfiguration\"], \"._utils.serialization\": [\"Deserializer\", \"Serializer\"], \"._operations_mixin\": [\"MultiapiServiceClientOperationsMixin\"]}}, \"typing\": {\"sdkcore\": {\"azure.core.credentials\": [\"TokenCredential\"]}}}", + "async_imports": "{\"conditional\": {\"stdlib\": {\"typing\": [\"Any\", \"Optional\"]}}, \"regular\": {\"sdkcore\": {\"azure.mgmt.core\": [\"AsyncARMPipelineClient\"], \"azure.core.pipeline\": [\"policies\"], \"azure.mgmt.core.policies\": [\"AsyncARMAutoResourceProviderRegistrationPolicy\"], \"azure.core.settings\": [\"settings\"], \"azure.mgmt.core.tools\": [\"get_arm_endpoints\"], \"azure.profiles\": [\"KnownProfiles\", \"ProfileDefinition\"], \"azure.profiles.multiapiclient\": [\"MultiApiClientMixin\"]}, \"stdlib\": {\"typing\": [\"Optional\", \"cast\"], \"typing_extensions\": [\"Self\"]}, \"local\": {\"._configuration\": [\"MultiapiServiceClientConfiguration\"], \".._utils.serialization\": [\"Deserializer\", \"Serializer\"], \"._operations_mixin\": [\"MultiapiServiceClientOperationsMixin\"]}}, \"typing\": {\"sdkcore\": {\"azure.core.credentials_async\": [\"AsyncTokenCredential\"]}}}" }, "global_parameters": { "sync": { diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiNoAsync/multiapinoasync/v3/_multiapi_service_client.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiNoAsync/multiapinoasync/v3/_multiapi_service_client.py index f50d2374086..34a5798130e 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiNoAsync/multiapinoasync/v3/_multiapi_service_client.py +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiNoAsync/multiapinoasync/v3/_multiapi_service_client.py @@ -18,8 +18,8 @@ from azure.mgmt.core.tools import get_arm_endpoints from . import models as _models -from .._serialization import Deserializer, Serializer from ._configuration import MultiapiServiceClientConfiguration +from ._utils.serialization import Deserializer, Serializer from .operations import MultiapiServiceClientOperationsMixin, OperationGroupOneOperations, OperationGroupTwoOperations if TYPE_CHECKING: diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiNoAsync/multiapinoasync/v3/_utils/__init__.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiNoAsync/multiapinoasync/v3/_utils/__init__.py new file mode 100644 index 00000000000..0af9b28f660 --- /dev/null +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiNoAsync/multiapinoasync/v3/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ModelFlattening/modelflattening/_serialization.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiNoAsync/multiapinoasync/v3/_utils/serialization.py similarity index 100% rename from packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ModelFlattening/modelflattening/_serialization.py rename to packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiNoAsync/multiapinoasync/v3/_utils/serialization.py diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiNoAsync/multiapinoasync/v3/_utils/utils.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiNoAsync/multiapinoasync/v3/_utils/utils.py new file mode 100644 index 00000000000..39b612f39a9 --- /dev/null +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiNoAsync/multiapinoasync/v3/_utils/utils.py @@ -0,0 +1,25 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from abc import ABC +from typing import Generic, TYPE_CHECKING, TypeVar + +if TYPE_CHECKING: + from .serialization import Deserializer, Serializer + + +TClient = TypeVar("TClient") +TConfig = TypeVar("TConfig") + + +class ClientMixinABC(ABC, Generic[TClient, TConfig]): + """DO NOT use this class. It is for internal typing use only.""" + + _client: TClient + _config: TConfig + _serialize: "Serializer" + _deserialize: "Deserializer" diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiNoAsync/multiapinoasync/v3/_vendor.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiNoAsync/multiapinoasync/v3/_vendor.py deleted file mode 100644 index 70517e0b7af..00000000000 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiNoAsync/multiapinoasync/v3/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) AutoRest Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import MultiapiServiceClientConfiguration - -if TYPE_CHECKING: - from azure.core import PipelineClient - - from .._serialization import Deserializer, Serializer - - -class MultiapiServiceClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "PipelineClient" - _config: MultiapiServiceClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiNoAsync/multiapinoasync/v3/models/_models_py3.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiNoAsync/multiapinoasync/v3/models/_models_py3.py index 04f6ab18536..1b8cf407f51 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiNoAsync/multiapinoasync/v3/models/_models_py3.py +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiNoAsync/multiapinoasync/v3/models/_models_py3.py @@ -8,7 +8,7 @@ from typing import Any, List, Optional, TYPE_CHECKING -from ... import _serialization +from .._utils import serialization as _serialization if TYPE_CHECKING: from .. import models as _models diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiNoAsync/multiapinoasync/v3/operations/_multiapi_service_client_operations.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiNoAsync/multiapinoasync/v3/operations/_multiapi_service_client_operations.py index cd4fac0a58f..ef9794ac061 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiNoAsync/multiapinoasync/v3/operations/_multiapi_service_client_operations.py +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiNoAsync/multiapinoasync/v3/operations/_multiapi_service_client_operations.py @@ -9,6 +9,7 @@ from typing import Any, Callable, Dict, Iterable, Optional, TypeVar import urllib.parse +from azure.core import PipelineClient from azure.core.exceptions import ( ClientAuthenticationError, HttpResponseError, @@ -25,8 +26,9 @@ from azure.mgmt.core.exceptions import ARMErrorFormat from .. import models as _models -from ..._serialization import Serializer -from .._vendor import MultiapiServiceClientMixinABC +from .._configuration import MultiapiServiceClientConfiguration +from .._utils.serialization import Serializer +from .._utils.utils import ClientMixinABC T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] @@ -79,7 +81,7 @@ def build_test_different_calls_request( return HttpRequest(method="GET", url=_url, params=_params, headers=_headers, **kwargs) -class MultiapiServiceClientOperationsMixin(MultiapiServiceClientMixinABC): +class MultiapiServiceClientOperationsMixin(ClientMixinABC[PipelineClient, MultiapiServiceClientConfiguration]): def _api_version(self, op_name: str) -> str: # pylint: disable=unused-argument try: return self._config.api_version diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiNoAsync/multiapinoasync/v3/operations/_operation_group_one_operations.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiNoAsync/multiapinoasync/v3/operations/_operation_group_one_operations.py index 4e2f855f9b2..49c69251d93 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiNoAsync/multiapinoasync/v3/operations/_operation_group_one_operations.py +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiNoAsync/multiapinoasync/v3/operations/_operation_group_one_operations.py @@ -27,8 +27,8 @@ from azure.mgmt.core.exceptions import ARMErrorFormat from .. import models as _models -from ..._serialization import Deserializer, Serializer from .._configuration import MultiapiServiceClientConfiguration +from .._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiNoAsync/multiapinoasync/v3/operations/_operation_group_two_operations.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiNoAsync/multiapinoasync/v3/operations/_operation_group_two_operations.py index 7f062724c26..7a11f4395c8 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiNoAsync/multiapinoasync/v3/operations/_operation_group_two_operations.py +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiNoAsync/multiapinoasync/v3/operations/_operation_group_two_operations.py @@ -25,8 +25,8 @@ from azure.mgmt.core.exceptions import ARMErrorFormat from .. import models as _models -from ..._serialization import Deserializer, Serializer from .._configuration import MultiapiServiceClientConfiguration +from .._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiSecurity/multiapisecurity/_multiapi_service_client.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiSecurity/multiapisecurity/_multiapi_service_client.py index d3dc33f622a..8da496ee64a 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiSecurity/multiapisecurity/_multiapi_service_client.py +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiSecurity/multiapisecurity/_multiapi_service_client.py @@ -19,7 +19,7 @@ from ._configuration import MultiapiServiceClientConfiguration from ._operations_mixin import MultiapiServiceClientOperationsMixin -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer if TYPE_CHECKING: # pylint: disable=unused-import,ungrouped-imports diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiSecurity/multiapisecurity/_operations_mixin.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiSecurity/multiapisecurity/_operations_mixin.py index a061f07c6d6..de7dab5ddf7 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiSecurity/multiapisecurity/_operations_mixin.py +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiSecurity/multiapisecurity/_operations_mixin.py @@ -8,7 +8,7 @@ # Changes may cause incorrect behavior and will be lost if the code is # regenerated. # -------------------------------------------------------------------------- -from ._serialization import Serializer, Deserializer +from ._utils.serialization import Serializer, Deserializer from io import IOBase from typing import Any, IO, Iterable, Iterator, Optional, Union diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiSecurity/multiapisecurity/_utils/__init__.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiSecurity/multiapisecurity/_utils/__init__.py new file mode 100644 index 00000000000..59333308532 --- /dev/null +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiSecurity/multiapisecurity/_utils/__init__.py @@ -0,0 +1,10 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is +# regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiSecurity/multiapisecurity/_utils/serialization.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiSecurity/multiapisecurity/_utils/serialization.py new file mode 100644 index 00000000000..05bcd7d403a --- /dev/null +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiSecurity/multiapisecurity/_utils/serialization.py @@ -0,0 +1,2025 @@ +# coding=utf-8 + +# pyright: reportUnnecessaryTypeIgnoreComment=false + +from base64 import b64decode, b64encode +import calendar +import datetime +import decimal +import email +from enum import Enum +import json +import logging +import re +import sys +import codecs +from typing import ( + Dict, + Any, + cast, + Optional, + Union, + AnyStr, + IO, + Mapping, + Callable, + MutableMapping, + List, +) + +try: + from urllib import quote # type: ignore +except ImportError: + from urllib.parse import quote +import xml.etree.ElementTree as ET + +import isodate # type: ignore +from typing_extensions import Self + +from azure.core.exceptions import DeserializationError, SerializationError +from azure.core.serialization import NULL as CoreNull + +_BOM = codecs.BOM_UTF8.decode(encoding="utf-8") + +JSON = MutableMapping[str, Any] + + +class RawDeserializer: + + # Accept "text" because we're open minded people... + JSON_REGEXP = re.compile(r"^(application|text)/([a-z+.]+\+)?json$") + + # Name used in context + CONTEXT_NAME = "deserialized_data" + + @classmethod + def deserialize_from_text(cls, data: Optional[Union[AnyStr, IO]], content_type: Optional[str] = None) -> Any: + """Decode data according to content-type. + + Accept a stream of data as well, but will be load at once in memory for now. + + If no content-type, will return the string version (not bytes, not stream) + + :param data: Input, could be bytes or stream (will be decoded with UTF8) or text + :type data: str or bytes or IO + :param str content_type: The content type. + :return: The deserialized data. + :rtype: object + """ + if hasattr(data, "read"): + # Assume a stream + data = cast(IO, data).read() + + if isinstance(data, bytes): + data_as_str = data.decode(encoding="utf-8-sig") + else: + # Explain to mypy the correct type. + data_as_str = cast(str, data) + + # Remove Byte Order Mark if present in string + data_as_str = data_as_str.lstrip(_BOM) + + if content_type is None: + return data + + if cls.JSON_REGEXP.match(content_type): + try: + return json.loads(data_as_str) + except ValueError as err: + raise DeserializationError("JSON is invalid: {}".format(err), err) from err + elif "xml" in (content_type or []): + try: + + try: + if isinstance(data, unicode): # type: ignore + # If I'm Python 2.7 and unicode XML will scream if I try a "fromstring" on unicode string + data_as_str = data_as_str.encode(encoding="utf-8") # type: ignore + except NameError: + pass + + return ET.fromstring(data_as_str) # nosec + except ET.ParseError as err: + # It might be because the server has an issue, and returned JSON with + # content-type XML.... + # So let's try a JSON load, and if it's still broken + # let's flow the initial exception + def _json_attemp(data): + try: + return True, json.loads(data) + except ValueError: + return False, None # Don't care about this one + + success, json_result = _json_attemp(data) + if success: + return json_result + # If i'm here, it's not JSON, it's not XML, let's scream + # and raise the last context in this block (the XML exception) + # The function hack is because Py2.7 messes up with exception + # context otherwise. + _LOGGER.critical("Wasn't XML not JSON, failing") + raise DeserializationError("XML is invalid") from err + elif content_type.startswith("text/"): + return data_as_str + raise DeserializationError("Cannot deserialize content-type: {}".format(content_type)) + + @classmethod + def deserialize_from_http_generics(cls, body_bytes: Optional[Union[AnyStr, IO]], headers: Mapping) -> Any: + """Deserialize from HTTP response. + + Use bytes and headers to NOT use any requests/aiohttp or whatever + specific implementation. + Headers will tested for "content-type" + + :param bytes body_bytes: The body of the response. + :param dict headers: The headers of the response. + :returns: The deserialized data. + :rtype: object + """ + # Try to use content-type from headers if available + content_type = None + if "content-type" in headers: + content_type = headers["content-type"].split(";")[0].strip().lower() + # Ouch, this server did not declare what it sent... + # Let's guess it's JSON... + # Also, since Autorest was considering that an empty body was a valid JSON, + # need that test as well.... + else: + content_type = "application/json" + + if body_bytes: + return cls.deserialize_from_text(body_bytes, content_type) + return None + + +_LOGGER = logging.getLogger(__name__) + +try: + _long_type = long # type: ignore +except NameError: + _long_type = int + +TZ_UTC = datetime.timezone.utc + +_FLATTEN = re.compile(r"(? None: + self.additional_properties: Optional[Dict[str, Any]] = {} + for k in kwargs: # pylint: disable=consider-using-dict-items + if k not in self._attribute_map: + _LOGGER.warning("%s is not a known attribute of class %s and will be ignored", k, self.__class__) + elif k in self._validation and self._validation[k].get("readonly", False): + _LOGGER.warning("Readonly attribute %s will be ignored in class %s", k, self.__class__) + else: + setattr(self, k, kwargs[k]) + + def __eq__(self, other: Any) -> bool: + """Compare objects by comparing all attributes. + + :param object other: The object to compare + :returns: True if objects are equal + :rtype: bool + """ + if isinstance(other, self.__class__): + return self.__dict__ == other.__dict__ + return False + + def __ne__(self, other: Any) -> bool: + """Compare objects by comparing all attributes. + + :param object other: The object to compare + :returns: True if objects are not equal + :rtype: bool + """ + return not self.__eq__(other) + + def __str__(self) -> str: + return str(self.__dict__) + + @classmethod + def enable_additional_properties_sending(cls) -> None: + cls._attribute_map["additional_properties"] = {"key": "", "type": "{object}"} + + @classmethod + def is_xml_model(cls) -> bool: + try: + cls._xml_map # type: ignore + except AttributeError: + return False + return True + + @classmethod + def _create_xml_node(cls): + """Create XML node. + + :returns: The XML node + :rtype: xml.etree.ElementTree.Element + """ + try: + xml_map = cls._xml_map # type: ignore + except AttributeError: + xml_map = {} + + return _create_xml_node(xml_map.get("name", cls.__name__), xml_map.get("prefix", None), xml_map.get("ns", None)) + + def serialize(self, keep_readonly: bool = False, **kwargs: Any) -> JSON: + """Return the JSON that would be sent to server from this model. + + This is an alias to `as_dict(full_restapi_key_transformer, keep_readonly=False)`. + + If you want XML serialization, you can pass the kwargs is_xml=True. + + :param bool keep_readonly: If you want to serialize the readonly attributes + :returns: A dict JSON compatible object + :rtype: dict + """ + serializer = Serializer(self._infer_class_models()) + return serializer._serialize( # type: ignore # pylint: disable=protected-access + self, keep_readonly=keep_readonly, **kwargs + ) + + def as_dict( + self, + keep_readonly: bool = True, + key_transformer: Callable[[str, Dict[str, Any], Any], Any] = attribute_transformer, + **kwargs: Any + ) -> JSON: + """Return a dict that can be serialized using json.dump. + + Advanced usage might optionally use a callback as parameter: + + .. code::python + + def my_key_transformer(key, attr_desc, value): + return key + + Key is the attribute name used in Python. Attr_desc + is a dict of metadata. Currently contains 'type' with the + msrest type and 'key' with the RestAPI encoded key. + Value is the current value in this object. + + The string returned will be used to serialize the key. + If the return type is a list, this is considered hierarchical + result dict. + + See the three examples in this file: + + - attribute_transformer + - full_restapi_key_transformer + - last_restapi_key_transformer + + If you want XML serialization, you can pass the kwargs is_xml=True. + + :param bool keep_readonly: If you want to serialize the readonly attributes + :param function key_transformer: A key transformer function. + :returns: A dict JSON compatible object + :rtype: dict + """ + serializer = Serializer(self._infer_class_models()) + return serializer._serialize( # type: ignore # pylint: disable=protected-access + self, key_transformer=key_transformer, keep_readonly=keep_readonly, **kwargs + ) + + @classmethod + def _infer_class_models(cls): + try: + str_models = cls.__module__.rsplit(".", 1)[0] + models = sys.modules[str_models] + client_models = {k: v for k, v in models.__dict__.items() if isinstance(v, type)} + if cls.__name__ not in client_models: + raise ValueError("Not Autorest generated code") + except Exception: # pylint: disable=broad-exception-caught + # Assume it's not Autorest generated (tests?). Add ourselves as dependencies. + client_models = {cls.__name__: cls} + return client_models + + @classmethod + def deserialize(cls, data: Any, content_type: Optional[str] = None) -> Self: + """Parse a str using the RestAPI syntax and return a model. + + :param str data: A str using RestAPI structure. JSON by default. + :param str content_type: JSON by default, set application/xml if XML. + :returns: An instance of this model + :raises DeserializationError: if something went wrong + :rtype: Self + """ + deserializer = Deserializer(cls._infer_class_models()) + return deserializer(cls.__name__, data, content_type=content_type) # type: ignore + + @classmethod + def from_dict( + cls, + data: Any, + key_extractors: Optional[Callable[[str, Dict[str, Any], Any], Any]] = None, + content_type: Optional[str] = None, + ) -> Self: + """Parse a dict using given key extractor return a model. + + By default consider key + extractors (rest_key_case_insensitive_extractor, attribute_key_case_insensitive_extractor + and last_rest_key_case_insensitive_extractor) + + :param dict data: A dict using RestAPI structure + :param function key_extractors: A key extractor function. + :param str content_type: JSON by default, set application/xml if XML. + :returns: An instance of this model + :raises DeserializationError: if something went wrong + :rtype: Self + """ + deserializer = Deserializer(cls._infer_class_models()) + deserializer.key_extractors = ( # type: ignore + [ # type: ignore + attribute_key_case_insensitive_extractor, + rest_key_case_insensitive_extractor, + last_rest_key_case_insensitive_extractor, + ] + if key_extractors is None + else key_extractors + ) + return deserializer(cls.__name__, data, content_type=content_type) # type: ignore + + @classmethod + def _flatten_subtype(cls, key, objects): + if "_subtype_map" not in cls.__dict__: + return {} + result = dict(cls._subtype_map[key]) + for valuetype in cls._subtype_map[key].values(): + result.update(objects[valuetype]._flatten_subtype(key, objects)) # pylint: disable=protected-access + return result + + @classmethod + def _classify(cls, response, objects): + """Check the class _subtype_map for any child classes. + We want to ignore any inherited _subtype_maps. + + :param dict response: The initial data + :param dict objects: The class objects + :returns: The class to be used + :rtype: class + """ + for subtype_key in cls.__dict__.get("_subtype_map", {}).keys(): + subtype_value = None + + if not isinstance(response, ET.Element): + rest_api_response_key = cls._get_rest_key_parts(subtype_key)[-1] + subtype_value = response.get(rest_api_response_key, None) or response.get(subtype_key, None) + else: + subtype_value = xml_key_extractor(subtype_key, cls._attribute_map[subtype_key], response) + if subtype_value: + # Try to match base class. Can be class name only + # (bug to fix in Autorest to support x-ms-discriminator-name) + if cls.__name__ == subtype_value: + return cls + flatten_mapping_type = cls._flatten_subtype(subtype_key, objects) + try: + return objects[flatten_mapping_type[subtype_value]] # type: ignore + except KeyError: + _LOGGER.warning( + "Subtype value %s has no mapping, use base class %s.", + subtype_value, + cls.__name__, + ) + break + else: + _LOGGER.warning("Discriminator %s is absent or null, use base class %s.", subtype_key, cls.__name__) + break + return cls + + @classmethod + def _get_rest_key_parts(cls, attr_key): + """Get the RestAPI key of this attr, split it and decode part + :param str attr_key: Attribute key must be in attribute_map. + :returns: A list of RestAPI part + :rtype: list + """ + rest_split_key = _FLATTEN.split(cls._attribute_map[attr_key]["key"]) + return [_decode_attribute_map_key(key_part) for key_part in rest_split_key] + + +def _decode_attribute_map_key(key): + """This decode a key in an _attribute_map to the actual key we want to look at + inside the received data. + + :param str key: A key string from the generated code + :returns: The decoded key + :rtype: str + """ + return key.replace("\\.", ".") + + +class Serializer: # pylint: disable=too-many-public-methods + """Request object model serializer.""" + + basic_types = {str: "str", int: "int", bool: "bool", float: "float"} + + _xml_basic_types_serializers = {"bool": lambda x: str(x).lower()} + days = {0: "Mon", 1: "Tue", 2: "Wed", 3: "Thu", 4: "Fri", 5: "Sat", 6: "Sun"} + months = { + 1: "Jan", + 2: "Feb", + 3: "Mar", + 4: "Apr", + 5: "May", + 6: "Jun", + 7: "Jul", + 8: "Aug", + 9: "Sep", + 10: "Oct", + 11: "Nov", + 12: "Dec", + } + validation = { + "min_length": lambda x, y: len(x) < y, + "max_length": lambda x, y: len(x) > y, + "minimum": lambda x, y: x < y, + "maximum": lambda x, y: x > y, + "minimum_ex": lambda x, y: x <= y, + "maximum_ex": lambda x, y: x >= y, + "min_items": lambda x, y: len(x) < y, + "max_items": lambda x, y: len(x) > y, + "pattern": lambda x, y: not re.match(y, x, re.UNICODE), + "unique": lambda x, y: len(x) != len(set(x)), + "multiple": lambda x, y: x % y != 0, + } + + def __init__(self, classes: Optional[Mapping[str, type]] = None) -> None: + self.serialize_type = { + "iso-8601": Serializer.serialize_iso, + "rfc-1123": Serializer.serialize_rfc, + "unix-time": Serializer.serialize_unix, + "duration": Serializer.serialize_duration, + "date": Serializer.serialize_date, + "time": Serializer.serialize_time, + "decimal": Serializer.serialize_decimal, + "long": Serializer.serialize_long, + "bytearray": Serializer.serialize_bytearray, + "base64": Serializer.serialize_base64, + "object": self.serialize_object, + "[]": self.serialize_iter, + "{}": self.serialize_dict, + } + self.dependencies: Dict[str, type] = dict(classes) if classes else {} + self.key_transformer = full_restapi_key_transformer + self.client_side_validation = True + + def _serialize( # pylint: disable=too-many-nested-blocks, too-many-branches, too-many-statements, too-many-locals + self, target_obj, data_type=None, **kwargs + ): + """Serialize data into a string according to type. + + :param object target_obj: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str, dict + :raises SerializationError: if serialization fails. + :returns: The serialized data. + """ + key_transformer = kwargs.get("key_transformer", self.key_transformer) + keep_readonly = kwargs.get("keep_readonly", False) + if target_obj is None: + return None + + attr_name = None + class_name = target_obj.__class__.__name__ + + if data_type: + return self.serialize_data(target_obj, data_type, **kwargs) + + if not hasattr(target_obj, "_attribute_map"): + data_type = type(target_obj).__name__ + if data_type in self.basic_types.values(): + return self.serialize_data(target_obj, data_type, **kwargs) + + # Force "is_xml" kwargs if we detect a XML model + try: + is_xml_model_serialization = kwargs["is_xml"] + except KeyError: + is_xml_model_serialization = kwargs.setdefault("is_xml", target_obj.is_xml_model()) + + serialized = {} + if is_xml_model_serialization: + serialized = target_obj._create_xml_node() # pylint: disable=protected-access + try: + attributes = target_obj._attribute_map # pylint: disable=protected-access + for attr, attr_desc in attributes.items(): + attr_name = attr + if not keep_readonly and target_obj._validation.get( # pylint: disable=protected-access + attr_name, {} + ).get("readonly", False): + continue + + if attr_name == "additional_properties" and attr_desc["key"] == "": + if target_obj.additional_properties is not None: + serialized.update(target_obj.additional_properties) + continue + try: + + orig_attr = getattr(target_obj, attr) + if is_xml_model_serialization: + pass # Don't provide "transformer" for XML for now. Keep "orig_attr" + else: # JSON + keys, orig_attr = key_transformer(attr, attr_desc.copy(), orig_attr) + keys = keys if isinstance(keys, list) else [keys] + + kwargs["serialization_ctxt"] = attr_desc + new_attr = self.serialize_data(orig_attr, attr_desc["type"], **kwargs) + + if is_xml_model_serialization: + xml_desc = attr_desc.get("xml", {}) + xml_name = xml_desc.get("name", attr_desc["key"]) + xml_prefix = xml_desc.get("prefix", None) + xml_ns = xml_desc.get("ns", None) + if xml_desc.get("attr", False): + if xml_ns: + ET.register_namespace(xml_prefix, xml_ns) + xml_name = "{{{}}}{}".format(xml_ns, xml_name) + serialized.set(xml_name, new_attr) # type: ignore + continue + if xml_desc.get("text", False): + serialized.text = new_attr # type: ignore + continue + if isinstance(new_attr, list): + serialized.extend(new_attr) # type: ignore + elif isinstance(new_attr, ET.Element): + # If the down XML has no XML/Name, + # we MUST replace the tag with the local tag. But keeping the namespaces. + if "name" not in getattr(orig_attr, "_xml_map", {}): + splitted_tag = new_attr.tag.split("}") + if len(splitted_tag) == 2: # Namespace + new_attr.tag = "}".join([splitted_tag[0], xml_name]) + else: + new_attr.tag = xml_name + serialized.append(new_attr) # type: ignore + else: # That's a basic type + # Integrate namespace if necessary + local_node = _create_xml_node(xml_name, xml_prefix, xml_ns) + local_node.text = str(new_attr) + serialized.append(local_node) # type: ignore + else: # JSON + for k in reversed(keys): # type: ignore + new_attr = {k: new_attr} + + _new_attr = new_attr + _serialized = serialized + for k in keys: # type: ignore + if k not in _serialized: + _serialized.update(_new_attr) # type: ignore + _new_attr = _new_attr[k] # type: ignore + _serialized = _serialized[k] + except ValueError as err: + if isinstance(err, SerializationError): + raise + + except (AttributeError, KeyError, TypeError) as err: + msg = "Attribute {} in object {} cannot be serialized.\n{}".format(attr_name, class_name, str(target_obj)) + raise SerializationError(msg) from err + return serialized + + def body(self, data, data_type, **kwargs): + """Serialize data intended for a request body. + + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: dict + :raises SerializationError: if serialization fails. + :raises ValueError: if data is None + :returns: The serialized request body + """ + + # Just in case this is a dict + internal_data_type_str = data_type.strip("[]{}") + internal_data_type = self.dependencies.get(internal_data_type_str, None) + try: + is_xml_model_serialization = kwargs["is_xml"] + except KeyError: + if internal_data_type and issubclass(internal_data_type, Model): + is_xml_model_serialization = kwargs.setdefault("is_xml", internal_data_type.is_xml_model()) + else: + is_xml_model_serialization = False + if internal_data_type and not isinstance(internal_data_type, Enum): + try: + deserializer = Deserializer(self.dependencies) + # Since it's on serialization, it's almost sure that format is not JSON REST + # We're not able to deal with additional properties for now. + deserializer.additional_properties_detection = False + if is_xml_model_serialization: + deserializer.key_extractors = [ # type: ignore + attribute_key_case_insensitive_extractor, + ] + else: + deserializer.key_extractors = [ + rest_key_case_insensitive_extractor, + attribute_key_case_insensitive_extractor, + last_rest_key_case_insensitive_extractor, + ] + data = deserializer._deserialize(data_type, data) # pylint: disable=protected-access + except DeserializationError as err: + raise SerializationError("Unable to build a model: " + str(err)) from err + + return self._serialize(data, data_type, **kwargs) + + def url(self, name, data, data_type, **kwargs): + """Serialize data intended for a URL path. + + :param str name: The name of the URL path parameter. + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str + :returns: The serialized URL path + :raises TypeError: if serialization fails. + :raises ValueError: if data is None + """ + try: + output = self.serialize_data(data, data_type, **kwargs) + if data_type == "bool": + output = json.dumps(output) + + if kwargs.get("skip_quote") is True: + output = str(output) + output = output.replace("{", quote("{")).replace("}", quote("}")) + else: + output = quote(str(output), safe="") + except SerializationError as exc: + raise TypeError("{} must be type {}.".format(name, data_type)) from exc + return output + + def query(self, name, data, data_type, **kwargs): + """Serialize data intended for a URL query. + + :param str name: The name of the query parameter. + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str, list + :raises TypeError: if serialization fails. + :raises ValueError: if data is None + :returns: The serialized query parameter + """ + try: + # Treat the list aside, since we don't want to encode the div separator + if data_type.startswith("["): + internal_data_type = data_type[1:-1] + do_quote = not kwargs.get("skip_quote", False) + return self.serialize_iter(data, internal_data_type, do_quote=do_quote, **kwargs) + + # Not a list, regular serialization + output = self.serialize_data(data, data_type, **kwargs) + if data_type == "bool": + output = json.dumps(output) + if kwargs.get("skip_quote") is True: + output = str(output) + else: + output = quote(str(output), safe="") + except SerializationError as exc: + raise TypeError("{} must be type {}.".format(name, data_type)) from exc + return str(output) + + def header(self, name, data, data_type, **kwargs): + """Serialize data intended for a request header. + + :param str name: The name of the header. + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str + :raises TypeError: if serialization fails. + :raises ValueError: if data is None + :returns: The serialized header + """ + try: + if data_type in ["[str]"]: + data = ["" if d is None else d for d in data] + + output = self.serialize_data(data, data_type, **kwargs) + if data_type == "bool": + output = json.dumps(output) + except SerializationError as exc: + raise TypeError("{} must be type {}.".format(name, data_type)) from exc + return str(output) + + def serialize_data(self, data, data_type, **kwargs): + """Serialize generic data according to supplied data type. + + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :raises AttributeError: if required data is None. + :raises ValueError: if data is None + :raises SerializationError: if serialization fails. + :returns: The serialized data. + :rtype: str, int, float, bool, dict, list + """ + if data is None: + raise ValueError("No value for given attribute") + + try: + if data is CoreNull: + return None + if data_type in self.basic_types.values(): + return self.serialize_basic(data, data_type, **kwargs) + + if data_type in self.serialize_type: + return self.serialize_type[data_type](data, **kwargs) + + # If dependencies is empty, try with current data class + # It has to be a subclass of Enum anyway + enum_type = self.dependencies.get(data_type, data.__class__) + if issubclass(enum_type, Enum): + return Serializer.serialize_enum(data, enum_obj=enum_type) + + iter_type = data_type[0] + data_type[-1] + if iter_type in self.serialize_type: + return self.serialize_type[iter_type](data, data_type[1:-1], **kwargs) + + except (ValueError, TypeError) as err: + msg = "Unable to serialize value: {!r} as type: {!r}." + raise SerializationError(msg.format(data, data_type)) from err + return self._serialize(data, **kwargs) + + @classmethod + def _get_custom_serializers(cls, data_type, **kwargs): # pylint: disable=inconsistent-return-statements + custom_serializer = kwargs.get("basic_types_serializers", {}).get(data_type) + if custom_serializer: + return custom_serializer + if kwargs.get("is_xml", False): + return cls._xml_basic_types_serializers.get(data_type) + + @classmethod + def serialize_basic(cls, data, data_type, **kwargs): + """Serialize basic builting data type. + Serializes objects to str, int, float or bool. + + Possible kwargs: + - basic_types_serializers dict[str, callable] : If set, use the callable as serializer + - is_xml bool : If set, use xml_basic_types_serializers + + :param obj data: Object to be serialized. + :param str data_type: Type of object in the iterable. + :rtype: str, int, float, bool + :return: serialized object + """ + custom_serializer = cls._get_custom_serializers(data_type, **kwargs) + if custom_serializer: + return custom_serializer(data) + if data_type == "str": + return cls.serialize_unicode(data) + return eval(data_type)(data) # nosec # pylint: disable=eval-used + + @classmethod + def serialize_unicode(cls, data): + """Special handling for serializing unicode strings in Py2. + Encode to UTF-8 if unicode, otherwise handle as a str. + + :param str data: Object to be serialized. + :rtype: str + :return: serialized object + """ + try: # If I received an enum, return its value + return data.value + except AttributeError: + pass + + try: + if isinstance(data, unicode): # type: ignore + # Don't change it, JSON and XML ElementTree are totally able + # to serialize correctly u'' strings + return data + except NameError: + return str(data) + return str(data) + + def serialize_iter(self, data, iter_type, div=None, **kwargs): + """Serialize iterable. + + Supported kwargs: + - serialization_ctxt dict : The current entry of _attribute_map, or same format. + serialization_ctxt['type'] should be same as data_type. + - is_xml bool : If set, serialize as XML + + :param list data: Object to be serialized. + :param str iter_type: Type of object in the iterable. + :param str div: If set, this str will be used to combine the elements + in the iterable into a combined string. Default is 'None'. + Defaults to False. + :rtype: list, str + :return: serialized iterable + """ + if isinstance(data, str): + raise SerializationError("Refuse str type as a valid iter type.") + + serialization_ctxt = kwargs.get("serialization_ctxt", {}) + is_xml = kwargs.get("is_xml", False) + + serialized = [] + for d in data: + try: + serialized.append(self.serialize_data(d, iter_type, **kwargs)) + except ValueError as err: + if isinstance(err, SerializationError): + raise + serialized.append(None) + + if kwargs.get("do_quote", False): + serialized = ["" if s is None else quote(str(s), safe="") for s in serialized] + + if div: + serialized = ["" if s is None else str(s) for s in serialized] + serialized = div.join(serialized) + + if "xml" in serialization_ctxt or is_xml: + # XML serialization is more complicated + xml_desc = serialization_ctxt.get("xml", {}) + xml_name = xml_desc.get("name") + if not xml_name: + xml_name = serialization_ctxt["key"] + + # Create a wrap node if necessary (use the fact that Element and list have "append") + is_wrapped = xml_desc.get("wrapped", False) + node_name = xml_desc.get("itemsName", xml_name) + if is_wrapped: + final_result = _create_xml_node(xml_name, xml_desc.get("prefix", None), xml_desc.get("ns", None)) + else: + final_result = [] + # All list elements to "local_node" + for el in serialized: + if isinstance(el, ET.Element): + el_node = el + else: + el_node = _create_xml_node(node_name, xml_desc.get("prefix", None), xml_desc.get("ns", None)) + if el is not None: # Otherwise it writes "None" :-p + el_node.text = str(el) + final_result.append(el_node) + return final_result + return serialized + + def serialize_dict(self, attr, dict_type, **kwargs): + """Serialize a dictionary of objects. + + :param dict attr: Object to be serialized. + :param str dict_type: Type of object in the dictionary. + :rtype: dict + :return: serialized dictionary + """ + serialization_ctxt = kwargs.get("serialization_ctxt", {}) + serialized = {} + for key, value in attr.items(): + try: + serialized[self.serialize_unicode(key)] = self.serialize_data(value, dict_type, **kwargs) + except ValueError as err: + if isinstance(err, SerializationError): + raise + serialized[self.serialize_unicode(key)] = None + + if "xml" in serialization_ctxt: + # XML serialization is more complicated + xml_desc = serialization_ctxt["xml"] + xml_name = xml_desc["name"] + + final_result = _create_xml_node(xml_name, xml_desc.get("prefix", None), xml_desc.get("ns", None)) + for key, value in serialized.items(): + ET.SubElement(final_result, key).text = value + return final_result + + return serialized + + def serialize_object(self, attr, **kwargs): # pylint: disable=too-many-return-statements + """Serialize a generic object. + This will be handled as a dictionary. If object passed in is not + a basic type (str, int, float, dict, list) it will simply be + cast to str. + + :param dict attr: Object to be serialized. + :rtype: dict or str + :return: serialized object + """ + if attr is None: + return None + if isinstance(attr, ET.Element): + return attr + obj_type = type(attr) + if obj_type in self.basic_types: + return self.serialize_basic(attr, self.basic_types[obj_type], **kwargs) + if obj_type is _long_type: + return self.serialize_long(attr) + if obj_type is str: + return self.serialize_unicode(attr) + if obj_type is datetime.datetime: + return self.serialize_iso(attr) + if obj_type is datetime.date: + return self.serialize_date(attr) + if obj_type is datetime.time: + return self.serialize_time(attr) + if obj_type is datetime.timedelta: + return self.serialize_duration(attr) + if obj_type is decimal.Decimal: + return self.serialize_decimal(attr) + + # If it's a model or I know this dependency, serialize as a Model + if obj_type in self.dependencies.values() or isinstance(attr, Model): + return self._serialize(attr) + + if obj_type == dict: + serialized = {} + for key, value in attr.items(): + try: + serialized[self.serialize_unicode(key)] = self.serialize_object(value, **kwargs) + except ValueError: + serialized[self.serialize_unicode(key)] = None + return serialized + + if obj_type == list: + serialized = [] + for obj in attr: + try: + serialized.append(self.serialize_object(obj, **kwargs)) + except ValueError: + pass + return serialized + return str(attr) + + @staticmethod + def serialize_enum(attr, enum_obj=None): + try: + result = attr.value + except AttributeError: + result = attr + try: + enum_obj(result) # type: ignore + return result + except ValueError as exc: + for enum_value in enum_obj: # type: ignore + if enum_value.value.lower() == str(attr).lower(): + return enum_value.value + error = "{!r} is not valid value for enum {!r}" + raise SerializationError(error.format(attr, enum_obj)) from exc + + @staticmethod + def serialize_bytearray(attr, **kwargs): # pylint: disable=unused-argument + """Serialize bytearray into base-64 string. + + :param str attr: Object to be serialized. + :rtype: str + :return: serialized base64 + """ + return b64encode(attr).decode() + + @staticmethod + def serialize_base64(attr, **kwargs): # pylint: disable=unused-argument + """Serialize str into base-64 string. + + :param str attr: Object to be serialized. + :rtype: str + :return: serialized base64 + """ + encoded = b64encode(attr).decode("ascii") + return encoded.strip("=").replace("+", "-").replace("/", "_") + + @staticmethod + def serialize_decimal(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Decimal object to float. + + :param decimal attr: Object to be serialized. + :rtype: float + :return: serialized decimal + """ + return float(attr) + + @staticmethod + def serialize_long(attr, **kwargs): # pylint: disable=unused-argument + """Serialize long (Py2) or int (Py3). + + :param int attr: Object to be serialized. + :rtype: int/long + :return: serialized long + """ + return _long_type(attr) + + @staticmethod + def serialize_date(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Date object into ISO-8601 formatted string. + + :param Date attr: Object to be serialized. + :rtype: str + :return: serialized date + """ + if isinstance(attr, str): + attr = isodate.parse_date(attr) + t = "{:04}-{:02}-{:02}".format(attr.year, attr.month, attr.day) + return t + + @staticmethod + def serialize_time(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Time object into ISO-8601 formatted string. + + :param datetime.time attr: Object to be serialized. + :rtype: str + :return: serialized time + """ + if isinstance(attr, str): + attr = isodate.parse_time(attr) + t = "{:02}:{:02}:{:02}".format(attr.hour, attr.minute, attr.second) + if attr.microsecond: + t += ".{:02}".format(attr.microsecond) + return t + + @staticmethod + def serialize_duration(attr, **kwargs): # pylint: disable=unused-argument + """Serialize TimeDelta object into ISO-8601 formatted string. + + :param TimeDelta attr: Object to be serialized. + :rtype: str + :return: serialized duration + """ + if isinstance(attr, str): + attr = isodate.parse_duration(attr) + return isodate.duration_isoformat(attr) + + @staticmethod + def serialize_rfc(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Datetime object into RFC-1123 formatted string. + + :param Datetime attr: Object to be serialized. + :rtype: str + :raises TypeError: if format invalid. + :return: serialized rfc + """ + try: + if not attr.tzinfo: + _LOGGER.warning("Datetime with no tzinfo will be considered UTC.") + utc = attr.utctimetuple() + except AttributeError as exc: + raise TypeError("RFC1123 object must be valid Datetime object.") from exc + + return "{}, {:02} {} {:04} {:02}:{:02}:{:02} GMT".format( + Serializer.days[utc.tm_wday], + utc.tm_mday, + Serializer.months[utc.tm_mon], + utc.tm_year, + utc.tm_hour, + utc.tm_min, + utc.tm_sec, + ) + + @staticmethod + def serialize_iso(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Datetime object into ISO-8601 formatted string. + + :param Datetime attr: Object to be serialized. + :rtype: str + :raises SerializationError: if format invalid. + :return: serialized iso + """ + if isinstance(attr, str): + attr = isodate.parse_datetime(attr) + try: + if not attr.tzinfo: + _LOGGER.warning("Datetime with no tzinfo will be considered UTC.") + utc = attr.utctimetuple() + if utc.tm_year > 9999 or utc.tm_year < 1: + raise OverflowError("Hit max or min date") + + microseconds = str(attr.microsecond).rjust(6, "0").rstrip("0").ljust(3, "0") + if microseconds: + microseconds = "." + microseconds + date = "{:04}-{:02}-{:02}T{:02}:{:02}:{:02}".format( + utc.tm_year, utc.tm_mon, utc.tm_mday, utc.tm_hour, utc.tm_min, utc.tm_sec + ) + return date + microseconds + "Z" + except (ValueError, OverflowError) as err: + msg = "Unable to serialize datetime object." + raise SerializationError(msg) from err + except AttributeError as err: + msg = "ISO-8601 object must be valid Datetime object." + raise TypeError(msg) from err + + @staticmethod + def serialize_unix(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Datetime object into IntTime format. + This is represented as seconds. + + :param Datetime attr: Object to be serialized. + :rtype: int + :raises SerializationError: if format invalid + :return: serialied unix + """ + if isinstance(attr, int): + return attr + try: + if not attr.tzinfo: + _LOGGER.warning("Datetime with no tzinfo will be considered UTC.") + return int(calendar.timegm(attr.utctimetuple())) + except AttributeError as exc: + raise TypeError("Unix time object must be valid Datetime object.") from exc + + +def rest_key_extractor(attr, attr_desc, data): # pylint: disable=unused-argument + key = attr_desc["key"] + working_data = data + + while "." in key: + # Need the cast, as for some reasons "split" is typed as list[str | Any] + dict_keys = cast(List[str], _FLATTEN.split(key)) + if len(dict_keys) == 1: + key = _decode_attribute_map_key(dict_keys[0]) + break + working_key = _decode_attribute_map_key(dict_keys[0]) + working_data = working_data.get(working_key, data) + if working_data is None: + # If at any point while following flatten JSON path see None, it means + # that all properties under are None as well + return None + key = ".".join(dict_keys[1:]) + + return working_data.get(key) + + +def rest_key_case_insensitive_extractor( # pylint: disable=unused-argument, inconsistent-return-statements + attr, attr_desc, data +): + key = attr_desc["key"] + working_data = data + + while "." in key: + dict_keys = _FLATTEN.split(key) + if len(dict_keys) == 1: + key = _decode_attribute_map_key(dict_keys[0]) + break + working_key = _decode_attribute_map_key(dict_keys[0]) + working_data = attribute_key_case_insensitive_extractor(working_key, None, working_data) + if working_data is None: + # If at any point while following flatten JSON path see None, it means + # that all properties under are None as well + return None + key = ".".join(dict_keys[1:]) + + if working_data: + return attribute_key_case_insensitive_extractor(key, None, working_data) + + +def last_rest_key_extractor(attr, attr_desc, data): # pylint: disable=unused-argument + """Extract the attribute in "data" based on the last part of the JSON path key. + + :param str attr: The attribute to extract + :param dict attr_desc: The attribute description + :param dict data: The data to extract from + :rtype: object + :returns: The extracted attribute + """ + key = attr_desc["key"] + dict_keys = _FLATTEN.split(key) + return attribute_key_extractor(dict_keys[-1], None, data) + + +def last_rest_key_case_insensitive_extractor(attr, attr_desc, data): # pylint: disable=unused-argument + """Extract the attribute in "data" based on the last part of the JSON path key. + + This is the case insensitive version of "last_rest_key_extractor" + :param str attr: The attribute to extract + :param dict attr_desc: The attribute description + :param dict data: The data to extract from + :rtype: object + :returns: The extracted attribute + """ + key = attr_desc["key"] + dict_keys = _FLATTEN.split(key) + return attribute_key_case_insensitive_extractor(dict_keys[-1], None, data) + + +def attribute_key_extractor(attr, _, data): + return data.get(attr) + + +def attribute_key_case_insensitive_extractor(attr, _, data): + found_key = None + lower_attr = attr.lower() + for key in data: + if lower_attr == key.lower(): + found_key = key + break + + return data.get(found_key) + + +def _extract_name_from_internal_type(internal_type): + """Given an internal type XML description, extract correct XML name with namespace. + + :param dict internal_type: An model type + :rtype: tuple + :returns: A tuple XML name + namespace dict + """ + internal_type_xml_map = getattr(internal_type, "_xml_map", {}) + xml_name = internal_type_xml_map.get("name", internal_type.__name__) + xml_ns = internal_type_xml_map.get("ns", None) + if xml_ns: + xml_name = "{{{}}}{}".format(xml_ns, xml_name) + return xml_name + + +def xml_key_extractor(attr, attr_desc, data): # pylint: disable=unused-argument,too-many-return-statements + if isinstance(data, dict): + return None + + # Test if this model is XML ready first + if not isinstance(data, ET.Element): + return None + + xml_desc = attr_desc.get("xml", {}) + xml_name = xml_desc.get("name", attr_desc["key"]) + + # Look for a children + is_iter_type = attr_desc["type"].startswith("[") + is_wrapped = xml_desc.get("wrapped", False) + internal_type = attr_desc.get("internalType", None) + internal_type_xml_map = getattr(internal_type, "_xml_map", {}) + + # Integrate namespace if necessary + xml_ns = xml_desc.get("ns", internal_type_xml_map.get("ns", None)) + if xml_ns: + xml_name = "{{{}}}{}".format(xml_ns, xml_name) + + # If it's an attribute, that's simple + if xml_desc.get("attr", False): + return data.get(xml_name) + + # If it's x-ms-text, that's simple too + if xml_desc.get("text", False): + return data.text + + # Scenario where I take the local name: + # - Wrapped node + # - Internal type is an enum (considered basic types) + # - Internal type has no XML/Name node + if is_wrapped or (internal_type and (issubclass(internal_type, Enum) or "name" not in internal_type_xml_map)): + children = data.findall(xml_name) + # If internal type has a local name and it's not a list, I use that name + elif not is_iter_type and internal_type and "name" in internal_type_xml_map: + xml_name = _extract_name_from_internal_type(internal_type) + children = data.findall(xml_name) + # That's an array + else: + if internal_type: # Complex type, ignore itemsName and use the complex type name + items_name = _extract_name_from_internal_type(internal_type) + else: + items_name = xml_desc.get("itemsName", xml_name) + children = data.findall(items_name) + + if len(children) == 0: + if is_iter_type: + if is_wrapped: + return None # is_wrapped no node, we want None + return [] # not wrapped, assume empty list + return None # Assume it's not there, maybe an optional node. + + # If is_iter_type and not wrapped, return all found children + if is_iter_type: + if not is_wrapped: + return children + # Iter and wrapped, should have found one node only (the wrap one) + if len(children) != 1: + raise DeserializationError( + "Tried to deserialize an array not wrapped, and found several nodes '{}'. Maybe you should declare this array as wrapped?".format( + xml_name + ) + ) + return list(children[0]) # Might be empty list and that's ok. + + # Here it's not a itertype, we should have found one element only or empty + if len(children) > 1: + raise DeserializationError("Find several XML '{}' where it was not expected".format(xml_name)) + return children[0] + + +class Deserializer: + """Response object model deserializer. + + :param dict classes: Class type dictionary for deserializing complex types. + :ivar list key_extractors: Ordered list of extractors to be used by this deserializer. + """ + + basic_types = {str: "str", int: "int", bool: "bool", float: "float"} + + valid_date = re.compile(r"\d{4}[-]\d{2}[-]\d{2}T\d{2}:\d{2}:\d{2}\.?\d*Z?[-+]?[\d{2}]?:?[\d{2}]?") + + def __init__(self, classes: Optional[Mapping[str, type]] = None) -> None: + self.deserialize_type = { + "iso-8601": Deserializer.deserialize_iso, + "rfc-1123": Deserializer.deserialize_rfc, + "unix-time": Deserializer.deserialize_unix, + "duration": Deserializer.deserialize_duration, + "date": Deserializer.deserialize_date, + "time": Deserializer.deserialize_time, + "decimal": Deserializer.deserialize_decimal, + "long": Deserializer.deserialize_long, + "bytearray": Deserializer.deserialize_bytearray, + "base64": Deserializer.deserialize_base64, + "object": self.deserialize_object, + "[]": self.deserialize_iter, + "{}": self.deserialize_dict, + } + self.deserialize_expected_types = { + "duration": (isodate.Duration, datetime.timedelta), + "iso-8601": (datetime.datetime), + } + self.dependencies: Dict[str, type] = dict(classes) if classes else {} + self.key_extractors = [rest_key_extractor, xml_key_extractor] + # Additional properties only works if the "rest_key_extractor" is used to + # extract the keys. Making it to work whatever the key extractor is too much + # complicated, with no real scenario for now. + # So adding a flag to disable additional properties detection. This flag should be + # used if your expect the deserialization to NOT come from a JSON REST syntax. + # Otherwise, result are unexpected + self.additional_properties_detection = True + + def __call__(self, target_obj, response_data, content_type=None): + """Call the deserializer to process a REST response. + + :param str target_obj: Target data type to deserialize to. + :param requests.Response response_data: REST response object. + :param str content_type: Swagger "produces" if available. + :raises DeserializationError: if deserialization fails. + :return: Deserialized object. + :rtype: object + """ + data = self._unpack_content(response_data, content_type) + return self._deserialize(target_obj, data) + + def _deserialize(self, target_obj, data): # pylint: disable=inconsistent-return-statements + """Call the deserializer on a model. + + Data needs to be already deserialized as JSON or XML ElementTree + + :param str target_obj: Target data type to deserialize to. + :param object data: Object to deserialize. + :raises DeserializationError: if deserialization fails. + :return: Deserialized object. + :rtype: object + """ + # This is already a model, go recursive just in case + if hasattr(data, "_attribute_map"): + constants = [name for name, config in getattr(data, "_validation", {}).items() if config.get("constant")] + try: + for attr, mapconfig in data._attribute_map.items(): # pylint: disable=protected-access + if attr in constants: + continue + value = getattr(data, attr) + if value is None: + continue + local_type = mapconfig["type"] + internal_data_type = local_type.strip("[]{}") + if internal_data_type not in self.dependencies or isinstance(internal_data_type, Enum): + continue + setattr(data, attr, self._deserialize(local_type, value)) + return data + except AttributeError: + return + + response, class_name = self._classify_target(target_obj, data) + + if isinstance(response, str): + return self.deserialize_data(data, response) + if isinstance(response, type) and issubclass(response, Enum): + return self.deserialize_enum(data, response) + + if data is None or data is CoreNull: + return data + try: + attributes = response._attribute_map # type: ignore # pylint: disable=protected-access + d_attrs = {} + for attr, attr_desc in attributes.items(): + # Check empty string. If it's not empty, someone has a real "additionalProperties"... + if attr == "additional_properties" and attr_desc["key"] == "": + continue + raw_value = None + # Enhance attr_desc with some dynamic data + attr_desc = attr_desc.copy() # Do a copy, do not change the real one + internal_data_type = attr_desc["type"].strip("[]{}") + if internal_data_type in self.dependencies: + attr_desc["internalType"] = self.dependencies[internal_data_type] + + for key_extractor in self.key_extractors: + found_value = key_extractor(attr, attr_desc, data) + if found_value is not None: + if raw_value is not None and raw_value != found_value: + msg = ( + "Ignoring extracted value '%s' from %s for key '%s'" + " (duplicate extraction, follow extractors order)" + ) + _LOGGER.warning(msg, found_value, key_extractor, attr) + continue + raw_value = found_value + + value = self.deserialize_data(raw_value, attr_desc["type"]) + d_attrs[attr] = value + except (AttributeError, TypeError, KeyError) as err: + msg = "Unable to deserialize to object: " + class_name # type: ignore + raise DeserializationError(msg) from err + additional_properties = self._build_additional_properties(attributes, data) + return self._instantiate_model(response, d_attrs, additional_properties) + + def _build_additional_properties(self, attribute_map, data): + if not self.additional_properties_detection: + return None + if "additional_properties" in attribute_map and attribute_map.get("additional_properties", {}).get("key") != "": + # Check empty string. If it's not empty, someone has a real "additionalProperties" + return None + if isinstance(data, ET.Element): + data = {el.tag: el.text for el in data} + + known_keys = { + _decode_attribute_map_key(_FLATTEN.split(desc["key"])[0]) + for desc in attribute_map.values() + if desc["key"] != "" + } + present_keys = set(data.keys()) + missing_keys = present_keys - known_keys + return {key: data[key] for key in missing_keys} + + def _classify_target(self, target, data): + """Check to see whether the deserialization target object can + be classified into a subclass. + Once classification has been determined, initialize object. + + :param str target: The target object type to deserialize to. + :param str/dict data: The response data to deserialize. + :return: The classified target object and its class name. + :rtype: tuple + """ + if target is None: + return None, None + + if isinstance(target, str): + try: + target = self.dependencies[target] + except KeyError: + return target, target + + try: + target = target._classify(data, self.dependencies) # type: ignore # pylint: disable=protected-access + except AttributeError: + pass # Target is not a Model, no classify + return target, target.__class__.__name__ # type: ignore + + def failsafe_deserialize(self, target_obj, data, content_type=None): + """Ignores any errors encountered in deserialization, + and falls back to not deserializing the object. Recommended + for use in error deserialization, as we want to return the + HttpResponseError to users, and not have them deal with + a deserialization error. + + :param str target_obj: The target object type to deserialize to. + :param str/dict data: The response data to deserialize. + :param str content_type: Swagger "produces" if available. + :return: Deserialized object. + :rtype: object + """ + try: + return self(target_obj, data, content_type=content_type) + except: # pylint: disable=bare-except + _LOGGER.debug( + "Ran into a deserialization error. Ignoring since this is failsafe deserialization", exc_info=True + ) + return None + + @staticmethod + def _unpack_content(raw_data, content_type=None): + """Extract the correct structure for deserialization. + + If raw_data is a PipelineResponse, try to extract the result of RawDeserializer. + if we can't, raise. Your Pipeline should have a RawDeserializer. + + If not a pipeline response and raw_data is bytes or string, use content-type + to decode it. If no content-type, try JSON. + + If raw_data is something else, bypass all logic and return it directly. + + :param obj raw_data: Data to be processed. + :param str content_type: How to parse if raw_data is a string/bytes. + :raises JSONDecodeError: If JSON is requested and parsing is impossible. + :raises UnicodeDecodeError: If bytes is not UTF8 + :rtype: object + :return: Unpacked content. + """ + # Assume this is enough to detect a Pipeline Response without importing it + context = getattr(raw_data, "context", {}) + if context: + if RawDeserializer.CONTEXT_NAME in context: + return context[RawDeserializer.CONTEXT_NAME] + raise ValueError("This pipeline didn't have the RawDeserializer policy; can't deserialize") + + # Assume this is enough to recognize universal_http.ClientResponse without importing it + if hasattr(raw_data, "body"): + return RawDeserializer.deserialize_from_http_generics(raw_data.text(), raw_data.headers) + + # Assume this enough to recognize requests.Response without importing it. + if hasattr(raw_data, "_content_consumed"): + return RawDeserializer.deserialize_from_http_generics(raw_data.text, raw_data.headers) + + if isinstance(raw_data, (str, bytes)) or hasattr(raw_data, "read"): + return RawDeserializer.deserialize_from_text(raw_data, content_type) # type: ignore + return raw_data + + def _instantiate_model(self, response, attrs, additional_properties=None): + """Instantiate a response model passing in deserialized args. + + :param Response response: The response model class. + :param dict attrs: The deserialized response attributes. + :param dict additional_properties: Additional properties to be set. + :rtype: Response + :return: The instantiated response model. + """ + if callable(response): + subtype = getattr(response, "_subtype_map", {}) + try: + readonly = [ + k + for k, v in response._validation.items() # pylint: disable=protected-access # type: ignore + if v.get("readonly") + ] + const = [ + k + for k, v in response._validation.items() # pylint: disable=protected-access # type: ignore + if v.get("constant") + ] + kwargs = {k: v for k, v in attrs.items() if k not in subtype and k not in readonly + const} + response_obj = response(**kwargs) + for attr in readonly: + setattr(response_obj, attr, attrs.get(attr)) + if additional_properties: + response_obj.additional_properties = additional_properties # type: ignore + return response_obj + except TypeError as err: + msg = "Unable to deserialize {} into model {}. ".format(kwargs, response) # type: ignore + raise DeserializationError(msg + str(err)) from err + else: + try: + for attr, value in attrs.items(): + setattr(response, attr, value) + return response + except Exception as exp: + msg = "Unable to populate response model. " + msg += "Type: {}, Error: {}".format(type(response), exp) + raise DeserializationError(msg) from exp + + def deserialize_data(self, data, data_type): # pylint: disable=too-many-return-statements + """Process data for deserialization according to data type. + + :param str data: The response string to be deserialized. + :param str data_type: The type to deserialize to. + :raises DeserializationError: if deserialization fails. + :return: Deserialized object. + :rtype: object + """ + if data is None: + return data + + try: + if not data_type: + return data + if data_type in self.basic_types.values(): + return self.deserialize_basic(data, data_type) + if data_type in self.deserialize_type: + if isinstance(data, self.deserialize_expected_types.get(data_type, tuple())): + return data + + is_a_text_parsing_type = lambda x: x not in [ # pylint: disable=unnecessary-lambda-assignment + "object", + "[]", + r"{}", + ] + if isinstance(data, ET.Element) and is_a_text_parsing_type(data_type) and not data.text: + return None + data_val = self.deserialize_type[data_type](data) + return data_val + + iter_type = data_type[0] + data_type[-1] + if iter_type in self.deserialize_type: + return self.deserialize_type[iter_type](data, data_type[1:-1]) + + obj_type = self.dependencies[data_type] + if issubclass(obj_type, Enum): + if isinstance(data, ET.Element): + data = data.text + return self.deserialize_enum(data, obj_type) + + except (ValueError, TypeError, AttributeError) as err: + msg = "Unable to deserialize response data." + msg += " Data: {}, {}".format(data, data_type) + raise DeserializationError(msg) from err + return self._deserialize(obj_type, data) + + def deserialize_iter(self, attr, iter_type): + """Deserialize an iterable. + + :param list attr: Iterable to be deserialized. + :param str iter_type: The type of object in the iterable. + :return: Deserialized iterable. + :rtype: list + """ + if attr is None: + return None + if isinstance(attr, ET.Element): # If I receive an element here, get the children + attr = list(attr) + if not isinstance(attr, (list, set)): + raise DeserializationError("Cannot deserialize as [{}] an object of type {}".format(iter_type, type(attr))) + return [self.deserialize_data(a, iter_type) for a in attr] + + def deserialize_dict(self, attr, dict_type): + """Deserialize a dictionary. + + :param dict/list attr: Dictionary to be deserialized. Also accepts + a list of key, value pairs. + :param str dict_type: The object type of the items in the dictionary. + :return: Deserialized dictionary. + :rtype: dict + """ + if isinstance(attr, list): + return {x["key"]: self.deserialize_data(x["value"], dict_type) for x in attr} + + if isinstance(attr, ET.Element): + # Transform value into {"Key": "value"} + attr = {el.tag: el.text for el in attr} + return {k: self.deserialize_data(v, dict_type) for k, v in attr.items()} + + def deserialize_object(self, attr, **kwargs): # pylint: disable=too-many-return-statements + """Deserialize a generic object. + This will be handled as a dictionary. + + :param dict attr: Dictionary to be deserialized. + :return: Deserialized object. + :rtype: dict + :raises TypeError: if non-builtin datatype encountered. + """ + if attr is None: + return None + if isinstance(attr, ET.Element): + # Do no recurse on XML, just return the tree as-is + return attr + if isinstance(attr, str): + return self.deserialize_basic(attr, "str") + obj_type = type(attr) + if obj_type in self.basic_types: + return self.deserialize_basic(attr, self.basic_types[obj_type]) + if obj_type is _long_type: + return self.deserialize_long(attr) + + if obj_type == dict: + deserialized = {} + for key, value in attr.items(): + try: + deserialized[key] = self.deserialize_object(value, **kwargs) + except ValueError: + deserialized[key] = None + return deserialized + + if obj_type == list: + deserialized = [] + for obj in attr: + try: + deserialized.append(self.deserialize_object(obj, **kwargs)) + except ValueError: + pass + return deserialized + + error = "Cannot deserialize generic object with type: " + raise TypeError(error + str(obj_type)) + + def deserialize_basic(self, attr, data_type): # pylint: disable=too-many-return-statements + """Deserialize basic builtin data type from string. + Will attempt to convert to str, int, float and bool. + This function will also accept '1', '0', 'true' and 'false' as + valid bool values. + + :param str attr: response string to be deserialized. + :param str data_type: deserialization data type. + :return: Deserialized basic type. + :rtype: str, int, float or bool + :raises TypeError: if string format is not valid. + """ + # If we're here, data is supposed to be a basic type. + # If it's still an XML node, take the text + if isinstance(attr, ET.Element): + attr = attr.text + if not attr: + if data_type == "str": + # None or '', node is empty string. + return "" + # None or '', node with a strong type is None. + # Don't try to model "empty bool" or "empty int" + return None + + if data_type == "bool": + if attr in [True, False, 1, 0]: + return bool(attr) + if isinstance(attr, str): + if attr.lower() in ["true", "1"]: + return True + if attr.lower() in ["false", "0"]: + return False + raise TypeError("Invalid boolean value: {}".format(attr)) + + if data_type == "str": + return self.deserialize_unicode(attr) + return eval(data_type)(attr) # nosec # pylint: disable=eval-used + + @staticmethod + def deserialize_unicode(data): + """Preserve unicode objects in Python 2, otherwise return data + as a string. + + :param str data: response string to be deserialized. + :return: Deserialized string. + :rtype: str or unicode + """ + # We might be here because we have an enum modeled as string, + # and we try to deserialize a partial dict with enum inside + if isinstance(data, Enum): + return data + + # Consider this is real string + try: + if isinstance(data, unicode): # type: ignore + return data + except NameError: + return str(data) + return str(data) + + @staticmethod + def deserialize_enum(data, enum_obj): + """Deserialize string into enum object. + + If the string is not a valid enum value it will be returned as-is + and a warning will be logged. + + :param str data: Response string to be deserialized. If this value is + None or invalid it will be returned as-is. + :param Enum enum_obj: Enum object to deserialize to. + :return: Deserialized enum object. + :rtype: Enum + """ + if isinstance(data, enum_obj) or data is None: + return data + if isinstance(data, Enum): + data = data.value + if isinstance(data, int): + # Workaround. We might consider remove it in the future. + try: + return list(enum_obj.__members__.values())[data] + except IndexError as exc: + error = "{!r} is not a valid index for enum {!r}" + raise DeserializationError(error.format(data, enum_obj)) from exc + try: + return enum_obj(str(data)) + except ValueError: + for enum_value in enum_obj: + if enum_value.value.lower() == str(data).lower(): + return enum_value + # We don't fail anymore for unknown value, we deserialize as a string + _LOGGER.warning("Deserializer is not able to find %s as valid enum in %s", data, enum_obj) + return Deserializer.deserialize_unicode(data) + + @staticmethod + def deserialize_bytearray(attr): + """Deserialize string into bytearray. + + :param str attr: response string to be deserialized. + :return: Deserialized bytearray + :rtype: bytearray + :raises TypeError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + return bytearray(b64decode(attr)) # type: ignore + + @staticmethod + def deserialize_base64(attr): + """Deserialize base64 encoded string into string. + + :param str attr: response string to be deserialized. + :return: Deserialized base64 string + :rtype: bytearray + :raises TypeError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + padding = "=" * (3 - (len(attr) + 3) % 4) # type: ignore + attr = attr + padding # type: ignore + encoded = attr.replace("-", "+").replace("_", "/") + return b64decode(encoded) + + @staticmethod + def deserialize_decimal(attr): + """Deserialize string into Decimal object. + + :param str attr: response string to be deserialized. + :return: Deserialized decimal + :raises DeserializationError: if string format invalid. + :rtype: decimal + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + return decimal.Decimal(str(attr)) # type: ignore + except decimal.DecimalException as err: + msg = "Invalid decimal {}".format(attr) + raise DeserializationError(msg) from err + + @staticmethod + def deserialize_long(attr): + """Deserialize string into long (Py2) or int (Py3). + + :param str attr: response string to be deserialized. + :return: Deserialized int + :rtype: long or int + :raises ValueError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + return _long_type(attr) # type: ignore + + @staticmethod + def deserialize_duration(attr): + """Deserialize ISO-8601 formatted string into TimeDelta object. + + :param str attr: response string to be deserialized. + :return: Deserialized duration + :rtype: TimeDelta + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + duration = isodate.parse_duration(attr) + except (ValueError, OverflowError, AttributeError) as err: + msg = "Cannot deserialize duration object." + raise DeserializationError(msg) from err + return duration + + @staticmethod + def deserialize_date(attr): + """Deserialize ISO-8601 formatted string into Date object. + + :param str attr: response string to be deserialized. + :return: Deserialized date + :rtype: Date + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + if re.search(r"[^\W\d_]", attr, re.I + re.U): # type: ignore + raise DeserializationError("Date must have only digits and -. Received: %s" % attr) + # This must NOT use defaultmonth/defaultday. Using None ensure this raises an exception. + return isodate.parse_date(attr, defaultmonth=0, defaultday=0) + + @staticmethod + def deserialize_time(attr): + """Deserialize ISO-8601 formatted string into time object. + + :param str attr: response string to be deserialized. + :return: Deserialized time + :rtype: datetime.time + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + if re.search(r"[^\W\d_]", attr, re.I + re.U): # type: ignore + raise DeserializationError("Date must have only digits and -. Received: %s" % attr) + return isodate.parse_time(attr) + + @staticmethod + def deserialize_rfc(attr): + """Deserialize RFC-1123 formatted string into Datetime object. + + :param str attr: response string to be deserialized. + :return: Deserialized RFC datetime + :rtype: Datetime + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + parsed_date = email.utils.parsedate_tz(attr) # type: ignore + date_obj = datetime.datetime( + *parsed_date[:6], tzinfo=datetime.timezone(datetime.timedelta(minutes=(parsed_date[9] or 0) / 60)) + ) + if not date_obj.tzinfo: + date_obj = date_obj.astimezone(tz=TZ_UTC) + except ValueError as err: + msg = "Cannot deserialize to rfc datetime object." + raise DeserializationError(msg) from err + return date_obj + + @staticmethod + def deserialize_iso(attr): + """Deserialize ISO-8601 formatted string into Datetime object. + + :param str attr: response string to be deserialized. + :return: Deserialized ISO datetime + :rtype: Datetime + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + attr = attr.upper() # type: ignore + match = Deserializer.valid_date.match(attr) + if not match: + raise ValueError("Invalid datetime string: " + attr) + + check_decimal = attr.split(".") + if len(check_decimal) > 1: + decimal_str = "" + for digit in check_decimal[1]: + if digit.isdigit(): + decimal_str += digit + else: + break + if len(decimal_str) > 6: + attr = attr.replace(decimal_str, decimal_str[0:6]) + + date_obj = isodate.parse_datetime(attr) + test_utc = date_obj.utctimetuple() + if test_utc.tm_year > 9999 or test_utc.tm_year < 1: + raise OverflowError("Hit max or min date") + except (ValueError, OverflowError, AttributeError) as err: + msg = "Cannot deserialize datetime object." + raise DeserializationError(msg) from err + return date_obj + + @staticmethod + def deserialize_unix(attr): + """Serialize Datetime object into IntTime format. + This is represented as seconds. + + :param int attr: Object to be serialized. + :return: Deserialized datetime + :rtype: Datetime + :raises DeserializationError: if format invalid + """ + if isinstance(attr, ET.Element): + attr = int(attr.text) # type: ignore + try: + attr = int(attr) + date_obj = datetime.datetime.fromtimestamp(attr, TZ_UTC) + except ValueError as err: + msg = "Cannot deserialize to unix datetime object." + raise DeserializationError(msg) from err + return date_obj diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiSecurity/multiapisecurity/aio/_multiapi_service_client.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiSecurity/multiapisecurity/aio/_multiapi_service_client.py index 681cdbfb1ea..bea59b1ae0d 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiSecurity/multiapisecurity/aio/_multiapi_service_client.py +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiSecurity/multiapisecurity/aio/_multiapi_service_client.py @@ -17,7 +17,7 @@ from azure.profiles import KnownProfiles, ProfileDefinition from azure.profiles.multiapiclient import MultiApiClientMixin -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import MultiapiServiceClientConfiguration from ._operations_mixin import MultiapiServiceClientOperationsMixin diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiSecurity/multiapisecurity/aio/_operations_mixin.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiSecurity/multiapisecurity/aio/_operations_mixin.py index f33111ee65c..cb351a3528c 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiSecurity/multiapisecurity/aio/_operations_mixin.py +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiSecurity/multiapisecurity/aio/_operations_mixin.py @@ -8,7 +8,7 @@ # Changes may cause incorrect behavior and will be lost if the code is # regenerated. # -------------------------------------------------------------------------- -from .._serialization import Serializer, Deserializer +from .._utils.serialization import Serializer, Deserializer from io import IOBase from typing import Any, AsyncIterable, AsyncIterator, IO, Optional, Union diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiSecurity/multiapisecurity/v0/_metadata.json b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiSecurity/multiapisecurity/v0/_metadata.json index e0d72c70a45..0ea30416781 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiSecurity/multiapisecurity/v0/_metadata.json +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiSecurity/multiapisecurity/v0/_metadata.json @@ -10,8 +10,8 @@ "azure_arm": false, "has_public_lro_operations": false, "client_side_validation": false, - "sync_imports": "{\"conditional\": {\"stdlib\": {\"typing\": [\"Any\", \"Optional\"]}}, \"regular\": {\"sdkcore\": {\"azure.core\": [\"PipelineClient\"], \"azure.core.pipeline\": [\"policies\"], \"azure.profiles\": [\"KnownProfiles\", \"ProfileDefinition\"], \"azure.profiles.multiapiclient\": [\"MultiApiClientMixin\"]}, \"local\": {\"._configuration\": [\"MultiapiServiceClientConfiguration\"], \".._serialization\": [\"Deserializer\", \"Serializer\"]}, \"stdlib\": {\"typing_extensions\": [\"Self\"]}}, \"typing\": {\"sdkcore\": {\"azure.core.credentials\": [\"TokenCredential\"]}}}", - "async_imports": "{\"conditional\": {\"stdlib\": {\"typing\": [\"Any\", \"Optional\"]}}, \"regular\": {\"sdkcore\": {\"azure.core\": [\"AsyncPipelineClient\"], \"azure.core.pipeline\": [\"policies\"], \"azure.profiles\": [\"KnownProfiles\", \"ProfileDefinition\"], \"azure.profiles.multiapiclient\": [\"MultiApiClientMixin\"]}, \"local\": {\"._configuration\": [\"MultiapiServiceClientConfiguration\"], \"..._serialization\": [\"Deserializer\", \"Serializer\"]}, \"stdlib\": {\"typing_extensions\": [\"Self\"]}}, \"typing\": {\"sdkcore\": {\"azure.core.credentials_async\": [\"AsyncTokenCredential\"]}}}" + "sync_imports": "{\"conditional\": {\"stdlib\": {\"typing\": [\"Any\", \"Optional\"]}}, \"regular\": {\"sdkcore\": {\"azure.core\": [\"PipelineClient\"], \"azure.core.pipeline\": [\"policies\"], \"azure.profiles\": [\"KnownProfiles\", \"ProfileDefinition\"], \"azure.profiles.multiapiclient\": [\"MultiApiClientMixin\"]}, \"local\": {\"._configuration\": [\"MultiapiServiceClientConfiguration\"], \"._utils.serialization\": [\"Deserializer\", \"Serializer\"]}, \"stdlib\": {\"typing_extensions\": [\"Self\"]}}, \"typing\": {\"sdkcore\": {\"azure.core.credentials\": [\"TokenCredential\"]}}}", + "async_imports": "{\"conditional\": {\"stdlib\": {\"typing\": [\"Any\", \"Optional\"]}}, \"regular\": {\"sdkcore\": {\"azure.core\": [\"AsyncPipelineClient\"], \"azure.core.pipeline\": [\"policies\"], \"azure.profiles\": [\"KnownProfiles\", \"ProfileDefinition\"], \"azure.profiles.multiapiclient\": [\"MultiApiClientMixin\"]}, \"local\": {\"._configuration\": [\"MultiapiServiceClientConfiguration\"], \".._utils.serialization\": [\"Deserializer\", \"Serializer\"]}, \"stdlib\": {\"typing_extensions\": [\"Self\"]}}, \"typing\": {\"sdkcore\": {\"azure.core.credentials_async\": [\"AsyncTokenCredential\"]}}}" }, "global_parameters": { "sync": { diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiSecurity/multiapisecurity/v0/_multiapi_service_client.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiSecurity/multiapisecurity/v0/_multiapi_service_client.py index a837213c499..9e7c6e778dd 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiSecurity/multiapisecurity/v0/_multiapi_service_client.py +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiSecurity/multiapisecurity/v0/_multiapi_service_client.py @@ -15,8 +15,8 @@ from azure.core.rest import HttpRequest, HttpResponse from . import models as _models -from .._serialization import Deserializer, Serializer from ._configuration import MultiapiServiceClientConfiguration +from ._utils.serialization import Deserializer, Serializer from .operations import OperationGroupOneOperations if TYPE_CHECKING: diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiSecurity/multiapisecurity/v0/_utils/__init__.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiSecurity/multiapisecurity/v0/_utils/__init__.py new file mode 100644 index 00000000000..0af9b28f660 --- /dev/null +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiSecurity/multiapisecurity/v0/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/MultipleInheritance/multipleinheritance/_serialization.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiSecurity/multiapisecurity/v0/_utils/serialization.py similarity index 100% rename from packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/MultipleInheritance/multipleinheritance/_serialization.py rename to packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiSecurity/multiapisecurity/v0/_utils/serialization.py diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiSecurity/multiapisecurity/v0/aio/_multiapi_service_client.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiSecurity/multiapisecurity/v0/aio/_multiapi_service_client.py index a7e33edcc2b..b811a2145ef 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiSecurity/multiapisecurity/v0/aio/_multiapi_service_client.py +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiSecurity/multiapisecurity/v0/aio/_multiapi_service_client.py @@ -15,7 +15,7 @@ from azure.core.rest import AsyncHttpResponse, HttpRequest from .. import models as _models -from ..._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import MultiapiServiceClientConfiguration from .operations import OperationGroupOneOperations diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiSecurity/multiapisecurity/v0/aio/operations/_operation_group_one_operations.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiSecurity/multiapisecurity/v0/aio/operations/_operation_group_one_operations.py index 9e7b4189565..63dce16d4c6 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiSecurity/multiapisecurity/v0/aio/operations/_operation_group_one_operations.py +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiSecurity/multiapisecurity/v0/aio/operations/_operation_group_one_operations.py @@ -23,7 +23,7 @@ from azure.core.utils import case_insensitive_dict from ... import models as _models -from ...._serialization import Deserializer, Serializer +from ..._utils.serialization import Deserializer, Serializer from ...operations._operation_group_one_operations import build_test_two_request from .._configuration import MultiapiServiceClientConfiguration diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiSecurity/multiapisecurity/v0/models/_models_py3.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiSecurity/multiapisecurity/v0/models/_models_py3.py index 9797a5a8c77..8a0e693958a 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiSecurity/multiapisecurity/v0/models/_models_py3.py +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiSecurity/multiapisecurity/v0/models/_models_py3.py @@ -8,7 +8,7 @@ from typing import Any, List, Optional, TYPE_CHECKING -from ... import _serialization +from .._utils import serialization as _serialization if TYPE_CHECKING: from .. import models as _models diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiSecurity/multiapisecurity/v0/operations/_operation_group_one_operations.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiSecurity/multiapisecurity/v0/operations/_operation_group_one_operations.py index 577d0ecca2d..f6bc2d19e28 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiSecurity/multiapisecurity/v0/operations/_operation_group_one_operations.py +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiSecurity/multiapisecurity/v0/operations/_operation_group_one_operations.py @@ -23,8 +23,8 @@ from azure.core.utils import case_insensitive_dict from .. import models as _models -from ..._serialization import Deserializer, Serializer from .._configuration import MultiapiServiceClientConfiguration +from .._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiSecurity/multiapisecurity/v1/_metadata.json b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiSecurity/multiapisecurity/v1/_metadata.json index 8298a83ebdc..991cb55d231 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiSecurity/multiapisecurity/v1/_metadata.json +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiSecurity/multiapisecurity/v1/_metadata.json @@ -10,8 +10,8 @@ "azure_arm": false, "has_public_lro_operations": true, "client_side_validation": false, - "sync_imports": "{\"conditional\": {\"stdlib\": {\"typing\": [\"Any\", \"Optional\"]}}, \"regular\": {\"sdkcore\": {\"azure.core\": [\"PipelineClient\"], \"azure.core.pipeline\": [\"policies\"], \"azure.profiles\": [\"KnownProfiles\", \"ProfileDefinition\"], \"azure.profiles.multiapiclient\": [\"MultiApiClientMixin\"]}, \"local\": {\"._configuration\": [\"MultiapiServiceClientConfiguration\"], \".._serialization\": [\"Deserializer\", \"Serializer\"], \"._operations_mixin\": [\"MultiapiServiceClientOperationsMixin\"]}, \"stdlib\": {\"typing_extensions\": [\"Self\"]}}, \"typing\": {\"sdkcore\": {\"azure.core.credentials\": [\"TokenCredential\"]}}}", - "async_imports": "{\"conditional\": {\"stdlib\": {\"typing\": [\"Any\", \"Optional\"]}}, \"regular\": {\"sdkcore\": {\"azure.core\": [\"AsyncPipelineClient\"], \"azure.core.pipeline\": [\"policies\"], \"azure.profiles\": [\"KnownProfiles\", \"ProfileDefinition\"], \"azure.profiles.multiapiclient\": [\"MultiApiClientMixin\"]}, \"local\": {\"._configuration\": [\"MultiapiServiceClientConfiguration\"], \"..._serialization\": [\"Deserializer\", \"Serializer\"], \"._operations_mixin\": [\"MultiapiServiceClientOperationsMixin\"]}, \"stdlib\": {\"typing_extensions\": [\"Self\"]}}, \"typing\": {\"sdkcore\": {\"azure.core.credentials_async\": [\"AsyncTokenCredential\"]}}}" + "sync_imports": "{\"conditional\": {\"stdlib\": {\"typing\": [\"Any\", \"Optional\"]}}, \"regular\": {\"sdkcore\": {\"azure.core\": [\"PipelineClient\"], \"azure.core.pipeline\": [\"policies\"], \"azure.profiles\": [\"KnownProfiles\", \"ProfileDefinition\"], \"azure.profiles.multiapiclient\": [\"MultiApiClientMixin\"]}, \"local\": {\"._configuration\": [\"MultiapiServiceClientConfiguration\"], \"._utils.serialization\": [\"Deserializer\", \"Serializer\"], \"._operations_mixin\": [\"MultiapiServiceClientOperationsMixin\"]}, \"stdlib\": {\"typing_extensions\": [\"Self\"]}}, \"typing\": {\"sdkcore\": {\"azure.core.credentials\": [\"TokenCredential\"]}}}", + "async_imports": "{\"conditional\": {\"stdlib\": {\"typing\": [\"Any\", \"Optional\"]}}, \"regular\": {\"sdkcore\": {\"azure.core\": [\"AsyncPipelineClient\"], \"azure.core.pipeline\": [\"policies\"], \"azure.profiles\": [\"KnownProfiles\", \"ProfileDefinition\"], \"azure.profiles.multiapiclient\": [\"MultiApiClientMixin\"]}, \"local\": {\"._configuration\": [\"MultiapiServiceClientConfiguration\"], \".._utils.serialization\": [\"Deserializer\", \"Serializer\"], \"._operations_mixin\": [\"MultiapiServiceClientOperationsMixin\"]}, \"stdlib\": {\"typing_extensions\": [\"Self\"]}}, \"typing\": {\"sdkcore\": {\"azure.core.credentials_async\": [\"AsyncTokenCredential\"]}}}" }, "global_parameters": { "sync": { diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiSecurity/multiapisecurity/v1/_multiapi_service_client.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiSecurity/multiapisecurity/v1/_multiapi_service_client.py index 546a3dd7669..30660c8d715 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiSecurity/multiapisecurity/v1/_multiapi_service_client.py +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiSecurity/multiapisecurity/v1/_multiapi_service_client.py @@ -15,8 +15,8 @@ from azure.core.rest import HttpRequest, HttpResponse from . import models as _models -from .._serialization import Deserializer, Serializer from ._configuration import MultiapiServiceClientConfiguration +from ._utils.serialization import Deserializer, Serializer from .operations import MultiapiServiceClientOperationsMixin, OperationGroupOneOperations if TYPE_CHECKING: diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiSecurity/multiapisecurity/v1/_utils/__init__.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiSecurity/multiapisecurity/v1/_utils/__init__.py new file mode 100644 index 00000000000..0af9b28f660 --- /dev/null +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiSecurity/multiapisecurity/v1/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/NoOperations/nooperations/_serialization.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiSecurity/multiapisecurity/v1/_utils/serialization.py similarity index 100% rename from packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/NoOperations/nooperations/_serialization.py rename to packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiSecurity/multiapisecurity/v1/_utils/serialization.py diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiSecurity/multiapisecurity/v1/_utils/utils.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiSecurity/multiapisecurity/v1/_utils/utils.py new file mode 100644 index 00000000000..39b612f39a9 --- /dev/null +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiSecurity/multiapisecurity/v1/_utils/utils.py @@ -0,0 +1,25 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from abc import ABC +from typing import Generic, TYPE_CHECKING, TypeVar + +if TYPE_CHECKING: + from .serialization import Deserializer, Serializer + + +TClient = TypeVar("TClient") +TConfig = TypeVar("TConfig") + + +class ClientMixinABC(ABC, Generic[TClient, TConfig]): + """DO NOT use this class. It is for internal typing use only.""" + + _client: TClient + _config: TConfig + _serialize: "Serializer" + _deserialize: "Deserializer" diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiSecurity/multiapisecurity/v1/_vendor.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiSecurity/multiapisecurity/v1/_vendor.py deleted file mode 100644 index 70517e0b7af..00000000000 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiSecurity/multiapisecurity/v1/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) AutoRest Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import MultiapiServiceClientConfiguration - -if TYPE_CHECKING: - from azure.core import PipelineClient - - from .._serialization import Deserializer, Serializer - - -class MultiapiServiceClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "PipelineClient" - _config: MultiapiServiceClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiSecurity/multiapisecurity/v1/aio/_multiapi_service_client.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiSecurity/multiapisecurity/v1/aio/_multiapi_service_client.py index 671fe43ce98..be90cd0ad28 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiSecurity/multiapisecurity/v1/aio/_multiapi_service_client.py +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiSecurity/multiapisecurity/v1/aio/_multiapi_service_client.py @@ -15,7 +15,7 @@ from azure.core.rest import AsyncHttpResponse, HttpRequest from .. import models as _models -from ..._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import MultiapiServiceClientConfiguration from .operations import MultiapiServiceClientOperationsMixin, OperationGroupOneOperations diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiSecurity/multiapisecurity/v1/aio/_vendor.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiSecurity/multiapisecurity/v1/aio/_vendor.py deleted file mode 100644 index 9c6fd05bb21..00000000000 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiSecurity/multiapisecurity/v1/aio/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) AutoRest Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import MultiapiServiceClientConfiguration - -if TYPE_CHECKING: - from azure.core import AsyncPipelineClient - - from ..._serialization import Deserializer, Serializer - - -class MultiapiServiceClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "AsyncPipelineClient" - _config: MultiapiServiceClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiSecurity/multiapisecurity/v1/aio/operations/_multiapi_service_client_operations.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiSecurity/multiapisecurity/v1/aio/operations/_multiapi_service_client_operations.py index 11c6819e70d..462aaeedc85 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiSecurity/multiapisecurity/v1/aio/operations/_multiapi_service_client_operations.py +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiSecurity/multiapisecurity/v1/aio/operations/_multiapi_service_client_operations.py @@ -11,6 +11,7 @@ from typing import Any, AsyncIterable, AsyncIterator, Callable, Dict, IO, Optional, TypeVar, Union, cast, overload import urllib.parse +from azure.core import AsyncPipelineClient from azure.core.async_paging import AsyncItemPaged, AsyncList from azure.core.exceptions import ( ClientAuthenticationError, @@ -31,19 +32,20 @@ from azure.core.utils import case_insensitive_dict from ... import models as _models +from ..._utils.utils import ClientMixinABC from ...operations._multiapi_service_client_operations import ( build_test_different_calls_request, build_test_lro_and_paging_request, build_test_lro_request, build_test_one_request, ) -from .._vendor import MultiapiServiceClientMixinABC +from .._configuration import MultiapiServiceClientConfiguration T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, AsyncHttpResponse], T, Dict[str, Any]], Any]] -class MultiapiServiceClientOperationsMixin(MultiapiServiceClientMixinABC): +class MultiapiServiceClientOperationsMixin(ClientMixinABC[AsyncPipelineClient, MultiapiServiceClientConfiguration]): def _api_version(self, op_name: str) -> str: # pylint: disable=unused-argument try: return self._config.api_version diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiSecurity/multiapisecurity/v1/aio/operations/_operation_group_one_operations.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiSecurity/multiapisecurity/v1/aio/operations/_operation_group_one_operations.py index 9ad7ce97e62..fb90a664507 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiSecurity/multiapisecurity/v1/aio/operations/_operation_group_one_operations.py +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiSecurity/multiapisecurity/v1/aio/operations/_operation_group_one_operations.py @@ -23,7 +23,7 @@ from azure.core.utils import case_insensitive_dict from ... import models as _models -from ...._serialization import Deserializer, Serializer +from ..._utils.serialization import Deserializer, Serializer from ...operations._operation_group_one_operations import build_test_two_request from .._configuration import MultiapiServiceClientConfiguration diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiSecurity/multiapisecurity/v1/models/_models_py3.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiSecurity/multiapisecurity/v1/models/_models_py3.py index c9ddcd7fa74..c2e625ad032 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiSecurity/multiapisecurity/v1/models/_models_py3.py +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiSecurity/multiapisecurity/v1/models/_models_py3.py @@ -8,7 +8,7 @@ from typing import Any, List, Optional, TYPE_CHECKING -from ... import _serialization +from .._utils import serialization as _serialization if TYPE_CHECKING: from .. import models as _models diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiSecurity/multiapisecurity/v1/operations/_multiapi_service_client_operations.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiSecurity/multiapisecurity/v1/operations/_multiapi_service_client_operations.py index f2bc0aeba8c..b801749db42 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiSecurity/multiapisecurity/v1/operations/_multiapi_service_client_operations.py +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiSecurity/multiapisecurity/v1/operations/_multiapi_service_client_operations.py @@ -10,6 +10,7 @@ from typing import Any, Callable, Dict, IO, Iterable, Iterator, Optional, TypeVar, Union, cast, overload import urllib.parse +from azure.core import PipelineClient from azure.core.exceptions import ( ClientAuthenticationError, HttpResponseError, @@ -29,8 +30,9 @@ from azure.core.utils import case_insensitive_dict from .. import models as _models -from ..._serialization import Serializer -from .._vendor import MultiapiServiceClientMixinABC +from .._configuration import MultiapiServiceClientConfiguration +from .._utils.serialization import Serializer +from .._utils.utils import ClientMixinABC T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] @@ -120,7 +122,7 @@ def build_test_different_calls_request(*, greeting_in_english: str, **kwargs: An return HttpRequest(method="GET", url=_url, params=_params, headers=_headers, **kwargs) -class MultiapiServiceClientOperationsMixin(MultiapiServiceClientMixinABC): +class MultiapiServiceClientOperationsMixin(ClientMixinABC[PipelineClient, MultiapiServiceClientConfiguration]): def _api_version(self, op_name: str) -> str: # pylint: disable=unused-argument try: return self._config.api_version diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiSecurity/multiapisecurity/v1/operations/_operation_group_one_operations.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiSecurity/multiapisecurity/v1/operations/_operation_group_one_operations.py index 48b86e9927f..42f3785aa20 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiSecurity/multiapisecurity/v1/operations/_operation_group_one_operations.py +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiSecurity/multiapisecurity/v1/operations/_operation_group_one_operations.py @@ -23,8 +23,8 @@ from azure.core.utils import case_insensitive_dict from .. import models as _models -from ..._serialization import Deserializer, Serializer from .._configuration import MultiapiServiceClientConfiguration +from .._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiWithSubmodule/multiapiwithsubmodule/submodule/_multiapi_service_client.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiWithSubmodule/multiapiwithsubmodule/submodule/_multiapi_service_client.py index c5dc63d1028..78dabe92d76 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiWithSubmodule/multiapiwithsubmodule/submodule/_multiapi_service_client.py +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiWithSubmodule/multiapiwithsubmodule/submodule/_multiapi_service_client.py @@ -22,7 +22,7 @@ from ._configuration import MultiapiServiceClientConfiguration from ._operations_mixin import MultiapiServiceClientOperationsMixin -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer if TYPE_CHECKING: # pylint: disable=unused-import,ungrouped-imports diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiWithSubmodule/multiapiwithsubmodule/submodule/_operations_mixin.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiWithSubmodule/multiapiwithsubmodule/submodule/_operations_mixin.py index e80398ecccd..cc6cd7dc361 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiWithSubmodule/multiapiwithsubmodule/submodule/_operations_mixin.py +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiWithSubmodule/multiapiwithsubmodule/submodule/_operations_mixin.py @@ -8,7 +8,7 @@ # Changes may cause incorrect behavior and will be lost if the code is # regenerated. # -------------------------------------------------------------------------- -from ._serialization import Serializer, Deserializer +from ._utils.serialization import Serializer, Deserializer from io import IOBase from typing import Any, IO, Iterable, Iterator, Optional, Union diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiWithSubmodule/multiapiwithsubmodule/submodule/_utils/__init__.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiWithSubmodule/multiapiwithsubmodule/submodule/_utils/__init__.py new file mode 100644 index 00000000000..59333308532 --- /dev/null +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiWithSubmodule/multiapiwithsubmodule/submodule/_utils/__init__.py @@ -0,0 +1,10 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is +# regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiWithSubmodule/multiapiwithsubmodule/submodule/_utils/serialization.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiWithSubmodule/multiapiwithsubmodule/submodule/_utils/serialization.py new file mode 100644 index 00000000000..05bcd7d403a --- /dev/null +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiWithSubmodule/multiapiwithsubmodule/submodule/_utils/serialization.py @@ -0,0 +1,2025 @@ +# coding=utf-8 + +# pyright: reportUnnecessaryTypeIgnoreComment=false + +from base64 import b64decode, b64encode +import calendar +import datetime +import decimal +import email +from enum import Enum +import json +import logging +import re +import sys +import codecs +from typing import ( + Dict, + Any, + cast, + Optional, + Union, + AnyStr, + IO, + Mapping, + Callable, + MutableMapping, + List, +) + +try: + from urllib import quote # type: ignore +except ImportError: + from urllib.parse import quote +import xml.etree.ElementTree as ET + +import isodate # type: ignore +from typing_extensions import Self + +from azure.core.exceptions import DeserializationError, SerializationError +from azure.core.serialization import NULL as CoreNull + +_BOM = codecs.BOM_UTF8.decode(encoding="utf-8") + +JSON = MutableMapping[str, Any] + + +class RawDeserializer: + + # Accept "text" because we're open minded people... + JSON_REGEXP = re.compile(r"^(application|text)/([a-z+.]+\+)?json$") + + # Name used in context + CONTEXT_NAME = "deserialized_data" + + @classmethod + def deserialize_from_text(cls, data: Optional[Union[AnyStr, IO]], content_type: Optional[str] = None) -> Any: + """Decode data according to content-type. + + Accept a stream of data as well, but will be load at once in memory for now. + + If no content-type, will return the string version (not bytes, not stream) + + :param data: Input, could be bytes or stream (will be decoded with UTF8) or text + :type data: str or bytes or IO + :param str content_type: The content type. + :return: The deserialized data. + :rtype: object + """ + if hasattr(data, "read"): + # Assume a stream + data = cast(IO, data).read() + + if isinstance(data, bytes): + data_as_str = data.decode(encoding="utf-8-sig") + else: + # Explain to mypy the correct type. + data_as_str = cast(str, data) + + # Remove Byte Order Mark if present in string + data_as_str = data_as_str.lstrip(_BOM) + + if content_type is None: + return data + + if cls.JSON_REGEXP.match(content_type): + try: + return json.loads(data_as_str) + except ValueError as err: + raise DeserializationError("JSON is invalid: {}".format(err), err) from err + elif "xml" in (content_type or []): + try: + + try: + if isinstance(data, unicode): # type: ignore + # If I'm Python 2.7 and unicode XML will scream if I try a "fromstring" on unicode string + data_as_str = data_as_str.encode(encoding="utf-8") # type: ignore + except NameError: + pass + + return ET.fromstring(data_as_str) # nosec + except ET.ParseError as err: + # It might be because the server has an issue, and returned JSON with + # content-type XML.... + # So let's try a JSON load, and if it's still broken + # let's flow the initial exception + def _json_attemp(data): + try: + return True, json.loads(data) + except ValueError: + return False, None # Don't care about this one + + success, json_result = _json_attemp(data) + if success: + return json_result + # If i'm here, it's not JSON, it's not XML, let's scream + # and raise the last context in this block (the XML exception) + # The function hack is because Py2.7 messes up with exception + # context otherwise. + _LOGGER.critical("Wasn't XML not JSON, failing") + raise DeserializationError("XML is invalid") from err + elif content_type.startswith("text/"): + return data_as_str + raise DeserializationError("Cannot deserialize content-type: {}".format(content_type)) + + @classmethod + def deserialize_from_http_generics(cls, body_bytes: Optional[Union[AnyStr, IO]], headers: Mapping) -> Any: + """Deserialize from HTTP response. + + Use bytes and headers to NOT use any requests/aiohttp or whatever + specific implementation. + Headers will tested for "content-type" + + :param bytes body_bytes: The body of the response. + :param dict headers: The headers of the response. + :returns: The deserialized data. + :rtype: object + """ + # Try to use content-type from headers if available + content_type = None + if "content-type" in headers: + content_type = headers["content-type"].split(";")[0].strip().lower() + # Ouch, this server did not declare what it sent... + # Let's guess it's JSON... + # Also, since Autorest was considering that an empty body was a valid JSON, + # need that test as well.... + else: + content_type = "application/json" + + if body_bytes: + return cls.deserialize_from_text(body_bytes, content_type) + return None + + +_LOGGER = logging.getLogger(__name__) + +try: + _long_type = long # type: ignore +except NameError: + _long_type = int + +TZ_UTC = datetime.timezone.utc + +_FLATTEN = re.compile(r"(? None: + self.additional_properties: Optional[Dict[str, Any]] = {} + for k in kwargs: # pylint: disable=consider-using-dict-items + if k not in self._attribute_map: + _LOGGER.warning("%s is not a known attribute of class %s and will be ignored", k, self.__class__) + elif k in self._validation and self._validation[k].get("readonly", False): + _LOGGER.warning("Readonly attribute %s will be ignored in class %s", k, self.__class__) + else: + setattr(self, k, kwargs[k]) + + def __eq__(self, other: Any) -> bool: + """Compare objects by comparing all attributes. + + :param object other: The object to compare + :returns: True if objects are equal + :rtype: bool + """ + if isinstance(other, self.__class__): + return self.__dict__ == other.__dict__ + return False + + def __ne__(self, other: Any) -> bool: + """Compare objects by comparing all attributes. + + :param object other: The object to compare + :returns: True if objects are not equal + :rtype: bool + """ + return not self.__eq__(other) + + def __str__(self) -> str: + return str(self.__dict__) + + @classmethod + def enable_additional_properties_sending(cls) -> None: + cls._attribute_map["additional_properties"] = {"key": "", "type": "{object}"} + + @classmethod + def is_xml_model(cls) -> bool: + try: + cls._xml_map # type: ignore + except AttributeError: + return False + return True + + @classmethod + def _create_xml_node(cls): + """Create XML node. + + :returns: The XML node + :rtype: xml.etree.ElementTree.Element + """ + try: + xml_map = cls._xml_map # type: ignore + except AttributeError: + xml_map = {} + + return _create_xml_node(xml_map.get("name", cls.__name__), xml_map.get("prefix", None), xml_map.get("ns", None)) + + def serialize(self, keep_readonly: bool = False, **kwargs: Any) -> JSON: + """Return the JSON that would be sent to server from this model. + + This is an alias to `as_dict(full_restapi_key_transformer, keep_readonly=False)`. + + If you want XML serialization, you can pass the kwargs is_xml=True. + + :param bool keep_readonly: If you want to serialize the readonly attributes + :returns: A dict JSON compatible object + :rtype: dict + """ + serializer = Serializer(self._infer_class_models()) + return serializer._serialize( # type: ignore # pylint: disable=protected-access + self, keep_readonly=keep_readonly, **kwargs + ) + + def as_dict( + self, + keep_readonly: bool = True, + key_transformer: Callable[[str, Dict[str, Any], Any], Any] = attribute_transformer, + **kwargs: Any + ) -> JSON: + """Return a dict that can be serialized using json.dump. + + Advanced usage might optionally use a callback as parameter: + + .. code::python + + def my_key_transformer(key, attr_desc, value): + return key + + Key is the attribute name used in Python. Attr_desc + is a dict of metadata. Currently contains 'type' with the + msrest type and 'key' with the RestAPI encoded key. + Value is the current value in this object. + + The string returned will be used to serialize the key. + If the return type is a list, this is considered hierarchical + result dict. + + See the three examples in this file: + + - attribute_transformer + - full_restapi_key_transformer + - last_restapi_key_transformer + + If you want XML serialization, you can pass the kwargs is_xml=True. + + :param bool keep_readonly: If you want to serialize the readonly attributes + :param function key_transformer: A key transformer function. + :returns: A dict JSON compatible object + :rtype: dict + """ + serializer = Serializer(self._infer_class_models()) + return serializer._serialize( # type: ignore # pylint: disable=protected-access + self, key_transformer=key_transformer, keep_readonly=keep_readonly, **kwargs + ) + + @classmethod + def _infer_class_models(cls): + try: + str_models = cls.__module__.rsplit(".", 1)[0] + models = sys.modules[str_models] + client_models = {k: v for k, v in models.__dict__.items() if isinstance(v, type)} + if cls.__name__ not in client_models: + raise ValueError("Not Autorest generated code") + except Exception: # pylint: disable=broad-exception-caught + # Assume it's not Autorest generated (tests?). Add ourselves as dependencies. + client_models = {cls.__name__: cls} + return client_models + + @classmethod + def deserialize(cls, data: Any, content_type: Optional[str] = None) -> Self: + """Parse a str using the RestAPI syntax and return a model. + + :param str data: A str using RestAPI structure. JSON by default. + :param str content_type: JSON by default, set application/xml if XML. + :returns: An instance of this model + :raises DeserializationError: if something went wrong + :rtype: Self + """ + deserializer = Deserializer(cls._infer_class_models()) + return deserializer(cls.__name__, data, content_type=content_type) # type: ignore + + @classmethod + def from_dict( + cls, + data: Any, + key_extractors: Optional[Callable[[str, Dict[str, Any], Any], Any]] = None, + content_type: Optional[str] = None, + ) -> Self: + """Parse a dict using given key extractor return a model. + + By default consider key + extractors (rest_key_case_insensitive_extractor, attribute_key_case_insensitive_extractor + and last_rest_key_case_insensitive_extractor) + + :param dict data: A dict using RestAPI structure + :param function key_extractors: A key extractor function. + :param str content_type: JSON by default, set application/xml if XML. + :returns: An instance of this model + :raises DeserializationError: if something went wrong + :rtype: Self + """ + deserializer = Deserializer(cls._infer_class_models()) + deserializer.key_extractors = ( # type: ignore + [ # type: ignore + attribute_key_case_insensitive_extractor, + rest_key_case_insensitive_extractor, + last_rest_key_case_insensitive_extractor, + ] + if key_extractors is None + else key_extractors + ) + return deserializer(cls.__name__, data, content_type=content_type) # type: ignore + + @classmethod + def _flatten_subtype(cls, key, objects): + if "_subtype_map" not in cls.__dict__: + return {} + result = dict(cls._subtype_map[key]) + for valuetype in cls._subtype_map[key].values(): + result.update(objects[valuetype]._flatten_subtype(key, objects)) # pylint: disable=protected-access + return result + + @classmethod + def _classify(cls, response, objects): + """Check the class _subtype_map for any child classes. + We want to ignore any inherited _subtype_maps. + + :param dict response: The initial data + :param dict objects: The class objects + :returns: The class to be used + :rtype: class + """ + for subtype_key in cls.__dict__.get("_subtype_map", {}).keys(): + subtype_value = None + + if not isinstance(response, ET.Element): + rest_api_response_key = cls._get_rest_key_parts(subtype_key)[-1] + subtype_value = response.get(rest_api_response_key, None) or response.get(subtype_key, None) + else: + subtype_value = xml_key_extractor(subtype_key, cls._attribute_map[subtype_key], response) + if subtype_value: + # Try to match base class. Can be class name only + # (bug to fix in Autorest to support x-ms-discriminator-name) + if cls.__name__ == subtype_value: + return cls + flatten_mapping_type = cls._flatten_subtype(subtype_key, objects) + try: + return objects[flatten_mapping_type[subtype_value]] # type: ignore + except KeyError: + _LOGGER.warning( + "Subtype value %s has no mapping, use base class %s.", + subtype_value, + cls.__name__, + ) + break + else: + _LOGGER.warning("Discriminator %s is absent or null, use base class %s.", subtype_key, cls.__name__) + break + return cls + + @classmethod + def _get_rest_key_parts(cls, attr_key): + """Get the RestAPI key of this attr, split it and decode part + :param str attr_key: Attribute key must be in attribute_map. + :returns: A list of RestAPI part + :rtype: list + """ + rest_split_key = _FLATTEN.split(cls._attribute_map[attr_key]["key"]) + return [_decode_attribute_map_key(key_part) for key_part in rest_split_key] + + +def _decode_attribute_map_key(key): + """This decode a key in an _attribute_map to the actual key we want to look at + inside the received data. + + :param str key: A key string from the generated code + :returns: The decoded key + :rtype: str + """ + return key.replace("\\.", ".") + + +class Serializer: # pylint: disable=too-many-public-methods + """Request object model serializer.""" + + basic_types = {str: "str", int: "int", bool: "bool", float: "float"} + + _xml_basic_types_serializers = {"bool": lambda x: str(x).lower()} + days = {0: "Mon", 1: "Tue", 2: "Wed", 3: "Thu", 4: "Fri", 5: "Sat", 6: "Sun"} + months = { + 1: "Jan", + 2: "Feb", + 3: "Mar", + 4: "Apr", + 5: "May", + 6: "Jun", + 7: "Jul", + 8: "Aug", + 9: "Sep", + 10: "Oct", + 11: "Nov", + 12: "Dec", + } + validation = { + "min_length": lambda x, y: len(x) < y, + "max_length": lambda x, y: len(x) > y, + "minimum": lambda x, y: x < y, + "maximum": lambda x, y: x > y, + "minimum_ex": lambda x, y: x <= y, + "maximum_ex": lambda x, y: x >= y, + "min_items": lambda x, y: len(x) < y, + "max_items": lambda x, y: len(x) > y, + "pattern": lambda x, y: not re.match(y, x, re.UNICODE), + "unique": lambda x, y: len(x) != len(set(x)), + "multiple": lambda x, y: x % y != 0, + } + + def __init__(self, classes: Optional[Mapping[str, type]] = None) -> None: + self.serialize_type = { + "iso-8601": Serializer.serialize_iso, + "rfc-1123": Serializer.serialize_rfc, + "unix-time": Serializer.serialize_unix, + "duration": Serializer.serialize_duration, + "date": Serializer.serialize_date, + "time": Serializer.serialize_time, + "decimal": Serializer.serialize_decimal, + "long": Serializer.serialize_long, + "bytearray": Serializer.serialize_bytearray, + "base64": Serializer.serialize_base64, + "object": self.serialize_object, + "[]": self.serialize_iter, + "{}": self.serialize_dict, + } + self.dependencies: Dict[str, type] = dict(classes) if classes else {} + self.key_transformer = full_restapi_key_transformer + self.client_side_validation = True + + def _serialize( # pylint: disable=too-many-nested-blocks, too-many-branches, too-many-statements, too-many-locals + self, target_obj, data_type=None, **kwargs + ): + """Serialize data into a string according to type. + + :param object target_obj: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str, dict + :raises SerializationError: if serialization fails. + :returns: The serialized data. + """ + key_transformer = kwargs.get("key_transformer", self.key_transformer) + keep_readonly = kwargs.get("keep_readonly", False) + if target_obj is None: + return None + + attr_name = None + class_name = target_obj.__class__.__name__ + + if data_type: + return self.serialize_data(target_obj, data_type, **kwargs) + + if not hasattr(target_obj, "_attribute_map"): + data_type = type(target_obj).__name__ + if data_type in self.basic_types.values(): + return self.serialize_data(target_obj, data_type, **kwargs) + + # Force "is_xml" kwargs if we detect a XML model + try: + is_xml_model_serialization = kwargs["is_xml"] + except KeyError: + is_xml_model_serialization = kwargs.setdefault("is_xml", target_obj.is_xml_model()) + + serialized = {} + if is_xml_model_serialization: + serialized = target_obj._create_xml_node() # pylint: disable=protected-access + try: + attributes = target_obj._attribute_map # pylint: disable=protected-access + for attr, attr_desc in attributes.items(): + attr_name = attr + if not keep_readonly and target_obj._validation.get( # pylint: disable=protected-access + attr_name, {} + ).get("readonly", False): + continue + + if attr_name == "additional_properties" and attr_desc["key"] == "": + if target_obj.additional_properties is not None: + serialized.update(target_obj.additional_properties) + continue + try: + + orig_attr = getattr(target_obj, attr) + if is_xml_model_serialization: + pass # Don't provide "transformer" for XML for now. Keep "orig_attr" + else: # JSON + keys, orig_attr = key_transformer(attr, attr_desc.copy(), orig_attr) + keys = keys if isinstance(keys, list) else [keys] + + kwargs["serialization_ctxt"] = attr_desc + new_attr = self.serialize_data(orig_attr, attr_desc["type"], **kwargs) + + if is_xml_model_serialization: + xml_desc = attr_desc.get("xml", {}) + xml_name = xml_desc.get("name", attr_desc["key"]) + xml_prefix = xml_desc.get("prefix", None) + xml_ns = xml_desc.get("ns", None) + if xml_desc.get("attr", False): + if xml_ns: + ET.register_namespace(xml_prefix, xml_ns) + xml_name = "{{{}}}{}".format(xml_ns, xml_name) + serialized.set(xml_name, new_attr) # type: ignore + continue + if xml_desc.get("text", False): + serialized.text = new_attr # type: ignore + continue + if isinstance(new_attr, list): + serialized.extend(new_attr) # type: ignore + elif isinstance(new_attr, ET.Element): + # If the down XML has no XML/Name, + # we MUST replace the tag with the local tag. But keeping the namespaces. + if "name" not in getattr(orig_attr, "_xml_map", {}): + splitted_tag = new_attr.tag.split("}") + if len(splitted_tag) == 2: # Namespace + new_attr.tag = "}".join([splitted_tag[0], xml_name]) + else: + new_attr.tag = xml_name + serialized.append(new_attr) # type: ignore + else: # That's a basic type + # Integrate namespace if necessary + local_node = _create_xml_node(xml_name, xml_prefix, xml_ns) + local_node.text = str(new_attr) + serialized.append(local_node) # type: ignore + else: # JSON + for k in reversed(keys): # type: ignore + new_attr = {k: new_attr} + + _new_attr = new_attr + _serialized = serialized + for k in keys: # type: ignore + if k not in _serialized: + _serialized.update(_new_attr) # type: ignore + _new_attr = _new_attr[k] # type: ignore + _serialized = _serialized[k] + except ValueError as err: + if isinstance(err, SerializationError): + raise + + except (AttributeError, KeyError, TypeError) as err: + msg = "Attribute {} in object {} cannot be serialized.\n{}".format(attr_name, class_name, str(target_obj)) + raise SerializationError(msg) from err + return serialized + + def body(self, data, data_type, **kwargs): + """Serialize data intended for a request body. + + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: dict + :raises SerializationError: if serialization fails. + :raises ValueError: if data is None + :returns: The serialized request body + """ + + # Just in case this is a dict + internal_data_type_str = data_type.strip("[]{}") + internal_data_type = self.dependencies.get(internal_data_type_str, None) + try: + is_xml_model_serialization = kwargs["is_xml"] + except KeyError: + if internal_data_type and issubclass(internal_data_type, Model): + is_xml_model_serialization = kwargs.setdefault("is_xml", internal_data_type.is_xml_model()) + else: + is_xml_model_serialization = False + if internal_data_type and not isinstance(internal_data_type, Enum): + try: + deserializer = Deserializer(self.dependencies) + # Since it's on serialization, it's almost sure that format is not JSON REST + # We're not able to deal with additional properties for now. + deserializer.additional_properties_detection = False + if is_xml_model_serialization: + deserializer.key_extractors = [ # type: ignore + attribute_key_case_insensitive_extractor, + ] + else: + deserializer.key_extractors = [ + rest_key_case_insensitive_extractor, + attribute_key_case_insensitive_extractor, + last_rest_key_case_insensitive_extractor, + ] + data = deserializer._deserialize(data_type, data) # pylint: disable=protected-access + except DeserializationError as err: + raise SerializationError("Unable to build a model: " + str(err)) from err + + return self._serialize(data, data_type, **kwargs) + + def url(self, name, data, data_type, **kwargs): + """Serialize data intended for a URL path. + + :param str name: The name of the URL path parameter. + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str + :returns: The serialized URL path + :raises TypeError: if serialization fails. + :raises ValueError: if data is None + """ + try: + output = self.serialize_data(data, data_type, **kwargs) + if data_type == "bool": + output = json.dumps(output) + + if kwargs.get("skip_quote") is True: + output = str(output) + output = output.replace("{", quote("{")).replace("}", quote("}")) + else: + output = quote(str(output), safe="") + except SerializationError as exc: + raise TypeError("{} must be type {}.".format(name, data_type)) from exc + return output + + def query(self, name, data, data_type, **kwargs): + """Serialize data intended for a URL query. + + :param str name: The name of the query parameter. + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str, list + :raises TypeError: if serialization fails. + :raises ValueError: if data is None + :returns: The serialized query parameter + """ + try: + # Treat the list aside, since we don't want to encode the div separator + if data_type.startswith("["): + internal_data_type = data_type[1:-1] + do_quote = not kwargs.get("skip_quote", False) + return self.serialize_iter(data, internal_data_type, do_quote=do_quote, **kwargs) + + # Not a list, regular serialization + output = self.serialize_data(data, data_type, **kwargs) + if data_type == "bool": + output = json.dumps(output) + if kwargs.get("skip_quote") is True: + output = str(output) + else: + output = quote(str(output), safe="") + except SerializationError as exc: + raise TypeError("{} must be type {}.".format(name, data_type)) from exc + return str(output) + + def header(self, name, data, data_type, **kwargs): + """Serialize data intended for a request header. + + :param str name: The name of the header. + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str + :raises TypeError: if serialization fails. + :raises ValueError: if data is None + :returns: The serialized header + """ + try: + if data_type in ["[str]"]: + data = ["" if d is None else d for d in data] + + output = self.serialize_data(data, data_type, **kwargs) + if data_type == "bool": + output = json.dumps(output) + except SerializationError as exc: + raise TypeError("{} must be type {}.".format(name, data_type)) from exc + return str(output) + + def serialize_data(self, data, data_type, **kwargs): + """Serialize generic data according to supplied data type. + + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :raises AttributeError: if required data is None. + :raises ValueError: if data is None + :raises SerializationError: if serialization fails. + :returns: The serialized data. + :rtype: str, int, float, bool, dict, list + """ + if data is None: + raise ValueError("No value for given attribute") + + try: + if data is CoreNull: + return None + if data_type in self.basic_types.values(): + return self.serialize_basic(data, data_type, **kwargs) + + if data_type in self.serialize_type: + return self.serialize_type[data_type](data, **kwargs) + + # If dependencies is empty, try with current data class + # It has to be a subclass of Enum anyway + enum_type = self.dependencies.get(data_type, data.__class__) + if issubclass(enum_type, Enum): + return Serializer.serialize_enum(data, enum_obj=enum_type) + + iter_type = data_type[0] + data_type[-1] + if iter_type in self.serialize_type: + return self.serialize_type[iter_type](data, data_type[1:-1], **kwargs) + + except (ValueError, TypeError) as err: + msg = "Unable to serialize value: {!r} as type: {!r}." + raise SerializationError(msg.format(data, data_type)) from err + return self._serialize(data, **kwargs) + + @classmethod + def _get_custom_serializers(cls, data_type, **kwargs): # pylint: disable=inconsistent-return-statements + custom_serializer = kwargs.get("basic_types_serializers", {}).get(data_type) + if custom_serializer: + return custom_serializer + if kwargs.get("is_xml", False): + return cls._xml_basic_types_serializers.get(data_type) + + @classmethod + def serialize_basic(cls, data, data_type, **kwargs): + """Serialize basic builting data type. + Serializes objects to str, int, float or bool. + + Possible kwargs: + - basic_types_serializers dict[str, callable] : If set, use the callable as serializer + - is_xml bool : If set, use xml_basic_types_serializers + + :param obj data: Object to be serialized. + :param str data_type: Type of object in the iterable. + :rtype: str, int, float, bool + :return: serialized object + """ + custom_serializer = cls._get_custom_serializers(data_type, **kwargs) + if custom_serializer: + return custom_serializer(data) + if data_type == "str": + return cls.serialize_unicode(data) + return eval(data_type)(data) # nosec # pylint: disable=eval-used + + @classmethod + def serialize_unicode(cls, data): + """Special handling for serializing unicode strings in Py2. + Encode to UTF-8 if unicode, otherwise handle as a str. + + :param str data: Object to be serialized. + :rtype: str + :return: serialized object + """ + try: # If I received an enum, return its value + return data.value + except AttributeError: + pass + + try: + if isinstance(data, unicode): # type: ignore + # Don't change it, JSON and XML ElementTree are totally able + # to serialize correctly u'' strings + return data + except NameError: + return str(data) + return str(data) + + def serialize_iter(self, data, iter_type, div=None, **kwargs): + """Serialize iterable. + + Supported kwargs: + - serialization_ctxt dict : The current entry of _attribute_map, or same format. + serialization_ctxt['type'] should be same as data_type. + - is_xml bool : If set, serialize as XML + + :param list data: Object to be serialized. + :param str iter_type: Type of object in the iterable. + :param str div: If set, this str will be used to combine the elements + in the iterable into a combined string. Default is 'None'. + Defaults to False. + :rtype: list, str + :return: serialized iterable + """ + if isinstance(data, str): + raise SerializationError("Refuse str type as a valid iter type.") + + serialization_ctxt = kwargs.get("serialization_ctxt", {}) + is_xml = kwargs.get("is_xml", False) + + serialized = [] + for d in data: + try: + serialized.append(self.serialize_data(d, iter_type, **kwargs)) + except ValueError as err: + if isinstance(err, SerializationError): + raise + serialized.append(None) + + if kwargs.get("do_quote", False): + serialized = ["" if s is None else quote(str(s), safe="") for s in serialized] + + if div: + serialized = ["" if s is None else str(s) for s in serialized] + serialized = div.join(serialized) + + if "xml" in serialization_ctxt or is_xml: + # XML serialization is more complicated + xml_desc = serialization_ctxt.get("xml", {}) + xml_name = xml_desc.get("name") + if not xml_name: + xml_name = serialization_ctxt["key"] + + # Create a wrap node if necessary (use the fact that Element and list have "append") + is_wrapped = xml_desc.get("wrapped", False) + node_name = xml_desc.get("itemsName", xml_name) + if is_wrapped: + final_result = _create_xml_node(xml_name, xml_desc.get("prefix", None), xml_desc.get("ns", None)) + else: + final_result = [] + # All list elements to "local_node" + for el in serialized: + if isinstance(el, ET.Element): + el_node = el + else: + el_node = _create_xml_node(node_name, xml_desc.get("prefix", None), xml_desc.get("ns", None)) + if el is not None: # Otherwise it writes "None" :-p + el_node.text = str(el) + final_result.append(el_node) + return final_result + return serialized + + def serialize_dict(self, attr, dict_type, **kwargs): + """Serialize a dictionary of objects. + + :param dict attr: Object to be serialized. + :param str dict_type: Type of object in the dictionary. + :rtype: dict + :return: serialized dictionary + """ + serialization_ctxt = kwargs.get("serialization_ctxt", {}) + serialized = {} + for key, value in attr.items(): + try: + serialized[self.serialize_unicode(key)] = self.serialize_data(value, dict_type, **kwargs) + except ValueError as err: + if isinstance(err, SerializationError): + raise + serialized[self.serialize_unicode(key)] = None + + if "xml" in serialization_ctxt: + # XML serialization is more complicated + xml_desc = serialization_ctxt["xml"] + xml_name = xml_desc["name"] + + final_result = _create_xml_node(xml_name, xml_desc.get("prefix", None), xml_desc.get("ns", None)) + for key, value in serialized.items(): + ET.SubElement(final_result, key).text = value + return final_result + + return serialized + + def serialize_object(self, attr, **kwargs): # pylint: disable=too-many-return-statements + """Serialize a generic object. + This will be handled as a dictionary. If object passed in is not + a basic type (str, int, float, dict, list) it will simply be + cast to str. + + :param dict attr: Object to be serialized. + :rtype: dict or str + :return: serialized object + """ + if attr is None: + return None + if isinstance(attr, ET.Element): + return attr + obj_type = type(attr) + if obj_type in self.basic_types: + return self.serialize_basic(attr, self.basic_types[obj_type], **kwargs) + if obj_type is _long_type: + return self.serialize_long(attr) + if obj_type is str: + return self.serialize_unicode(attr) + if obj_type is datetime.datetime: + return self.serialize_iso(attr) + if obj_type is datetime.date: + return self.serialize_date(attr) + if obj_type is datetime.time: + return self.serialize_time(attr) + if obj_type is datetime.timedelta: + return self.serialize_duration(attr) + if obj_type is decimal.Decimal: + return self.serialize_decimal(attr) + + # If it's a model or I know this dependency, serialize as a Model + if obj_type in self.dependencies.values() or isinstance(attr, Model): + return self._serialize(attr) + + if obj_type == dict: + serialized = {} + for key, value in attr.items(): + try: + serialized[self.serialize_unicode(key)] = self.serialize_object(value, **kwargs) + except ValueError: + serialized[self.serialize_unicode(key)] = None + return serialized + + if obj_type == list: + serialized = [] + for obj in attr: + try: + serialized.append(self.serialize_object(obj, **kwargs)) + except ValueError: + pass + return serialized + return str(attr) + + @staticmethod + def serialize_enum(attr, enum_obj=None): + try: + result = attr.value + except AttributeError: + result = attr + try: + enum_obj(result) # type: ignore + return result + except ValueError as exc: + for enum_value in enum_obj: # type: ignore + if enum_value.value.lower() == str(attr).lower(): + return enum_value.value + error = "{!r} is not valid value for enum {!r}" + raise SerializationError(error.format(attr, enum_obj)) from exc + + @staticmethod + def serialize_bytearray(attr, **kwargs): # pylint: disable=unused-argument + """Serialize bytearray into base-64 string. + + :param str attr: Object to be serialized. + :rtype: str + :return: serialized base64 + """ + return b64encode(attr).decode() + + @staticmethod + def serialize_base64(attr, **kwargs): # pylint: disable=unused-argument + """Serialize str into base-64 string. + + :param str attr: Object to be serialized. + :rtype: str + :return: serialized base64 + """ + encoded = b64encode(attr).decode("ascii") + return encoded.strip("=").replace("+", "-").replace("/", "_") + + @staticmethod + def serialize_decimal(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Decimal object to float. + + :param decimal attr: Object to be serialized. + :rtype: float + :return: serialized decimal + """ + return float(attr) + + @staticmethod + def serialize_long(attr, **kwargs): # pylint: disable=unused-argument + """Serialize long (Py2) or int (Py3). + + :param int attr: Object to be serialized. + :rtype: int/long + :return: serialized long + """ + return _long_type(attr) + + @staticmethod + def serialize_date(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Date object into ISO-8601 formatted string. + + :param Date attr: Object to be serialized. + :rtype: str + :return: serialized date + """ + if isinstance(attr, str): + attr = isodate.parse_date(attr) + t = "{:04}-{:02}-{:02}".format(attr.year, attr.month, attr.day) + return t + + @staticmethod + def serialize_time(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Time object into ISO-8601 formatted string. + + :param datetime.time attr: Object to be serialized. + :rtype: str + :return: serialized time + """ + if isinstance(attr, str): + attr = isodate.parse_time(attr) + t = "{:02}:{:02}:{:02}".format(attr.hour, attr.minute, attr.second) + if attr.microsecond: + t += ".{:02}".format(attr.microsecond) + return t + + @staticmethod + def serialize_duration(attr, **kwargs): # pylint: disable=unused-argument + """Serialize TimeDelta object into ISO-8601 formatted string. + + :param TimeDelta attr: Object to be serialized. + :rtype: str + :return: serialized duration + """ + if isinstance(attr, str): + attr = isodate.parse_duration(attr) + return isodate.duration_isoformat(attr) + + @staticmethod + def serialize_rfc(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Datetime object into RFC-1123 formatted string. + + :param Datetime attr: Object to be serialized. + :rtype: str + :raises TypeError: if format invalid. + :return: serialized rfc + """ + try: + if not attr.tzinfo: + _LOGGER.warning("Datetime with no tzinfo will be considered UTC.") + utc = attr.utctimetuple() + except AttributeError as exc: + raise TypeError("RFC1123 object must be valid Datetime object.") from exc + + return "{}, {:02} {} {:04} {:02}:{:02}:{:02} GMT".format( + Serializer.days[utc.tm_wday], + utc.tm_mday, + Serializer.months[utc.tm_mon], + utc.tm_year, + utc.tm_hour, + utc.tm_min, + utc.tm_sec, + ) + + @staticmethod + def serialize_iso(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Datetime object into ISO-8601 formatted string. + + :param Datetime attr: Object to be serialized. + :rtype: str + :raises SerializationError: if format invalid. + :return: serialized iso + """ + if isinstance(attr, str): + attr = isodate.parse_datetime(attr) + try: + if not attr.tzinfo: + _LOGGER.warning("Datetime with no tzinfo will be considered UTC.") + utc = attr.utctimetuple() + if utc.tm_year > 9999 or utc.tm_year < 1: + raise OverflowError("Hit max or min date") + + microseconds = str(attr.microsecond).rjust(6, "0").rstrip("0").ljust(3, "0") + if microseconds: + microseconds = "." + microseconds + date = "{:04}-{:02}-{:02}T{:02}:{:02}:{:02}".format( + utc.tm_year, utc.tm_mon, utc.tm_mday, utc.tm_hour, utc.tm_min, utc.tm_sec + ) + return date + microseconds + "Z" + except (ValueError, OverflowError) as err: + msg = "Unable to serialize datetime object." + raise SerializationError(msg) from err + except AttributeError as err: + msg = "ISO-8601 object must be valid Datetime object." + raise TypeError(msg) from err + + @staticmethod + def serialize_unix(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Datetime object into IntTime format. + This is represented as seconds. + + :param Datetime attr: Object to be serialized. + :rtype: int + :raises SerializationError: if format invalid + :return: serialied unix + """ + if isinstance(attr, int): + return attr + try: + if not attr.tzinfo: + _LOGGER.warning("Datetime with no tzinfo will be considered UTC.") + return int(calendar.timegm(attr.utctimetuple())) + except AttributeError as exc: + raise TypeError("Unix time object must be valid Datetime object.") from exc + + +def rest_key_extractor(attr, attr_desc, data): # pylint: disable=unused-argument + key = attr_desc["key"] + working_data = data + + while "." in key: + # Need the cast, as for some reasons "split" is typed as list[str | Any] + dict_keys = cast(List[str], _FLATTEN.split(key)) + if len(dict_keys) == 1: + key = _decode_attribute_map_key(dict_keys[0]) + break + working_key = _decode_attribute_map_key(dict_keys[0]) + working_data = working_data.get(working_key, data) + if working_data is None: + # If at any point while following flatten JSON path see None, it means + # that all properties under are None as well + return None + key = ".".join(dict_keys[1:]) + + return working_data.get(key) + + +def rest_key_case_insensitive_extractor( # pylint: disable=unused-argument, inconsistent-return-statements + attr, attr_desc, data +): + key = attr_desc["key"] + working_data = data + + while "." in key: + dict_keys = _FLATTEN.split(key) + if len(dict_keys) == 1: + key = _decode_attribute_map_key(dict_keys[0]) + break + working_key = _decode_attribute_map_key(dict_keys[0]) + working_data = attribute_key_case_insensitive_extractor(working_key, None, working_data) + if working_data is None: + # If at any point while following flatten JSON path see None, it means + # that all properties under are None as well + return None + key = ".".join(dict_keys[1:]) + + if working_data: + return attribute_key_case_insensitive_extractor(key, None, working_data) + + +def last_rest_key_extractor(attr, attr_desc, data): # pylint: disable=unused-argument + """Extract the attribute in "data" based on the last part of the JSON path key. + + :param str attr: The attribute to extract + :param dict attr_desc: The attribute description + :param dict data: The data to extract from + :rtype: object + :returns: The extracted attribute + """ + key = attr_desc["key"] + dict_keys = _FLATTEN.split(key) + return attribute_key_extractor(dict_keys[-1], None, data) + + +def last_rest_key_case_insensitive_extractor(attr, attr_desc, data): # pylint: disable=unused-argument + """Extract the attribute in "data" based on the last part of the JSON path key. + + This is the case insensitive version of "last_rest_key_extractor" + :param str attr: The attribute to extract + :param dict attr_desc: The attribute description + :param dict data: The data to extract from + :rtype: object + :returns: The extracted attribute + """ + key = attr_desc["key"] + dict_keys = _FLATTEN.split(key) + return attribute_key_case_insensitive_extractor(dict_keys[-1], None, data) + + +def attribute_key_extractor(attr, _, data): + return data.get(attr) + + +def attribute_key_case_insensitive_extractor(attr, _, data): + found_key = None + lower_attr = attr.lower() + for key in data: + if lower_attr == key.lower(): + found_key = key + break + + return data.get(found_key) + + +def _extract_name_from_internal_type(internal_type): + """Given an internal type XML description, extract correct XML name with namespace. + + :param dict internal_type: An model type + :rtype: tuple + :returns: A tuple XML name + namespace dict + """ + internal_type_xml_map = getattr(internal_type, "_xml_map", {}) + xml_name = internal_type_xml_map.get("name", internal_type.__name__) + xml_ns = internal_type_xml_map.get("ns", None) + if xml_ns: + xml_name = "{{{}}}{}".format(xml_ns, xml_name) + return xml_name + + +def xml_key_extractor(attr, attr_desc, data): # pylint: disable=unused-argument,too-many-return-statements + if isinstance(data, dict): + return None + + # Test if this model is XML ready first + if not isinstance(data, ET.Element): + return None + + xml_desc = attr_desc.get("xml", {}) + xml_name = xml_desc.get("name", attr_desc["key"]) + + # Look for a children + is_iter_type = attr_desc["type"].startswith("[") + is_wrapped = xml_desc.get("wrapped", False) + internal_type = attr_desc.get("internalType", None) + internal_type_xml_map = getattr(internal_type, "_xml_map", {}) + + # Integrate namespace if necessary + xml_ns = xml_desc.get("ns", internal_type_xml_map.get("ns", None)) + if xml_ns: + xml_name = "{{{}}}{}".format(xml_ns, xml_name) + + # If it's an attribute, that's simple + if xml_desc.get("attr", False): + return data.get(xml_name) + + # If it's x-ms-text, that's simple too + if xml_desc.get("text", False): + return data.text + + # Scenario where I take the local name: + # - Wrapped node + # - Internal type is an enum (considered basic types) + # - Internal type has no XML/Name node + if is_wrapped or (internal_type and (issubclass(internal_type, Enum) or "name" not in internal_type_xml_map)): + children = data.findall(xml_name) + # If internal type has a local name and it's not a list, I use that name + elif not is_iter_type and internal_type and "name" in internal_type_xml_map: + xml_name = _extract_name_from_internal_type(internal_type) + children = data.findall(xml_name) + # That's an array + else: + if internal_type: # Complex type, ignore itemsName and use the complex type name + items_name = _extract_name_from_internal_type(internal_type) + else: + items_name = xml_desc.get("itemsName", xml_name) + children = data.findall(items_name) + + if len(children) == 0: + if is_iter_type: + if is_wrapped: + return None # is_wrapped no node, we want None + return [] # not wrapped, assume empty list + return None # Assume it's not there, maybe an optional node. + + # If is_iter_type and not wrapped, return all found children + if is_iter_type: + if not is_wrapped: + return children + # Iter and wrapped, should have found one node only (the wrap one) + if len(children) != 1: + raise DeserializationError( + "Tried to deserialize an array not wrapped, and found several nodes '{}'. Maybe you should declare this array as wrapped?".format( + xml_name + ) + ) + return list(children[0]) # Might be empty list and that's ok. + + # Here it's not a itertype, we should have found one element only or empty + if len(children) > 1: + raise DeserializationError("Find several XML '{}' where it was not expected".format(xml_name)) + return children[0] + + +class Deserializer: + """Response object model deserializer. + + :param dict classes: Class type dictionary for deserializing complex types. + :ivar list key_extractors: Ordered list of extractors to be used by this deserializer. + """ + + basic_types = {str: "str", int: "int", bool: "bool", float: "float"} + + valid_date = re.compile(r"\d{4}[-]\d{2}[-]\d{2}T\d{2}:\d{2}:\d{2}\.?\d*Z?[-+]?[\d{2}]?:?[\d{2}]?") + + def __init__(self, classes: Optional[Mapping[str, type]] = None) -> None: + self.deserialize_type = { + "iso-8601": Deserializer.deserialize_iso, + "rfc-1123": Deserializer.deserialize_rfc, + "unix-time": Deserializer.deserialize_unix, + "duration": Deserializer.deserialize_duration, + "date": Deserializer.deserialize_date, + "time": Deserializer.deserialize_time, + "decimal": Deserializer.deserialize_decimal, + "long": Deserializer.deserialize_long, + "bytearray": Deserializer.deserialize_bytearray, + "base64": Deserializer.deserialize_base64, + "object": self.deserialize_object, + "[]": self.deserialize_iter, + "{}": self.deserialize_dict, + } + self.deserialize_expected_types = { + "duration": (isodate.Duration, datetime.timedelta), + "iso-8601": (datetime.datetime), + } + self.dependencies: Dict[str, type] = dict(classes) if classes else {} + self.key_extractors = [rest_key_extractor, xml_key_extractor] + # Additional properties only works if the "rest_key_extractor" is used to + # extract the keys. Making it to work whatever the key extractor is too much + # complicated, with no real scenario for now. + # So adding a flag to disable additional properties detection. This flag should be + # used if your expect the deserialization to NOT come from a JSON REST syntax. + # Otherwise, result are unexpected + self.additional_properties_detection = True + + def __call__(self, target_obj, response_data, content_type=None): + """Call the deserializer to process a REST response. + + :param str target_obj: Target data type to deserialize to. + :param requests.Response response_data: REST response object. + :param str content_type: Swagger "produces" if available. + :raises DeserializationError: if deserialization fails. + :return: Deserialized object. + :rtype: object + """ + data = self._unpack_content(response_data, content_type) + return self._deserialize(target_obj, data) + + def _deserialize(self, target_obj, data): # pylint: disable=inconsistent-return-statements + """Call the deserializer on a model. + + Data needs to be already deserialized as JSON or XML ElementTree + + :param str target_obj: Target data type to deserialize to. + :param object data: Object to deserialize. + :raises DeserializationError: if deserialization fails. + :return: Deserialized object. + :rtype: object + """ + # This is already a model, go recursive just in case + if hasattr(data, "_attribute_map"): + constants = [name for name, config in getattr(data, "_validation", {}).items() if config.get("constant")] + try: + for attr, mapconfig in data._attribute_map.items(): # pylint: disable=protected-access + if attr in constants: + continue + value = getattr(data, attr) + if value is None: + continue + local_type = mapconfig["type"] + internal_data_type = local_type.strip("[]{}") + if internal_data_type not in self.dependencies or isinstance(internal_data_type, Enum): + continue + setattr(data, attr, self._deserialize(local_type, value)) + return data + except AttributeError: + return + + response, class_name = self._classify_target(target_obj, data) + + if isinstance(response, str): + return self.deserialize_data(data, response) + if isinstance(response, type) and issubclass(response, Enum): + return self.deserialize_enum(data, response) + + if data is None or data is CoreNull: + return data + try: + attributes = response._attribute_map # type: ignore # pylint: disable=protected-access + d_attrs = {} + for attr, attr_desc in attributes.items(): + # Check empty string. If it's not empty, someone has a real "additionalProperties"... + if attr == "additional_properties" and attr_desc["key"] == "": + continue + raw_value = None + # Enhance attr_desc with some dynamic data + attr_desc = attr_desc.copy() # Do a copy, do not change the real one + internal_data_type = attr_desc["type"].strip("[]{}") + if internal_data_type in self.dependencies: + attr_desc["internalType"] = self.dependencies[internal_data_type] + + for key_extractor in self.key_extractors: + found_value = key_extractor(attr, attr_desc, data) + if found_value is not None: + if raw_value is not None and raw_value != found_value: + msg = ( + "Ignoring extracted value '%s' from %s for key '%s'" + " (duplicate extraction, follow extractors order)" + ) + _LOGGER.warning(msg, found_value, key_extractor, attr) + continue + raw_value = found_value + + value = self.deserialize_data(raw_value, attr_desc["type"]) + d_attrs[attr] = value + except (AttributeError, TypeError, KeyError) as err: + msg = "Unable to deserialize to object: " + class_name # type: ignore + raise DeserializationError(msg) from err + additional_properties = self._build_additional_properties(attributes, data) + return self._instantiate_model(response, d_attrs, additional_properties) + + def _build_additional_properties(self, attribute_map, data): + if not self.additional_properties_detection: + return None + if "additional_properties" in attribute_map and attribute_map.get("additional_properties", {}).get("key") != "": + # Check empty string. If it's not empty, someone has a real "additionalProperties" + return None + if isinstance(data, ET.Element): + data = {el.tag: el.text for el in data} + + known_keys = { + _decode_attribute_map_key(_FLATTEN.split(desc["key"])[0]) + for desc in attribute_map.values() + if desc["key"] != "" + } + present_keys = set(data.keys()) + missing_keys = present_keys - known_keys + return {key: data[key] for key in missing_keys} + + def _classify_target(self, target, data): + """Check to see whether the deserialization target object can + be classified into a subclass. + Once classification has been determined, initialize object. + + :param str target: The target object type to deserialize to. + :param str/dict data: The response data to deserialize. + :return: The classified target object and its class name. + :rtype: tuple + """ + if target is None: + return None, None + + if isinstance(target, str): + try: + target = self.dependencies[target] + except KeyError: + return target, target + + try: + target = target._classify(data, self.dependencies) # type: ignore # pylint: disable=protected-access + except AttributeError: + pass # Target is not a Model, no classify + return target, target.__class__.__name__ # type: ignore + + def failsafe_deserialize(self, target_obj, data, content_type=None): + """Ignores any errors encountered in deserialization, + and falls back to not deserializing the object. Recommended + for use in error deserialization, as we want to return the + HttpResponseError to users, and not have them deal with + a deserialization error. + + :param str target_obj: The target object type to deserialize to. + :param str/dict data: The response data to deserialize. + :param str content_type: Swagger "produces" if available. + :return: Deserialized object. + :rtype: object + """ + try: + return self(target_obj, data, content_type=content_type) + except: # pylint: disable=bare-except + _LOGGER.debug( + "Ran into a deserialization error. Ignoring since this is failsafe deserialization", exc_info=True + ) + return None + + @staticmethod + def _unpack_content(raw_data, content_type=None): + """Extract the correct structure for deserialization. + + If raw_data is a PipelineResponse, try to extract the result of RawDeserializer. + if we can't, raise. Your Pipeline should have a RawDeserializer. + + If not a pipeline response and raw_data is bytes or string, use content-type + to decode it. If no content-type, try JSON. + + If raw_data is something else, bypass all logic and return it directly. + + :param obj raw_data: Data to be processed. + :param str content_type: How to parse if raw_data is a string/bytes. + :raises JSONDecodeError: If JSON is requested and parsing is impossible. + :raises UnicodeDecodeError: If bytes is not UTF8 + :rtype: object + :return: Unpacked content. + """ + # Assume this is enough to detect a Pipeline Response without importing it + context = getattr(raw_data, "context", {}) + if context: + if RawDeserializer.CONTEXT_NAME in context: + return context[RawDeserializer.CONTEXT_NAME] + raise ValueError("This pipeline didn't have the RawDeserializer policy; can't deserialize") + + # Assume this is enough to recognize universal_http.ClientResponse without importing it + if hasattr(raw_data, "body"): + return RawDeserializer.deserialize_from_http_generics(raw_data.text(), raw_data.headers) + + # Assume this enough to recognize requests.Response without importing it. + if hasattr(raw_data, "_content_consumed"): + return RawDeserializer.deserialize_from_http_generics(raw_data.text, raw_data.headers) + + if isinstance(raw_data, (str, bytes)) or hasattr(raw_data, "read"): + return RawDeserializer.deserialize_from_text(raw_data, content_type) # type: ignore + return raw_data + + def _instantiate_model(self, response, attrs, additional_properties=None): + """Instantiate a response model passing in deserialized args. + + :param Response response: The response model class. + :param dict attrs: The deserialized response attributes. + :param dict additional_properties: Additional properties to be set. + :rtype: Response + :return: The instantiated response model. + """ + if callable(response): + subtype = getattr(response, "_subtype_map", {}) + try: + readonly = [ + k + for k, v in response._validation.items() # pylint: disable=protected-access # type: ignore + if v.get("readonly") + ] + const = [ + k + for k, v in response._validation.items() # pylint: disable=protected-access # type: ignore + if v.get("constant") + ] + kwargs = {k: v for k, v in attrs.items() if k not in subtype and k not in readonly + const} + response_obj = response(**kwargs) + for attr in readonly: + setattr(response_obj, attr, attrs.get(attr)) + if additional_properties: + response_obj.additional_properties = additional_properties # type: ignore + return response_obj + except TypeError as err: + msg = "Unable to deserialize {} into model {}. ".format(kwargs, response) # type: ignore + raise DeserializationError(msg + str(err)) from err + else: + try: + for attr, value in attrs.items(): + setattr(response, attr, value) + return response + except Exception as exp: + msg = "Unable to populate response model. " + msg += "Type: {}, Error: {}".format(type(response), exp) + raise DeserializationError(msg) from exp + + def deserialize_data(self, data, data_type): # pylint: disable=too-many-return-statements + """Process data for deserialization according to data type. + + :param str data: The response string to be deserialized. + :param str data_type: The type to deserialize to. + :raises DeserializationError: if deserialization fails. + :return: Deserialized object. + :rtype: object + """ + if data is None: + return data + + try: + if not data_type: + return data + if data_type in self.basic_types.values(): + return self.deserialize_basic(data, data_type) + if data_type in self.deserialize_type: + if isinstance(data, self.deserialize_expected_types.get(data_type, tuple())): + return data + + is_a_text_parsing_type = lambda x: x not in [ # pylint: disable=unnecessary-lambda-assignment + "object", + "[]", + r"{}", + ] + if isinstance(data, ET.Element) and is_a_text_parsing_type(data_type) and not data.text: + return None + data_val = self.deserialize_type[data_type](data) + return data_val + + iter_type = data_type[0] + data_type[-1] + if iter_type in self.deserialize_type: + return self.deserialize_type[iter_type](data, data_type[1:-1]) + + obj_type = self.dependencies[data_type] + if issubclass(obj_type, Enum): + if isinstance(data, ET.Element): + data = data.text + return self.deserialize_enum(data, obj_type) + + except (ValueError, TypeError, AttributeError) as err: + msg = "Unable to deserialize response data." + msg += " Data: {}, {}".format(data, data_type) + raise DeserializationError(msg) from err + return self._deserialize(obj_type, data) + + def deserialize_iter(self, attr, iter_type): + """Deserialize an iterable. + + :param list attr: Iterable to be deserialized. + :param str iter_type: The type of object in the iterable. + :return: Deserialized iterable. + :rtype: list + """ + if attr is None: + return None + if isinstance(attr, ET.Element): # If I receive an element here, get the children + attr = list(attr) + if not isinstance(attr, (list, set)): + raise DeserializationError("Cannot deserialize as [{}] an object of type {}".format(iter_type, type(attr))) + return [self.deserialize_data(a, iter_type) for a in attr] + + def deserialize_dict(self, attr, dict_type): + """Deserialize a dictionary. + + :param dict/list attr: Dictionary to be deserialized. Also accepts + a list of key, value pairs. + :param str dict_type: The object type of the items in the dictionary. + :return: Deserialized dictionary. + :rtype: dict + """ + if isinstance(attr, list): + return {x["key"]: self.deserialize_data(x["value"], dict_type) for x in attr} + + if isinstance(attr, ET.Element): + # Transform value into {"Key": "value"} + attr = {el.tag: el.text for el in attr} + return {k: self.deserialize_data(v, dict_type) for k, v in attr.items()} + + def deserialize_object(self, attr, **kwargs): # pylint: disable=too-many-return-statements + """Deserialize a generic object. + This will be handled as a dictionary. + + :param dict attr: Dictionary to be deserialized. + :return: Deserialized object. + :rtype: dict + :raises TypeError: if non-builtin datatype encountered. + """ + if attr is None: + return None + if isinstance(attr, ET.Element): + # Do no recurse on XML, just return the tree as-is + return attr + if isinstance(attr, str): + return self.deserialize_basic(attr, "str") + obj_type = type(attr) + if obj_type in self.basic_types: + return self.deserialize_basic(attr, self.basic_types[obj_type]) + if obj_type is _long_type: + return self.deserialize_long(attr) + + if obj_type == dict: + deserialized = {} + for key, value in attr.items(): + try: + deserialized[key] = self.deserialize_object(value, **kwargs) + except ValueError: + deserialized[key] = None + return deserialized + + if obj_type == list: + deserialized = [] + for obj in attr: + try: + deserialized.append(self.deserialize_object(obj, **kwargs)) + except ValueError: + pass + return deserialized + + error = "Cannot deserialize generic object with type: " + raise TypeError(error + str(obj_type)) + + def deserialize_basic(self, attr, data_type): # pylint: disable=too-many-return-statements + """Deserialize basic builtin data type from string. + Will attempt to convert to str, int, float and bool. + This function will also accept '1', '0', 'true' and 'false' as + valid bool values. + + :param str attr: response string to be deserialized. + :param str data_type: deserialization data type. + :return: Deserialized basic type. + :rtype: str, int, float or bool + :raises TypeError: if string format is not valid. + """ + # If we're here, data is supposed to be a basic type. + # If it's still an XML node, take the text + if isinstance(attr, ET.Element): + attr = attr.text + if not attr: + if data_type == "str": + # None or '', node is empty string. + return "" + # None or '', node with a strong type is None. + # Don't try to model "empty bool" or "empty int" + return None + + if data_type == "bool": + if attr in [True, False, 1, 0]: + return bool(attr) + if isinstance(attr, str): + if attr.lower() in ["true", "1"]: + return True + if attr.lower() in ["false", "0"]: + return False + raise TypeError("Invalid boolean value: {}".format(attr)) + + if data_type == "str": + return self.deserialize_unicode(attr) + return eval(data_type)(attr) # nosec # pylint: disable=eval-used + + @staticmethod + def deserialize_unicode(data): + """Preserve unicode objects in Python 2, otherwise return data + as a string. + + :param str data: response string to be deserialized. + :return: Deserialized string. + :rtype: str or unicode + """ + # We might be here because we have an enum modeled as string, + # and we try to deserialize a partial dict with enum inside + if isinstance(data, Enum): + return data + + # Consider this is real string + try: + if isinstance(data, unicode): # type: ignore + return data + except NameError: + return str(data) + return str(data) + + @staticmethod + def deserialize_enum(data, enum_obj): + """Deserialize string into enum object. + + If the string is not a valid enum value it will be returned as-is + and a warning will be logged. + + :param str data: Response string to be deserialized. If this value is + None or invalid it will be returned as-is. + :param Enum enum_obj: Enum object to deserialize to. + :return: Deserialized enum object. + :rtype: Enum + """ + if isinstance(data, enum_obj) or data is None: + return data + if isinstance(data, Enum): + data = data.value + if isinstance(data, int): + # Workaround. We might consider remove it in the future. + try: + return list(enum_obj.__members__.values())[data] + except IndexError as exc: + error = "{!r} is not a valid index for enum {!r}" + raise DeserializationError(error.format(data, enum_obj)) from exc + try: + return enum_obj(str(data)) + except ValueError: + for enum_value in enum_obj: + if enum_value.value.lower() == str(data).lower(): + return enum_value + # We don't fail anymore for unknown value, we deserialize as a string + _LOGGER.warning("Deserializer is not able to find %s as valid enum in %s", data, enum_obj) + return Deserializer.deserialize_unicode(data) + + @staticmethod + def deserialize_bytearray(attr): + """Deserialize string into bytearray. + + :param str attr: response string to be deserialized. + :return: Deserialized bytearray + :rtype: bytearray + :raises TypeError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + return bytearray(b64decode(attr)) # type: ignore + + @staticmethod + def deserialize_base64(attr): + """Deserialize base64 encoded string into string. + + :param str attr: response string to be deserialized. + :return: Deserialized base64 string + :rtype: bytearray + :raises TypeError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + padding = "=" * (3 - (len(attr) + 3) % 4) # type: ignore + attr = attr + padding # type: ignore + encoded = attr.replace("-", "+").replace("_", "/") + return b64decode(encoded) + + @staticmethod + def deserialize_decimal(attr): + """Deserialize string into Decimal object. + + :param str attr: response string to be deserialized. + :return: Deserialized decimal + :raises DeserializationError: if string format invalid. + :rtype: decimal + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + return decimal.Decimal(str(attr)) # type: ignore + except decimal.DecimalException as err: + msg = "Invalid decimal {}".format(attr) + raise DeserializationError(msg) from err + + @staticmethod + def deserialize_long(attr): + """Deserialize string into long (Py2) or int (Py3). + + :param str attr: response string to be deserialized. + :return: Deserialized int + :rtype: long or int + :raises ValueError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + return _long_type(attr) # type: ignore + + @staticmethod + def deserialize_duration(attr): + """Deserialize ISO-8601 formatted string into TimeDelta object. + + :param str attr: response string to be deserialized. + :return: Deserialized duration + :rtype: TimeDelta + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + duration = isodate.parse_duration(attr) + except (ValueError, OverflowError, AttributeError) as err: + msg = "Cannot deserialize duration object." + raise DeserializationError(msg) from err + return duration + + @staticmethod + def deserialize_date(attr): + """Deserialize ISO-8601 formatted string into Date object. + + :param str attr: response string to be deserialized. + :return: Deserialized date + :rtype: Date + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + if re.search(r"[^\W\d_]", attr, re.I + re.U): # type: ignore + raise DeserializationError("Date must have only digits and -. Received: %s" % attr) + # This must NOT use defaultmonth/defaultday. Using None ensure this raises an exception. + return isodate.parse_date(attr, defaultmonth=0, defaultday=0) + + @staticmethod + def deserialize_time(attr): + """Deserialize ISO-8601 formatted string into time object. + + :param str attr: response string to be deserialized. + :return: Deserialized time + :rtype: datetime.time + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + if re.search(r"[^\W\d_]", attr, re.I + re.U): # type: ignore + raise DeserializationError("Date must have only digits and -. Received: %s" % attr) + return isodate.parse_time(attr) + + @staticmethod + def deserialize_rfc(attr): + """Deserialize RFC-1123 formatted string into Datetime object. + + :param str attr: response string to be deserialized. + :return: Deserialized RFC datetime + :rtype: Datetime + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + parsed_date = email.utils.parsedate_tz(attr) # type: ignore + date_obj = datetime.datetime( + *parsed_date[:6], tzinfo=datetime.timezone(datetime.timedelta(minutes=(parsed_date[9] or 0) / 60)) + ) + if not date_obj.tzinfo: + date_obj = date_obj.astimezone(tz=TZ_UTC) + except ValueError as err: + msg = "Cannot deserialize to rfc datetime object." + raise DeserializationError(msg) from err + return date_obj + + @staticmethod + def deserialize_iso(attr): + """Deserialize ISO-8601 formatted string into Datetime object. + + :param str attr: response string to be deserialized. + :return: Deserialized ISO datetime + :rtype: Datetime + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + attr = attr.upper() # type: ignore + match = Deserializer.valid_date.match(attr) + if not match: + raise ValueError("Invalid datetime string: " + attr) + + check_decimal = attr.split(".") + if len(check_decimal) > 1: + decimal_str = "" + for digit in check_decimal[1]: + if digit.isdigit(): + decimal_str += digit + else: + break + if len(decimal_str) > 6: + attr = attr.replace(decimal_str, decimal_str[0:6]) + + date_obj = isodate.parse_datetime(attr) + test_utc = date_obj.utctimetuple() + if test_utc.tm_year > 9999 or test_utc.tm_year < 1: + raise OverflowError("Hit max or min date") + except (ValueError, OverflowError, AttributeError) as err: + msg = "Cannot deserialize datetime object." + raise DeserializationError(msg) from err + return date_obj + + @staticmethod + def deserialize_unix(attr): + """Serialize Datetime object into IntTime format. + This is represented as seconds. + + :param int attr: Object to be serialized. + :return: Deserialized datetime + :rtype: Datetime + :raises DeserializationError: if format invalid + """ + if isinstance(attr, ET.Element): + attr = int(attr.text) # type: ignore + try: + attr = int(attr) + date_obj = datetime.datetime.fromtimestamp(attr, TZ_UTC) + except ValueError as err: + msg = "Cannot deserialize to unix datetime object." + raise DeserializationError(msg) from err + return date_obj diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiWithSubmodule/multiapiwithsubmodule/submodule/aio/_multiapi_service_client.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiWithSubmodule/multiapiwithsubmodule/submodule/aio/_multiapi_service_client.py index 4dce1ff5a09..476229fa824 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiWithSubmodule/multiapiwithsubmodule/submodule/aio/_multiapi_service_client.py +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiWithSubmodule/multiapiwithsubmodule/submodule/aio/_multiapi_service_client.py @@ -20,7 +20,7 @@ from azure.profiles import KnownProfiles, ProfileDefinition from azure.profiles.multiapiclient import MultiApiClientMixin -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import MultiapiServiceClientConfiguration from ._operations_mixin import MultiapiServiceClientOperationsMixin diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiWithSubmodule/multiapiwithsubmodule/submodule/aio/_operations_mixin.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiWithSubmodule/multiapiwithsubmodule/submodule/aio/_operations_mixin.py index 4cd54f84d22..0c8e9b3f9e7 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiWithSubmodule/multiapiwithsubmodule/submodule/aio/_operations_mixin.py +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiWithSubmodule/multiapiwithsubmodule/submodule/aio/_operations_mixin.py @@ -8,7 +8,7 @@ # Changes may cause incorrect behavior and will be lost if the code is # regenerated. # -------------------------------------------------------------------------- -from .._serialization import Serializer, Deserializer +from .._utils.serialization import Serializer, Deserializer from io import IOBase from typing import Any, AsyncIterable, AsyncIterator, IO, Optional, Union diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiWithSubmodule/multiapiwithsubmodule/submodule/v1/_metadata.json b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiWithSubmodule/multiapiwithsubmodule/submodule/v1/_metadata.json index 7f0c01d0ca9..81eaf380600 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiWithSubmodule/multiapiwithsubmodule/submodule/v1/_metadata.json +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiWithSubmodule/multiapiwithsubmodule/submodule/v1/_metadata.json @@ -10,8 +10,8 @@ "azure_arm": true, "has_public_lro_operations": true, "client_side_validation": false, - "sync_imports": "{\"conditional\": {\"stdlib\": {\"typing\": [\"Any\", \"Optional\"]}}, \"regular\": {\"sdkcore\": {\"azure.mgmt.core\": [\"ARMPipelineClient\"], \"azure.core.pipeline\": [\"policies\"], \"azure.mgmt.core.policies\": [\"ARMAutoResourceProviderRegistrationPolicy\"], \"azure.core.settings\": [\"settings\"], \"azure.mgmt.core.tools\": [\"get_arm_endpoints\"], \"azure.profiles\": [\"KnownProfiles\", \"ProfileDefinition\"], \"azure.profiles.multiapiclient\": [\"MultiApiClientMixin\"]}, \"stdlib\": {\"typing\": [\"Optional\", \"cast\"], \"typing_extensions\": [\"Self\"]}, \"local\": {\"._configuration\": [\"MultiapiServiceClientConfiguration\"], \".._serialization\": [\"Deserializer\", \"Serializer\"], \"._operations_mixin\": [\"MultiapiServiceClientOperationsMixin\"]}}, \"typing\": {\"sdkcore\": {\"azure.core.credentials\": [\"TokenCredential\"]}}}", - "async_imports": "{\"conditional\": {\"stdlib\": {\"typing\": [\"Any\", \"Optional\"]}}, \"regular\": {\"sdkcore\": {\"azure.mgmt.core\": [\"AsyncARMPipelineClient\"], \"azure.core.pipeline\": [\"policies\"], \"azure.mgmt.core.policies\": [\"AsyncARMAutoResourceProviderRegistrationPolicy\"], \"azure.core.settings\": [\"settings\"], \"azure.mgmt.core.tools\": [\"get_arm_endpoints\"], \"azure.profiles\": [\"KnownProfiles\", \"ProfileDefinition\"], \"azure.profiles.multiapiclient\": [\"MultiApiClientMixin\"]}, \"stdlib\": {\"typing\": [\"Optional\", \"cast\"], \"typing_extensions\": [\"Self\"]}, \"local\": {\"._configuration\": [\"MultiapiServiceClientConfiguration\"], \"..._serialization\": [\"Deserializer\", \"Serializer\"], \"._operations_mixin\": [\"MultiapiServiceClientOperationsMixin\"]}}, \"typing\": {\"sdkcore\": {\"azure.core.credentials_async\": [\"AsyncTokenCredential\"]}}}" + "sync_imports": "{\"conditional\": {\"stdlib\": {\"typing\": [\"Any\", \"Optional\"]}}, \"regular\": {\"sdkcore\": {\"azure.mgmt.core\": [\"ARMPipelineClient\"], \"azure.core.pipeline\": [\"policies\"], \"azure.mgmt.core.policies\": [\"ARMAutoResourceProviderRegistrationPolicy\"], \"azure.core.settings\": [\"settings\"], \"azure.mgmt.core.tools\": [\"get_arm_endpoints\"], \"azure.profiles\": [\"KnownProfiles\", \"ProfileDefinition\"], \"azure.profiles.multiapiclient\": [\"MultiApiClientMixin\"]}, \"stdlib\": {\"typing\": [\"Optional\", \"cast\"], \"typing_extensions\": [\"Self\"]}, \"local\": {\"._configuration\": [\"MultiapiServiceClientConfiguration\"], \"._utils.serialization\": [\"Deserializer\", \"Serializer\"], \"._operations_mixin\": [\"MultiapiServiceClientOperationsMixin\"]}}, \"typing\": {\"sdkcore\": {\"azure.core.credentials\": [\"TokenCredential\"]}}}", + "async_imports": "{\"conditional\": {\"stdlib\": {\"typing\": [\"Any\", \"Optional\"]}}, \"regular\": {\"sdkcore\": {\"azure.mgmt.core\": [\"AsyncARMPipelineClient\"], \"azure.core.pipeline\": [\"policies\"], \"azure.mgmt.core.policies\": [\"AsyncARMAutoResourceProviderRegistrationPolicy\"], \"azure.core.settings\": [\"settings\"], \"azure.mgmt.core.tools\": [\"get_arm_endpoints\"], \"azure.profiles\": [\"KnownProfiles\", \"ProfileDefinition\"], \"azure.profiles.multiapiclient\": [\"MultiApiClientMixin\"]}, \"stdlib\": {\"typing\": [\"Optional\", \"cast\"], \"typing_extensions\": [\"Self\"]}, \"local\": {\"._configuration\": [\"MultiapiServiceClientConfiguration\"], \".._utils.serialization\": [\"Deserializer\", \"Serializer\"], \"._operations_mixin\": [\"MultiapiServiceClientOperationsMixin\"]}}, \"typing\": {\"sdkcore\": {\"azure.core.credentials_async\": [\"AsyncTokenCredential\"]}}}" }, "global_parameters": { "sync": { diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiWithSubmodule/multiapiwithsubmodule/submodule/v1/_multiapi_service_client.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiWithSubmodule/multiapiwithsubmodule/submodule/v1/_multiapi_service_client.py index 58558aab795..c474e81ef92 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiWithSubmodule/multiapiwithsubmodule/submodule/v1/_multiapi_service_client.py +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiWithSubmodule/multiapiwithsubmodule/submodule/v1/_multiapi_service_client.py @@ -18,8 +18,8 @@ from azure.mgmt.core.tools import get_arm_endpoints from . import models as _models -from .._serialization import Deserializer, Serializer from ._configuration import MultiapiServiceClientConfiguration +from ._utils.serialization import Deserializer, Serializer from .operations import MultiapiServiceClientOperationsMixin, OperationGroupOneOperations if TYPE_CHECKING: diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiWithSubmodule/multiapiwithsubmodule/submodule/v1/_utils/__init__.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiWithSubmodule/multiapiwithsubmodule/submodule/v1/_utils/__init__.py new file mode 100644 index 00000000000..0af9b28f660 --- /dev/null +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiWithSubmodule/multiapiwithsubmodule/submodule/v1/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/NonStringEnums/nonstringenums/_serialization.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiWithSubmodule/multiapiwithsubmodule/submodule/v1/_utils/serialization.py similarity index 100% rename from packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/NonStringEnums/nonstringenums/_serialization.py rename to packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiWithSubmodule/multiapiwithsubmodule/submodule/v1/_utils/serialization.py diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiWithSubmodule/multiapiwithsubmodule/submodule/v1/_utils/utils.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiWithSubmodule/multiapiwithsubmodule/submodule/v1/_utils/utils.py new file mode 100644 index 00000000000..39b612f39a9 --- /dev/null +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiWithSubmodule/multiapiwithsubmodule/submodule/v1/_utils/utils.py @@ -0,0 +1,25 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from abc import ABC +from typing import Generic, TYPE_CHECKING, TypeVar + +if TYPE_CHECKING: + from .serialization import Deserializer, Serializer + + +TClient = TypeVar("TClient") +TConfig = TypeVar("TConfig") + + +class ClientMixinABC(ABC, Generic[TClient, TConfig]): + """DO NOT use this class. It is for internal typing use only.""" + + _client: TClient + _config: TConfig + _serialize: "Serializer" + _deserialize: "Deserializer" diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiWithSubmodule/multiapiwithsubmodule/submodule/v1/_vendor.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiWithSubmodule/multiapiwithsubmodule/submodule/v1/_vendor.py deleted file mode 100644 index 70517e0b7af..00000000000 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiWithSubmodule/multiapiwithsubmodule/submodule/v1/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) AutoRest Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import MultiapiServiceClientConfiguration - -if TYPE_CHECKING: - from azure.core import PipelineClient - - from .._serialization import Deserializer, Serializer - - -class MultiapiServiceClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "PipelineClient" - _config: MultiapiServiceClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiWithSubmodule/multiapiwithsubmodule/submodule/v1/aio/_multiapi_service_client.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiWithSubmodule/multiapiwithsubmodule/submodule/v1/aio/_multiapi_service_client.py index acbb6759b54..c44779221e8 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiWithSubmodule/multiapiwithsubmodule/submodule/v1/aio/_multiapi_service_client.py +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiWithSubmodule/multiapiwithsubmodule/submodule/v1/aio/_multiapi_service_client.py @@ -18,7 +18,7 @@ from azure.mgmt.core.tools import get_arm_endpoints from .. import models as _models -from ..._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import MultiapiServiceClientConfiguration from .operations import MultiapiServiceClientOperationsMixin, OperationGroupOneOperations diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiWithSubmodule/multiapiwithsubmodule/submodule/v1/aio/_vendor.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiWithSubmodule/multiapiwithsubmodule/submodule/v1/aio/_vendor.py deleted file mode 100644 index 9c6fd05bb21..00000000000 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiWithSubmodule/multiapiwithsubmodule/submodule/v1/aio/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) AutoRest Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import MultiapiServiceClientConfiguration - -if TYPE_CHECKING: - from azure.core import AsyncPipelineClient - - from ..._serialization import Deserializer, Serializer - - -class MultiapiServiceClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "AsyncPipelineClient" - _config: MultiapiServiceClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiWithSubmodule/multiapiwithsubmodule/submodule/v1/aio/operations/_multiapi_service_client_operations.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiWithSubmodule/multiapiwithsubmodule/submodule/v1/aio/operations/_multiapi_service_client_operations.py index 15d12f2dfbb..1c1abc8e81c 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiWithSubmodule/multiapiwithsubmodule/submodule/v1/aio/operations/_multiapi_service_client_operations.py +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiWithSubmodule/multiapiwithsubmodule/submodule/v1/aio/operations/_multiapi_service_client_operations.py @@ -11,6 +11,7 @@ from typing import Any, AsyncIterable, AsyncIterator, Callable, Dict, IO, Optional, TypeVar, Union, cast, overload import urllib.parse +from azure.core import AsyncPipelineClient from azure.core.async_paging import AsyncItemPaged, AsyncList from azure.core.exceptions import ( ClientAuthenticationError, @@ -32,19 +33,20 @@ from azure.mgmt.core.polling.async_arm_polling import AsyncARMPolling from ... import models as _models +from ..._utils.utils import ClientMixinABC from ...operations._multiapi_service_client_operations import ( build_test_different_calls_request, build_test_lro_and_paging_request, build_test_lro_request, build_test_one_request, ) -from .._vendor import MultiapiServiceClientMixinABC +from .._configuration import MultiapiServiceClientConfiguration T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, AsyncHttpResponse], T, Dict[str, Any]], Any]] -class MultiapiServiceClientOperationsMixin(MultiapiServiceClientMixinABC): +class MultiapiServiceClientOperationsMixin(ClientMixinABC[AsyncPipelineClient, MultiapiServiceClientConfiguration]): def _api_version(self, op_name: str) -> str: # pylint: disable=unused-argument try: return self._config.api_version diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiWithSubmodule/multiapiwithsubmodule/submodule/v1/aio/operations/_operation_group_one_operations.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiWithSubmodule/multiapiwithsubmodule/submodule/v1/aio/operations/_operation_group_one_operations.py index 20f69dbcf28..8a9a62edd42 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiWithSubmodule/multiapiwithsubmodule/submodule/v1/aio/operations/_operation_group_one_operations.py +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiWithSubmodule/multiapiwithsubmodule/submodule/v1/aio/operations/_operation_group_one_operations.py @@ -24,7 +24,7 @@ from azure.mgmt.core.exceptions import ARMErrorFormat from ... import models as _models -from ...._serialization import Deserializer, Serializer +from ..._utils.serialization import Deserializer, Serializer from ...operations._operation_group_one_operations import build_test_two_request from .._configuration import MultiapiServiceClientConfiguration diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiWithSubmodule/multiapiwithsubmodule/submodule/v1/models/_models_py3.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiWithSubmodule/multiapiwithsubmodule/submodule/v1/models/_models_py3.py index cbc5fbd265b..89ad9df253a 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiWithSubmodule/multiapiwithsubmodule/submodule/v1/models/_models_py3.py +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiWithSubmodule/multiapiwithsubmodule/submodule/v1/models/_models_py3.py @@ -8,7 +8,7 @@ from typing import Any, List, Optional, TYPE_CHECKING -from ... import _serialization +from .._utils import serialization as _serialization if TYPE_CHECKING: from .. import models as _models diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiWithSubmodule/multiapiwithsubmodule/submodule/v1/operations/_multiapi_service_client_operations.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiWithSubmodule/multiapiwithsubmodule/submodule/v1/operations/_multiapi_service_client_operations.py index 2fbd75acfc7..80f7596c452 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiWithSubmodule/multiapiwithsubmodule/submodule/v1/operations/_multiapi_service_client_operations.py +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiWithSubmodule/multiapiwithsubmodule/submodule/v1/operations/_multiapi_service_client_operations.py @@ -10,6 +10,7 @@ from typing import Any, Callable, Dict, IO, Iterable, Iterator, Optional, TypeVar, Union, cast, overload import urllib.parse +from azure.core import PipelineClient from azure.core.exceptions import ( ClientAuthenticationError, HttpResponseError, @@ -30,8 +31,9 @@ from azure.mgmt.core.polling.arm_polling import ARMPolling from .. import models as _models -from ..._serialization import Serializer -from .._vendor import MultiapiServiceClientMixinABC +from .._configuration import MultiapiServiceClientConfiguration +from .._utils.serialization import Serializer +from .._utils.utils import ClientMixinABC T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] @@ -121,7 +123,7 @@ def build_test_different_calls_request(*, greeting_in_english: str, **kwargs: An return HttpRequest(method="GET", url=_url, params=_params, headers=_headers, **kwargs) -class MultiapiServiceClientOperationsMixin(MultiapiServiceClientMixinABC): +class MultiapiServiceClientOperationsMixin(ClientMixinABC[PipelineClient, MultiapiServiceClientConfiguration]): def _api_version(self, op_name: str) -> str: # pylint: disable=unused-argument try: return self._config.api_version diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiWithSubmodule/multiapiwithsubmodule/submodule/v1/operations/_operation_group_one_operations.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiWithSubmodule/multiapiwithsubmodule/submodule/v1/operations/_operation_group_one_operations.py index 39dfd8a43c1..33fb755f911 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiWithSubmodule/multiapiwithsubmodule/submodule/v1/operations/_operation_group_one_operations.py +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiWithSubmodule/multiapiwithsubmodule/submodule/v1/operations/_operation_group_one_operations.py @@ -24,8 +24,8 @@ from azure.mgmt.core.exceptions import ARMErrorFormat from .. import models as _models -from ..._serialization import Deserializer, Serializer from .._configuration import MultiapiServiceClientConfiguration +from .._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiWithSubmodule/multiapiwithsubmodule/submodule/v2/_metadata.json b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiWithSubmodule/multiapiwithsubmodule/submodule/v2/_metadata.json index 8791ef7dd53..742314809e9 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiWithSubmodule/multiapiwithsubmodule/submodule/v2/_metadata.json +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiWithSubmodule/multiapiwithsubmodule/submodule/v2/_metadata.json @@ -10,8 +10,8 @@ "azure_arm": true, "has_public_lro_operations": false, "client_side_validation": false, - "sync_imports": "{\"conditional\": {\"stdlib\": {\"typing\": [\"Any\", \"Optional\"]}}, \"regular\": {\"sdkcore\": {\"azure.mgmt.core\": [\"ARMPipelineClient\"], \"azure.core.pipeline\": [\"policies\"], \"azure.mgmt.core.policies\": [\"ARMAutoResourceProviderRegistrationPolicy\"], \"azure.core.settings\": [\"settings\"], \"azure.mgmt.core.tools\": [\"get_arm_endpoints\"], \"azure.profiles\": [\"KnownProfiles\", \"ProfileDefinition\"], \"azure.profiles.multiapiclient\": [\"MultiApiClientMixin\"]}, \"stdlib\": {\"typing\": [\"Optional\", \"cast\"], \"typing_extensions\": [\"Self\"]}, \"local\": {\"._configuration\": [\"MultiapiServiceClientConfiguration\"], \".._serialization\": [\"Deserializer\", \"Serializer\"], \"._operations_mixin\": [\"MultiapiServiceClientOperationsMixin\"]}}, \"typing\": {\"sdkcore\": {\"azure.core.credentials\": [\"TokenCredential\"]}}}", - "async_imports": "{\"conditional\": {\"stdlib\": {\"typing\": [\"Any\", \"Optional\"]}}, \"regular\": {\"sdkcore\": {\"azure.mgmt.core\": [\"AsyncARMPipelineClient\"], \"azure.core.pipeline\": [\"policies\"], \"azure.mgmt.core.policies\": [\"AsyncARMAutoResourceProviderRegistrationPolicy\"], \"azure.core.settings\": [\"settings\"], \"azure.mgmt.core.tools\": [\"get_arm_endpoints\"], \"azure.profiles\": [\"KnownProfiles\", \"ProfileDefinition\"], \"azure.profiles.multiapiclient\": [\"MultiApiClientMixin\"]}, \"stdlib\": {\"typing\": [\"Optional\", \"cast\"], \"typing_extensions\": [\"Self\"]}, \"local\": {\"._configuration\": [\"MultiapiServiceClientConfiguration\"], \"..._serialization\": [\"Deserializer\", \"Serializer\"], \"._operations_mixin\": [\"MultiapiServiceClientOperationsMixin\"]}}, \"typing\": {\"sdkcore\": {\"azure.core.credentials_async\": [\"AsyncTokenCredential\"]}}}" + "sync_imports": "{\"conditional\": {\"stdlib\": {\"typing\": [\"Any\", \"Optional\"]}}, \"regular\": {\"sdkcore\": {\"azure.mgmt.core\": [\"ARMPipelineClient\"], \"azure.core.pipeline\": [\"policies\"], \"azure.mgmt.core.policies\": [\"ARMAutoResourceProviderRegistrationPolicy\"], \"azure.core.settings\": [\"settings\"], \"azure.mgmt.core.tools\": [\"get_arm_endpoints\"], \"azure.profiles\": [\"KnownProfiles\", \"ProfileDefinition\"], \"azure.profiles.multiapiclient\": [\"MultiApiClientMixin\"]}, \"stdlib\": {\"typing\": [\"Optional\", \"cast\"], \"typing_extensions\": [\"Self\"]}, \"local\": {\"._configuration\": [\"MultiapiServiceClientConfiguration\"], \"._utils.serialization\": [\"Deserializer\", \"Serializer\"], \"._operations_mixin\": [\"MultiapiServiceClientOperationsMixin\"]}}, \"typing\": {\"sdkcore\": {\"azure.core.credentials\": [\"TokenCredential\"]}}}", + "async_imports": "{\"conditional\": {\"stdlib\": {\"typing\": [\"Any\", \"Optional\"]}}, \"regular\": {\"sdkcore\": {\"azure.mgmt.core\": [\"AsyncARMPipelineClient\"], \"azure.core.pipeline\": [\"policies\"], \"azure.mgmt.core.policies\": [\"AsyncARMAutoResourceProviderRegistrationPolicy\"], \"azure.core.settings\": [\"settings\"], \"azure.mgmt.core.tools\": [\"get_arm_endpoints\"], \"azure.profiles\": [\"KnownProfiles\", \"ProfileDefinition\"], \"azure.profiles.multiapiclient\": [\"MultiApiClientMixin\"]}, \"stdlib\": {\"typing\": [\"Optional\", \"cast\"], \"typing_extensions\": [\"Self\"]}, \"local\": {\"._configuration\": [\"MultiapiServiceClientConfiguration\"], \".._utils.serialization\": [\"Deserializer\", \"Serializer\"], \"._operations_mixin\": [\"MultiapiServiceClientOperationsMixin\"]}}, \"typing\": {\"sdkcore\": {\"azure.core.credentials_async\": [\"AsyncTokenCredential\"]}}}" }, "global_parameters": { "sync": { diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiWithSubmodule/multiapiwithsubmodule/submodule/v2/_multiapi_service_client.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiWithSubmodule/multiapiwithsubmodule/submodule/v2/_multiapi_service_client.py index c7d0fdf0ec8..5ca1e81e782 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiWithSubmodule/multiapiwithsubmodule/submodule/v2/_multiapi_service_client.py +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiWithSubmodule/multiapiwithsubmodule/submodule/v2/_multiapi_service_client.py @@ -18,8 +18,8 @@ from azure.mgmt.core.tools import get_arm_endpoints from . import models as _models -from .._serialization import Deserializer, Serializer from ._configuration import MultiapiServiceClientConfiguration +from ._utils.serialization import Deserializer, Serializer from .operations import MultiapiServiceClientOperationsMixin, OperationGroupOneOperations, OperationGroupTwoOperations if TYPE_CHECKING: diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiWithSubmodule/multiapiwithsubmodule/submodule/v2/_utils/__init__.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiWithSubmodule/multiapiwithsubmodule/submodule/v2/_utils/__init__.py new file mode 100644 index 00000000000..0af9b28f660 --- /dev/null +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiWithSubmodule/multiapiwithsubmodule/submodule/v2/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ObjectType/objecttype/_serialization.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiWithSubmodule/multiapiwithsubmodule/submodule/v2/_utils/serialization.py similarity index 100% rename from packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ObjectType/objecttype/_serialization.py rename to packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiWithSubmodule/multiapiwithsubmodule/submodule/v2/_utils/serialization.py diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiWithSubmodule/multiapiwithsubmodule/submodule/v2/_utils/utils.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiWithSubmodule/multiapiwithsubmodule/submodule/v2/_utils/utils.py new file mode 100644 index 00000000000..39b612f39a9 --- /dev/null +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiWithSubmodule/multiapiwithsubmodule/submodule/v2/_utils/utils.py @@ -0,0 +1,25 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from abc import ABC +from typing import Generic, TYPE_CHECKING, TypeVar + +if TYPE_CHECKING: + from .serialization import Deserializer, Serializer + + +TClient = TypeVar("TClient") +TConfig = TypeVar("TConfig") + + +class ClientMixinABC(ABC, Generic[TClient, TConfig]): + """DO NOT use this class. It is for internal typing use only.""" + + _client: TClient + _config: TConfig + _serialize: "Serializer" + _deserialize: "Deserializer" diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiWithSubmodule/multiapiwithsubmodule/submodule/v2/_vendor.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiWithSubmodule/multiapiwithsubmodule/submodule/v2/_vendor.py deleted file mode 100644 index 70517e0b7af..00000000000 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiWithSubmodule/multiapiwithsubmodule/submodule/v2/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) AutoRest Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import MultiapiServiceClientConfiguration - -if TYPE_CHECKING: - from azure.core import PipelineClient - - from .._serialization import Deserializer, Serializer - - -class MultiapiServiceClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "PipelineClient" - _config: MultiapiServiceClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiWithSubmodule/multiapiwithsubmodule/submodule/v2/aio/_multiapi_service_client.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiWithSubmodule/multiapiwithsubmodule/submodule/v2/aio/_multiapi_service_client.py index 5d82132928c..15b2874aded 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiWithSubmodule/multiapiwithsubmodule/submodule/v2/aio/_multiapi_service_client.py +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiWithSubmodule/multiapiwithsubmodule/submodule/v2/aio/_multiapi_service_client.py @@ -18,7 +18,7 @@ from azure.mgmt.core.tools import get_arm_endpoints from .. import models as _models -from ..._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import MultiapiServiceClientConfiguration from .operations import MultiapiServiceClientOperationsMixin, OperationGroupOneOperations, OperationGroupTwoOperations diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiWithSubmodule/multiapiwithsubmodule/submodule/v2/aio/_vendor.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiWithSubmodule/multiapiwithsubmodule/submodule/v2/aio/_vendor.py deleted file mode 100644 index 9c6fd05bb21..00000000000 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiWithSubmodule/multiapiwithsubmodule/submodule/v2/aio/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) AutoRest Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import MultiapiServiceClientConfiguration - -if TYPE_CHECKING: - from azure.core import AsyncPipelineClient - - from ..._serialization import Deserializer, Serializer - - -class MultiapiServiceClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "AsyncPipelineClient" - _config: MultiapiServiceClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiWithSubmodule/multiapiwithsubmodule/submodule/v2/aio/operations/_multiapi_service_client_operations.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiWithSubmodule/multiapiwithsubmodule/submodule/v2/aio/operations/_multiapi_service_client_operations.py index 1c1f6c1dec1..1f54b726312 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiWithSubmodule/multiapiwithsubmodule/submodule/v2/aio/operations/_multiapi_service_client_operations.py +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiWithSubmodule/multiapiwithsubmodule/submodule/v2/aio/operations/_multiapi_service_client_operations.py @@ -9,6 +9,7 @@ from collections.abc import MutableMapping from typing import Any, Callable, Dict, Optional, TypeVar +from azure.core import AsyncPipelineClient from azure.core.exceptions import ( ClientAuthenticationError, HttpResponseError, @@ -24,14 +25,15 @@ from azure.mgmt.core.exceptions import ARMErrorFormat from ... import models as _models +from ..._utils.utils import ClientMixinABC from ...operations._multiapi_service_client_operations import build_test_different_calls_request, build_test_one_request -from .._vendor import MultiapiServiceClientMixinABC +from .._configuration import MultiapiServiceClientConfiguration T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, AsyncHttpResponse], T, Dict[str, Any]], Any]] -class MultiapiServiceClientOperationsMixin(MultiapiServiceClientMixinABC): +class MultiapiServiceClientOperationsMixin(ClientMixinABC[AsyncPipelineClient, MultiapiServiceClientConfiguration]): def _api_version(self, op_name: str) -> str: # pylint: disable=unused-argument try: return self._config.api_version diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiWithSubmodule/multiapiwithsubmodule/submodule/v2/aio/operations/_operation_group_one_operations.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiWithSubmodule/multiapiwithsubmodule/submodule/v2/aio/operations/_operation_group_one_operations.py index 12736314957..fcd3097bafc 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiWithSubmodule/multiapiwithsubmodule/submodule/v2/aio/operations/_operation_group_one_operations.py +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiWithSubmodule/multiapiwithsubmodule/submodule/v2/aio/operations/_operation_group_one_operations.py @@ -25,7 +25,7 @@ from azure.mgmt.core.exceptions import ARMErrorFormat from ... import models as _models -from ...._serialization import Deserializer, Serializer +from ..._utils.serialization import Deserializer, Serializer from ...operations._operation_group_one_operations import build_test_three_request, build_test_two_request from .._configuration import MultiapiServiceClientConfiguration diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiWithSubmodule/multiapiwithsubmodule/submodule/v2/aio/operations/_operation_group_two_operations.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiWithSubmodule/multiapiwithsubmodule/submodule/v2/aio/operations/_operation_group_two_operations.py index bf392fe2370..9d9495d9cee 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiWithSubmodule/multiapiwithsubmodule/submodule/v2/aio/operations/_operation_group_two_operations.py +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiWithSubmodule/multiapiwithsubmodule/submodule/v2/aio/operations/_operation_group_two_operations.py @@ -24,7 +24,7 @@ from azure.mgmt.core.exceptions import ARMErrorFormat from ... import models as _models -from ...._serialization import Deserializer, Serializer +from ..._utils.serialization import Deserializer, Serializer from ...operations._operation_group_two_operations import build_test_four_request from .._configuration import MultiapiServiceClientConfiguration diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiWithSubmodule/multiapiwithsubmodule/submodule/v2/models/_models_py3.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiWithSubmodule/multiapiwithsubmodule/submodule/v2/models/_models_py3.py index 46990252065..a00726a3da2 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiWithSubmodule/multiapiwithsubmodule/submodule/v2/models/_models_py3.py +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiWithSubmodule/multiapiwithsubmodule/submodule/v2/models/_models_py3.py @@ -8,7 +8,7 @@ from typing import Any, Optional -from ... import _serialization +from .._utils import serialization as _serialization class Error(_serialization.Model): diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiWithSubmodule/multiapiwithsubmodule/submodule/v2/operations/_multiapi_service_client_operations.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiWithSubmodule/multiapiwithsubmodule/submodule/v2/operations/_multiapi_service_client_operations.py index 37b0bcad371..bc3af687661 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiWithSubmodule/multiapiwithsubmodule/submodule/v2/operations/_multiapi_service_client_operations.py +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiWithSubmodule/multiapiwithsubmodule/submodule/v2/operations/_multiapi_service_client_operations.py @@ -8,6 +8,7 @@ from collections.abc import MutableMapping from typing import Any, Callable, Dict, Optional, TypeVar +from azure.core import PipelineClient from azure.core.exceptions import ( ClientAuthenticationError, HttpResponseError, @@ -23,8 +24,9 @@ from azure.mgmt.core.exceptions import ARMErrorFormat from .. import models as _models -from ..._serialization import Serializer -from .._vendor import MultiapiServiceClientMixinABC +from .._configuration import MultiapiServiceClientConfiguration +from .._utils.serialization import Serializer +from .._utils.utils import ClientMixinABC T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] @@ -79,7 +81,7 @@ def build_test_different_calls_request( return HttpRequest(method="GET", url=_url, params=_params, headers=_headers, **kwargs) -class MultiapiServiceClientOperationsMixin(MultiapiServiceClientMixinABC): +class MultiapiServiceClientOperationsMixin(ClientMixinABC[PipelineClient, MultiapiServiceClientConfiguration]): def _api_version(self, op_name: str) -> str: # pylint: disable=unused-argument try: return self._config.api_version diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiWithSubmodule/multiapiwithsubmodule/submodule/v2/operations/_operation_group_one_operations.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiWithSubmodule/multiapiwithsubmodule/submodule/v2/operations/_operation_group_one_operations.py index 942bc64589c..215f5efe447 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiWithSubmodule/multiapiwithsubmodule/submodule/v2/operations/_operation_group_one_operations.py +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiWithSubmodule/multiapiwithsubmodule/submodule/v2/operations/_operation_group_one_operations.py @@ -25,8 +25,8 @@ from azure.mgmt.core.exceptions import ARMErrorFormat from .. import models as _models -from ..._serialization import Deserializer, Serializer from .._configuration import MultiapiServiceClientConfiguration +from .._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiWithSubmodule/multiapiwithsubmodule/submodule/v2/operations/_operation_group_two_operations.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiWithSubmodule/multiapiwithsubmodule/submodule/v2/operations/_operation_group_two_operations.py index 180d5814141..7ad3c39a269 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiWithSubmodule/multiapiwithsubmodule/submodule/v2/operations/_operation_group_two_operations.py +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiWithSubmodule/multiapiwithsubmodule/submodule/v2/operations/_operation_group_two_operations.py @@ -24,8 +24,8 @@ from azure.mgmt.core.exceptions import ARMErrorFormat from .. import models as _models -from ..._serialization import Deserializer, Serializer from .._configuration import MultiapiServiceClientConfiguration +from .._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiWithSubmodule/multiapiwithsubmodule/submodule/v3/_metadata.json b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiWithSubmodule/multiapiwithsubmodule/submodule/v3/_metadata.json index f8f245dbd69..7a6d382829e 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiWithSubmodule/multiapiwithsubmodule/submodule/v3/_metadata.json +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiWithSubmodule/multiapiwithsubmodule/submodule/v3/_metadata.json @@ -10,8 +10,8 @@ "azure_arm": true, "has_public_lro_operations": false, "client_side_validation": false, - "sync_imports": "{\"conditional\": {\"stdlib\": {\"typing\": [\"Any\", \"Optional\"]}}, \"regular\": {\"sdkcore\": {\"azure.mgmt.core\": [\"ARMPipelineClient\"], \"azure.core.pipeline\": [\"policies\"], \"azure.mgmt.core.policies\": [\"ARMAutoResourceProviderRegistrationPolicy\"], \"azure.core.settings\": [\"settings\"], \"azure.mgmt.core.tools\": [\"get_arm_endpoints\"], \"azure.profiles\": [\"KnownProfiles\", \"ProfileDefinition\"], \"azure.profiles.multiapiclient\": [\"MultiApiClientMixin\"]}, \"stdlib\": {\"typing\": [\"Optional\", \"cast\"], \"typing_extensions\": [\"Self\"]}, \"local\": {\"._configuration\": [\"MultiapiServiceClientConfiguration\"], \".._serialization\": [\"Deserializer\", \"Serializer\"], \"._operations_mixin\": [\"MultiapiServiceClientOperationsMixin\"]}}, \"typing\": {\"sdkcore\": {\"azure.core.credentials\": [\"TokenCredential\"]}}}", - "async_imports": "{\"conditional\": {\"stdlib\": {\"typing\": [\"Any\", \"Optional\"]}}, \"regular\": {\"sdkcore\": {\"azure.mgmt.core\": [\"AsyncARMPipelineClient\"], \"azure.core.pipeline\": [\"policies\"], \"azure.mgmt.core.policies\": [\"AsyncARMAutoResourceProviderRegistrationPolicy\"], \"azure.core.settings\": [\"settings\"], \"azure.mgmt.core.tools\": [\"get_arm_endpoints\"], \"azure.profiles\": [\"KnownProfiles\", \"ProfileDefinition\"], \"azure.profiles.multiapiclient\": [\"MultiApiClientMixin\"]}, \"stdlib\": {\"typing\": [\"Optional\", \"cast\"], \"typing_extensions\": [\"Self\"]}, \"local\": {\"._configuration\": [\"MultiapiServiceClientConfiguration\"], \"..._serialization\": [\"Deserializer\", \"Serializer\"], \"._operations_mixin\": [\"MultiapiServiceClientOperationsMixin\"]}}, \"typing\": {\"sdkcore\": {\"azure.core.credentials_async\": [\"AsyncTokenCredential\"]}}}" + "sync_imports": "{\"conditional\": {\"stdlib\": {\"typing\": [\"Any\", \"Optional\"]}}, \"regular\": {\"sdkcore\": {\"azure.mgmt.core\": [\"ARMPipelineClient\"], \"azure.core.pipeline\": [\"policies\"], \"azure.mgmt.core.policies\": [\"ARMAutoResourceProviderRegistrationPolicy\"], \"azure.core.settings\": [\"settings\"], \"azure.mgmt.core.tools\": [\"get_arm_endpoints\"], \"azure.profiles\": [\"KnownProfiles\", \"ProfileDefinition\"], \"azure.profiles.multiapiclient\": [\"MultiApiClientMixin\"]}, \"stdlib\": {\"typing\": [\"Optional\", \"cast\"], \"typing_extensions\": [\"Self\"]}, \"local\": {\"._configuration\": [\"MultiapiServiceClientConfiguration\"], \"._utils.serialization\": [\"Deserializer\", \"Serializer\"], \"._operations_mixin\": [\"MultiapiServiceClientOperationsMixin\"]}}, \"typing\": {\"sdkcore\": {\"azure.core.credentials\": [\"TokenCredential\"]}}}", + "async_imports": "{\"conditional\": {\"stdlib\": {\"typing\": [\"Any\", \"Optional\"]}}, \"regular\": {\"sdkcore\": {\"azure.mgmt.core\": [\"AsyncARMPipelineClient\"], \"azure.core.pipeline\": [\"policies\"], \"azure.mgmt.core.policies\": [\"AsyncARMAutoResourceProviderRegistrationPolicy\"], \"azure.core.settings\": [\"settings\"], \"azure.mgmt.core.tools\": [\"get_arm_endpoints\"], \"azure.profiles\": [\"KnownProfiles\", \"ProfileDefinition\"], \"azure.profiles.multiapiclient\": [\"MultiApiClientMixin\"]}, \"stdlib\": {\"typing\": [\"Optional\", \"cast\"], \"typing_extensions\": [\"Self\"]}, \"local\": {\"._configuration\": [\"MultiapiServiceClientConfiguration\"], \".._utils.serialization\": [\"Deserializer\", \"Serializer\"], \"._operations_mixin\": [\"MultiapiServiceClientOperationsMixin\"]}}, \"typing\": {\"sdkcore\": {\"azure.core.credentials_async\": [\"AsyncTokenCredential\"]}}}" }, "global_parameters": { "sync": { diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiWithSubmodule/multiapiwithsubmodule/submodule/v3/_multiapi_service_client.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiWithSubmodule/multiapiwithsubmodule/submodule/v3/_multiapi_service_client.py index 5ab87d89403..15db91e2af4 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiWithSubmodule/multiapiwithsubmodule/submodule/v3/_multiapi_service_client.py +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiWithSubmodule/multiapiwithsubmodule/submodule/v3/_multiapi_service_client.py @@ -18,8 +18,8 @@ from azure.mgmt.core.tools import get_arm_endpoints from . import models as _models -from .._serialization import Deserializer, Serializer from ._configuration import MultiapiServiceClientConfiguration +from ._utils.serialization import Deserializer, Serializer from .operations import MultiapiServiceClientOperationsMixin, OperationGroupOneOperations, OperationGroupTwoOperations if TYPE_CHECKING: diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiWithSubmodule/multiapiwithsubmodule/submodule/v3/_utils/__init__.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiWithSubmodule/multiapiwithsubmodule/submodule/v3/_utils/__init__.py new file mode 100644 index 00000000000..0af9b28f660 --- /dev/null +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiWithSubmodule/multiapiwithsubmodule/submodule/v3/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ParameterFlattening/parameterflattening/_serialization.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiWithSubmodule/multiapiwithsubmodule/submodule/v3/_utils/serialization.py similarity index 100% rename from packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ParameterFlattening/parameterflattening/_serialization.py rename to packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiWithSubmodule/multiapiwithsubmodule/submodule/v3/_utils/serialization.py diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiWithSubmodule/multiapiwithsubmodule/submodule/v3/_utils/utils.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiWithSubmodule/multiapiwithsubmodule/submodule/v3/_utils/utils.py new file mode 100644 index 00000000000..39b612f39a9 --- /dev/null +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiWithSubmodule/multiapiwithsubmodule/submodule/v3/_utils/utils.py @@ -0,0 +1,25 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from abc import ABC +from typing import Generic, TYPE_CHECKING, TypeVar + +if TYPE_CHECKING: + from .serialization import Deserializer, Serializer + + +TClient = TypeVar("TClient") +TConfig = TypeVar("TConfig") + + +class ClientMixinABC(ABC, Generic[TClient, TConfig]): + """DO NOT use this class. It is for internal typing use only.""" + + _client: TClient + _config: TConfig + _serialize: "Serializer" + _deserialize: "Deserializer" diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiWithSubmodule/multiapiwithsubmodule/submodule/v3/_vendor.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiWithSubmodule/multiapiwithsubmodule/submodule/v3/_vendor.py deleted file mode 100644 index 70517e0b7af..00000000000 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiWithSubmodule/multiapiwithsubmodule/submodule/v3/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) AutoRest Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import MultiapiServiceClientConfiguration - -if TYPE_CHECKING: - from azure.core import PipelineClient - - from .._serialization import Deserializer, Serializer - - -class MultiapiServiceClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "PipelineClient" - _config: MultiapiServiceClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiWithSubmodule/multiapiwithsubmodule/submodule/v3/aio/_multiapi_service_client.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiWithSubmodule/multiapiwithsubmodule/submodule/v3/aio/_multiapi_service_client.py index 755244f091b..83d202c5635 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiWithSubmodule/multiapiwithsubmodule/submodule/v3/aio/_multiapi_service_client.py +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiWithSubmodule/multiapiwithsubmodule/submodule/v3/aio/_multiapi_service_client.py @@ -18,7 +18,7 @@ from azure.mgmt.core.tools import get_arm_endpoints from .. import models as _models -from ..._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import MultiapiServiceClientConfiguration from .operations import MultiapiServiceClientOperationsMixin, OperationGroupOneOperations, OperationGroupTwoOperations diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiWithSubmodule/multiapiwithsubmodule/submodule/v3/aio/_vendor.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiWithSubmodule/multiapiwithsubmodule/submodule/v3/aio/_vendor.py deleted file mode 100644 index 9c6fd05bb21..00000000000 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiWithSubmodule/multiapiwithsubmodule/submodule/v3/aio/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) AutoRest Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import MultiapiServiceClientConfiguration - -if TYPE_CHECKING: - from azure.core import AsyncPipelineClient - - from ..._serialization import Deserializer, Serializer - - -class MultiapiServiceClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "AsyncPipelineClient" - _config: MultiapiServiceClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiWithSubmodule/multiapiwithsubmodule/submodule/v3/aio/operations/_multiapi_service_client_operations.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiWithSubmodule/multiapiwithsubmodule/submodule/v3/aio/operations/_multiapi_service_client_operations.py index bcee179417c..0c7a4137537 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiWithSubmodule/multiapiwithsubmodule/submodule/v3/aio/operations/_multiapi_service_client_operations.py +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiWithSubmodule/multiapiwithsubmodule/submodule/v3/aio/operations/_multiapi_service_client_operations.py @@ -10,6 +10,7 @@ from typing import Any, AsyncIterable, Callable, Dict, Optional, TypeVar import urllib.parse +from azure.core import AsyncPipelineClient from azure.core.async_paging import AsyncItemPaged, AsyncList from azure.core.exceptions import ( ClientAuthenticationError, @@ -27,17 +28,18 @@ from azure.mgmt.core.exceptions import ARMErrorFormat from ... import models as _models +from ..._utils.utils import ClientMixinABC from ...operations._multiapi_service_client_operations import ( build_test_different_calls_request, build_test_paging_request, ) -from .._vendor import MultiapiServiceClientMixinABC +from .._configuration import MultiapiServiceClientConfiguration T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, AsyncHttpResponse], T, Dict[str, Any]], Any]] -class MultiapiServiceClientOperationsMixin(MultiapiServiceClientMixinABC): +class MultiapiServiceClientOperationsMixin(ClientMixinABC[AsyncPipelineClient, MultiapiServiceClientConfiguration]): def _api_version(self, op_name: str) -> str: # pylint: disable=unused-argument try: return self._config.api_version diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiWithSubmodule/multiapiwithsubmodule/submodule/v3/aio/operations/_operation_group_one_operations.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiWithSubmodule/multiapiwithsubmodule/submodule/v3/aio/operations/_operation_group_one_operations.py index 85adb1822ed..df8c55ccdbf 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiWithSubmodule/multiapiwithsubmodule/submodule/v3/aio/operations/_operation_group_one_operations.py +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiWithSubmodule/multiapiwithsubmodule/submodule/v3/aio/operations/_operation_group_one_operations.py @@ -28,7 +28,7 @@ from azure.mgmt.core.exceptions import ARMErrorFormat from ... import models as _models -from ...._serialization import Deserializer, Serializer +from ..._utils.serialization import Deserializer, Serializer from ...operations._operation_group_one_operations import ( build_test_operation_group_paging_request, build_test_two_request, diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiWithSubmodule/multiapiwithsubmodule/submodule/v3/aio/operations/_operation_group_two_operations.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiWithSubmodule/multiapiwithsubmodule/submodule/v3/aio/operations/_operation_group_two_operations.py index 72b43a9db1b..f82398c6d8f 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiWithSubmodule/multiapiwithsubmodule/submodule/v3/aio/operations/_operation_group_two_operations.py +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiWithSubmodule/multiapiwithsubmodule/submodule/v3/aio/operations/_operation_group_two_operations.py @@ -25,7 +25,7 @@ from azure.mgmt.core.exceptions import ARMErrorFormat from ... import models as _models -from ...._serialization import Deserializer, Serializer +from ..._utils.serialization import Deserializer, Serializer from ...operations._operation_group_two_operations import build_test_five_request, build_test_four_request from .._configuration import MultiapiServiceClientConfiguration diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiWithSubmodule/multiapiwithsubmodule/submodule/v3/models/_models_py3.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiWithSubmodule/multiapiwithsubmodule/submodule/v3/models/_models_py3.py index a7d63282c19..526b8aa9272 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiWithSubmodule/multiapiwithsubmodule/submodule/v3/models/_models_py3.py +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiWithSubmodule/multiapiwithsubmodule/submodule/v3/models/_models_py3.py @@ -8,7 +8,7 @@ from typing import Any, List, Optional, TYPE_CHECKING -from ... import _serialization +from .._utils import serialization as _serialization if TYPE_CHECKING: from .. import models as _models diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiWithSubmodule/multiapiwithsubmodule/submodule/v3/operations/_multiapi_service_client_operations.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiWithSubmodule/multiapiwithsubmodule/submodule/v3/operations/_multiapi_service_client_operations.py index 5726e327268..0c762374e50 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiWithSubmodule/multiapiwithsubmodule/submodule/v3/operations/_multiapi_service_client_operations.py +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiWithSubmodule/multiapiwithsubmodule/submodule/v3/operations/_multiapi_service_client_operations.py @@ -9,6 +9,7 @@ from typing import Any, Callable, Dict, Iterable, Optional, TypeVar import urllib.parse +from azure.core import PipelineClient from azure.core.exceptions import ( ClientAuthenticationError, HttpResponseError, @@ -25,8 +26,9 @@ from azure.mgmt.core.exceptions import ARMErrorFormat from .. import models as _models -from ..._serialization import Serializer -from .._vendor import MultiapiServiceClientMixinABC +from .._configuration import MultiapiServiceClientConfiguration +from .._utils.serialization import Serializer +from .._utils.utils import ClientMixinABC T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] @@ -79,7 +81,7 @@ def build_test_different_calls_request( return HttpRequest(method="GET", url=_url, params=_params, headers=_headers, **kwargs) -class MultiapiServiceClientOperationsMixin(MultiapiServiceClientMixinABC): +class MultiapiServiceClientOperationsMixin(ClientMixinABC[PipelineClient, MultiapiServiceClientConfiguration]): def _api_version(self, op_name: str) -> str: # pylint: disable=unused-argument try: return self._config.api_version diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiWithSubmodule/multiapiwithsubmodule/submodule/v3/operations/_operation_group_one_operations.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiWithSubmodule/multiapiwithsubmodule/submodule/v3/operations/_operation_group_one_operations.py index 42f454b99e2..d75b16538bd 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiWithSubmodule/multiapiwithsubmodule/submodule/v3/operations/_operation_group_one_operations.py +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiWithSubmodule/multiapiwithsubmodule/submodule/v3/operations/_operation_group_one_operations.py @@ -27,8 +27,8 @@ from azure.mgmt.core.exceptions import ARMErrorFormat from .. import models as _models -from ..._serialization import Deserializer, Serializer from .._configuration import MultiapiServiceClientConfiguration +from .._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiWithSubmodule/multiapiwithsubmodule/submodule/v3/operations/_operation_group_two_operations.py b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiWithSubmodule/multiapiwithsubmodule/submodule/v3/operations/_operation_group_two_operations.py index 4da92e57dd5..4a17179e0cd 100644 --- a/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiWithSubmodule/multiapiwithsubmodule/submodule/v3/operations/_operation_group_two_operations.py +++ b/packages/autorest.python/test/multiapi/Expected/AcceptanceTests/MultiapiWithSubmodule/multiapiwithsubmodule/submodule/v3/operations/_operation_group_two_operations.py @@ -25,8 +25,8 @@ from azure.mgmt.core.exceptions import ARMErrorFormat from .. import models as _models -from ..._serialization import Deserializer, Serializer from .._configuration import MultiapiServiceClientConfiguration +from .._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/autorest.python/test/multiapi/tox.ini b/packages/autorest.python/test/multiapi/tox.ini index 168c919ef02..8b188547ab8 100644 --- a/packages/autorest.python/test/multiapi/tox.ini +++ b/packages/autorest.python/test/multiapi/tox.ini @@ -8,11 +8,11 @@ deps= -r requirements.txt -r ../../../../eng/dev_requirements.txt commands= - pytest --cov=Expected + pytest [testenv:ci] commands = - pytest --cov=Expected + pytest [testenv:sphinx] ; setenv = diff --git a/packages/autorest.python/test/unittests/tox.ini b/packages/autorest.python/test/unittests/tox.ini index c68d3678d19..859a7dece30 100644 --- a/packages/autorest.python/test/unittests/tox.ini +++ b/packages/autorest.python/test/unittests/tox.ini @@ -7,4 +7,4 @@ passenv=* deps= -r requirements.txt commands= - pytest --cov=Expected + pytest diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/AdditionalProperties/additionalproperties/_additional_properties_client.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/AdditionalProperties/additionalproperties/_additional_properties_client.py index c3c9daf9bd6..c36eb97e707 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/AdditionalProperties/additionalproperties/_additional_properties_client.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/AdditionalProperties/additionalproperties/_additional_properties_client.py @@ -16,7 +16,7 @@ from . import models as _models from ._configuration import AdditionalPropertiesClientConfiguration -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer from .operations import PetsOperations diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/AdditionalProperties/additionalproperties/_utils/__init__.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/AdditionalProperties/additionalproperties/_utils/__init__.py new file mode 100644 index 00000000000..0af9b28f660 --- /dev/null +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/AdditionalProperties/additionalproperties/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ParameterizedEndpoint/parameterizedendpoint/_serialization.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/AdditionalProperties/additionalproperties/_utils/serialization.py similarity index 100% rename from packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ParameterizedEndpoint/parameterizedendpoint/_serialization.py rename to packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/AdditionalProperties/additionalproperties/_utils/serialization.py diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/AdditionalProperties/additionalproperties/aio/_additional_properties_client.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/AdditionalProperties/additionalproperties/aio/_additional_properties_client.py index f0c436287c7..5c61c049257 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/AdditionalProperties/additionalproperties/aio/_additional_properties_client.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/AdditionalProperties/additionalproperties/aio/_additional_properties_client.py @@ -15,7 +15,7 @@ from azure.core.rest import AsyncHttpResponse, HttpRequest from .. import models as _models -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import AdditionalPropertiesClientConfiguration from .operations import PetsOperations diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/AdditionalProperties/additionalproperties/aio/operations/_pets_operations.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/AdditionalProperties/additionalproperties/aio/operations/_pets_operations.py index 6ee79630059..5412ce8d2e3 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/AdditionalProperties/additionalproperties/aio/operations/_pets_operations.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/AdditionalProperties/additionalproperties/aio/operations/_pets_operations.py @@ -24,7 +24,7 @@ from azure.core.utils import case_insensitive_dict from ... import models as _models -from ..._serialization import Deserializer, Serializer +from ..._utils.serialization import Deserializer, Serializer from ...operations._pets_operations import ( build_create_ap_in_properties_request, build_create_ap_in_properties_with_ap_string_request, diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/AdditionalProperties/additionalproperties/models/_models_py3.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/AdditionalProperties/additionalproperties/models/_models_py3.py index 09b53300933..838921313c4 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/AdditionalProperties/additionalproperties/models/_models_py3.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/AdditionalProperties/additionalproperties/models/_models_py3.py @@ -8,7 +8,7 @@ from typing import Any, Dict, Optional -from .. import _serialization +from .._utils import serialization as _serialization class PetAPTrue(_serialization.Model): diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/AdditionalProperties/additionalproperties/operations/_pets_operations.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/AdditionalProperties/additionalproperties/operations/_pets_operations.py index 6883456c4ec..f5ec4def7a8 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/AdditionalProperties/additionalproperties/operations/_pets_operations.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/AdditionalProperties/additionalproperties/operations/_pets_operations.py @@ -25,7 +25,7 @@ from .. import models as _models from .._configuration import AdditionalPropertiesClientConfiguration -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Anything/anything/_anything_client.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Anything/anything/_anything_client.py index a4653139be9..f1360522921 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Anything/anything/_anything_client.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Anything/anything/_anything_client.py @@ -15,7 +15,7 @@ from azure.core.rest import HttpRequest, HttpResponse from ._configuration import AnythingClientConfiguration -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer from .operations import AnythingClientOperationsMixin diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Anything/anything/_utils/__init__.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Anything/anything/_utils/__init__.py new file mode 100644 index 00000000000..0af9b28f660 --- /dev/null +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Anything/anything/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Report/report/_serialization.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Anything/anything/_utils/serialization.py similarity index 100% rename from packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Report/report/_serialization.py rename to packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Anything/anything/_utils/serialization.py diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Anything/anything/_utils/utils.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Anything/anything/_utils/utils.py new file mode 100644 index 00000000000..39b612f39a9 --- /dev/null +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Anything/anything/_utils/utils.py @@ -0,0 +1,25 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from abc import ABC +from typing import Generic, TYPE_CHECKING, TypeVar + +if TYPE_CHECKING: + from .serialization import Deserializer, Serializer + + +TClient = TypeVar("TClient") +TConfig = TypeVar("TConfig") + + +class ClientMixinABC(ABC, Generic[TClient, TConfig]): + """DO NOT use this class. It is for internal typing use only.""" + + _client: TClient + _config: TConfig + _serialize: "Serializer" + _deserialize: "Deserializer" diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Anything/anything/_vendor.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Anything/anything/_vendor.py deleted file mode 100644 index db0a5a9a33b..00000000000 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Anything/anything/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) AutoRest Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import AnythingClientConfiguration - -if TYPE_CHECKING: - from azure.core import PipelineClient - - from ._serialization import Deserializer, Serializer - - -class AnythingClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "PipelineClient" - _config: AnythingClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Anything/anything/aio/_anything_client.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Anything/anything/aio/_anything_client.py index f2e6e6d527e..9784837beb0 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Anything/anything/aio/_anything_client.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Anything/anything/aio/_anything_client.py @@ -14,7 +14,7 @@ from azure.core.pipeline import policies from azure.core.rest import AsyncHttpResponse, HttpRequest -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import AnythingClientConfiguration from .operations import AnythingClientOperationsMixin diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Anything/anything/aio/_vendor.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Anything/anything/aio/_vendor.py deleted file mode 100644 index c99b54eef8d..00000000000 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Anything/anything/aio/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) AutoRest Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import AnythingClientConfiguration - -if TYPE_CHECKING: - from azure.core import AsyncPipelineClient - - from .._serialization import Deserializer, Serializer - - -class AnythingClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "AsyncPipelineClient" - _config: AnythingClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Anything/anything/aio/operations/_anything_client_operations.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Anything/anything/aio/operations/_anything_client_operations.py index 38235f6d05d..89c2a9c97c7 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Anything/anything/aio/operations/_anything_client_operations.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Anything/anything/aio/operations/_anything_client_operations.py @@ -9,6 +9,7 @@ from collections.abc import MutableMapping from typing import Any, Callable, Dict, Optional, TypeVar +from azure.core import AsyncPipelineClient from azure.core.exceptions import ( ClientAuthenticationError, HttpResponseError, @@ -22,6 +23,7 @@ from azure.core.tracing.decorator_async import distributed_trace_async from azure.core.utils import case_insensitive_dict +from ..._utils.utils import ClientMixinABC from ...operations._anything_client_operations import ( build_get_array_request, build_get_object_request, @@ -30,13 +32,13 @@ build_put_object_request, build_put_string_request, ) -from .._vendor import AnythingClientMixinABC +from .._configuration import AnythingClientConfiguration T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, AsyncHttpResponse], T, Dict[str, Any]], Any]] -class AnythingClientOperationsMixin(AnythingClientMixinABC): +class AnythingClientOperationsMixin(ClientMixinABC[AsyncPipelineClient, AnythingClientConfiguration]): @distributed_trace_async async def get_object(self, **kwargs: Any) -> Any: diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Anything/anything/operations/_anything_client_operations.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Anything/anything/operations/_anything_client_operations.py index ecfdc70b82b..eb6560b328a 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Anything/anything/operations/_anything_client_operations.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Anything/anything/operations/_anything_client_operations.py @@ -8,6 +8,7 @@ from collections.abc import MutableMapping from typing import Any, Callable, Dict, Optional, TypeVar +from azure.core import PipelineClient from azure.core.exceptions import ( ClientAuthenticationError, HttpResponseError, @@ -21,8 +22,9 @@ from azure.core.tracing.decorator import distributed_trace from azure.core.utils import case_insensitive_dict -from .._serialization import Serializer -from .._vendor import AnythingClientMixinABC +from .._configuration import AnythingClientConfiguration +from .._utils.serialization import Serializer +from .._utils.utils import ClientMixinABC T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] @@ -115,7 +117,7 @@ def build_put_array_request(*, json: Any, **kwargs: Any) -> HttpRequest: return HttpRequest(method="PUT", url=_url, headers=_headers, json=json, **kwargs) -class AnythingClientOperationsMixin(AnythingClientMixinABC): +class AnythingClientOperationsMixin(ClientMixinABC[PipelineClient, AnythingClientConfiguration]): @distributed_trace def get_object(self, **kwargs: Any) -> Any: diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyArray/bodyarray/_auto_rest_swagger_bat_array_service.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyArray/bodyarray/_auto_rest_swagger_bat_array_service.py index a79cfca019a..17ae7ddb465 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyArray/bodyarray/_auto_rest_swagger_bat_array_service.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyArray/bodyarray/_auto_rest_swagger_bat_array_service.py @@ -16,7 +16,7 @@ from . import models as _models from ._configuration import AutoRestSwaggerBATArrayServiceConfiguration -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer from .operations import ArrayOperations diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyArray/bodyarray/_utils/__init__.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyArray/bodyarray/_utils/__init__.py new file mode 100644 index 00000000000..0af9b28f660 --- /dev/null +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyArray/bodyarray/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ReservedWords/reservedwords/_serialization.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyArray/bodyarray/_utils/serialization.py similarity index 100% rename from packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ReservedWords/reservedwords/_serialization.py rename to packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyArray/bodyarray/_utils/serialization.py diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyArray/bodyarray/aio/_auto_rest_swagger_bat_array_service.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyArray/bodyarray/aio/_auto_rest_swagger_bat_array_service.py index 6050b5a70e0..f4b56f17271 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyArray/bodyarray/aio/_auto_rest_swagger_bat_array_service.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyArray/bodyarray/aio/_auto_rest_swagger_bat_array_service.py @@ -15,7 +15,7 @@ from azure.core.rest import AsyncHttpResponse, HttpRequest from .. import models as _models -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import AutoRestSwaggerBATArrayServiceConfiguration from .operations import ArrayOperations diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyArray/bodyarray/aio/operations/_array_operations.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyArray/bodyarray/aio/operations/_array_operations.py index b139b77b6d3..68314979749 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyArray/bodyarray/aio/operations/_array_operations.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyArray/bodyarray/aio/operations/_array_operations.py @@ -26,7 +26,7 @@ from azure.core.utils import case_insensitive_dict from ... import models as _models -from ..._serialization import Deserializer, Serializer +from ..._utils.serialization import Deserializer, Serializer from ...operations._array_operations import ( build_get_array_empty_request, build_get_array_item_empty_request, diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyArray/bodyarray/models/_models_py3.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyArray/bodyarray/models/_models_py3.py index 6aa1810338a..35f5e8e8764 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyArray/bodyarray/models/_models_py3.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyArray/bodyarray/models/_models_py3.py @@ -8,7 +8,7 @@ from typing import Any, Optional -from .. import _serialization +from .._utils import serialization as _serialization class Error(_serialization.Model): diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyArray/bodyarray/operations/_array_operations.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyArray/bodyarray/operations/_array_operations.py index a093d9d22d8..4e9f0f1a7aa 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyArray/bodyarray/operations/_array_operations.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyArray/bodyarray/operations/_array_operations.py @@ -27,7 +27,7 @@ from .. import models as _models from .._configuration import AutoRestSwaggerBATArrayServiceConfiguration -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyArrayWithNamespaceFolders/vanilla/body/array/_auto_rest_swagger_bat_array_service.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyArrayWithNamespaceFolders/vanilla/body/array/_auto_rest_swagger_bat_array_service.py index 289431d9bf8..f493961f7ff 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyArrayWithNamespaceFolders/vanilla/body/array/_auto_rest_swagger_bat_array_service.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyArrayWithNamespaceFolders/vanilla/body/array/_auto_rest_swagger_bat_array_service.py @@ -16,7 +16,7 @@ from . import models as _models from ._configuration import AutoRestSwaggerBATArrayServiceConfiguration -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer from .operations import ArrayOperations diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyArrayWithNamespaceFolders/vanilla/body/array/_utils/__init__.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyArrayWithNamespaceFolders/vanilla/body/array/_utils/__init__.py new file mode 100644 index 00000000000..0af9b28f660 --- /dev/null +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyArrayWithNamespaceFolders/vanilla/body/array/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/SecurityAadSwagger/securityaadswagger/_serialization.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyArrayWithNamespaceFolders/vanilla/body/array/_utils/serialization.py similarity index 100% rename from packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/SecurityAadSwagger/securityaadswagger/_serialization.py rename to packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyArrayWithNamespaceFolders/vanilla/body/array/_utils/serialization.py diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyArrayWithNamespaceFolders/vanilla/body/array/aio/_auto_rest_swagger_bat_array_service.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyArrayWithNamespaceFolders/vanilla/body/array/aio/_auto_rest_swagger_bat_array_service.py index 5d952d1c653..822c3eca370 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyArrayWithNamespaceFolders/vanilla/body/array/aio/_auto_rest_swagger_bat_array_service.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyArrayWithNamespaceFolders/vanilla/body/array/aio/_auto_rest_swagger_bat_array_service.py @@ -15,7 +15,7 @@ from azure.core.rest import AsyncHttpResponse, HttpRequest from .. import models as _models -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import AutoRestSwaggerBATArrayServiceConfiguration from .operations import ArrayOperations diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyArrayWithNamespaceFolders/vanilla/body/array/aio/operations/_array_operations.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyArrayWithNamespaceFolders/vanilla/body/array/aio/operations/_array_operations.py index 39315832813..b64882ea816 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyArrayWithNamespaceFolders/vanilla/body/array/aio/operations/_array_operations.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyArrayWithNamespaceFolders/vanilla/body/array/aio/operations/_array_operations.py @@ -26,7 +26,7 @@ from azure.core.utils import case_insensitive_dict from ... import models as _models -from ..._serialization import Deserializer, Serializer +from ..._utils.serialization import Deserializer, Serializer from ...operations._array_operations import ( build_get_array_empty_request, build_get_array_item_empty_request, diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyArrayWithNamespaceFolders/vanilla/body/array/models/_models_py3.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyArrayWithNamespaceFolders/vanilla/body/array/models/_models_py3.py index 6aa1810338a..35f5e8e8764 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyArrayWithNamespaceFolders/vanilla/body/array/models/_models_py3.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyArrayWithNamespaceFolders/vanilla/body/array/models/_models_py3.py @@ -8,7 +8,7 @@ from typing import Any, Optional -from .. import _serialization +from .._utils import serialization as _serialization class Error(_serialization.Model): diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyArrayWithNamespaceFolders/vanilla/body/array/operations/_array_operations.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyArrayWithNamespaceFolders/vanilla/body/array/operations/_array_operations.py index 73671016939..6f90faff515 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyArrayWithNamespaceFolders/vanilla/body/array/operations/_array_operations.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyArrayWithNamespaceFolders/vanilla/body/array/operations/_array_operations.py @@ -27,7 +27,7 @@ from .. import models as _models from .._configuration import AutoRestSwaggerBATArrayServiceConfiguration -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyBinary/bodybinary/_binary_with_content_type_application_json.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyBinary/bodybinary/_binary_with_content_type_application_json.py index 89a0d339ec6..de84376639d 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyBinary/bodybinary/_binary_with_content_type_application_json.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyBinary/bodybinary/_binary_with_content_type_application_json.py @@ -16,7 +16,7 @@ from . import models as _models from ._configuration import BinaryWithContentTypeApplicationJsonConfiguration -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer from .operations import DownloadOperations, UploadOperations diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyBinary/bodybinary/_utils/__init__.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyBinary/bodybinary/_utils/__init__.py new file mode 100644 index 00000000000..0af9b28f660 --- /dev/null +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyBinary/bodybinary/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/SecurityAadSwaggerCredentialFlag/securityaadswaggercredentialflag/_serialization.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyBinary/bodybinary/_utils/serialization.py similarity index 100% rename from packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/SecurityAadSwaggerCredentialFlag/securityaadswaggercredentialflag/_serialization.py rename to packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyBinary/bodybinary/_utils/serialization.py diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyBinary/bodybinary/aio/_binary_with_content_type_application_json.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyBinary/bodybinary/aio/_binary_with_content_type_application_json.py index 7d46eab1c05..370e2944356 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyBinary/bodybinary/aio/_binary_with_content_type_application_json.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyBinary/bodybinary/aio/_binary_with_content_type_application_json.py @@ -15,7 +15,7 @@ from azure.core.rest import AsyncHttpResponse, HttpRequest from .. import models as _models -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import BinaryWithContentTypeApplicationJsonConfiguration from .operations import DownloadOperations, UploadOperations diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyBinary/bodybinary/aio/operations/_download_operations.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyBinary/bodybinary/aio/operations/_download_operations.py index 5a12192f5bd..5c916cb6213 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyBinary/bodybinary/aio/operations/_download_operations.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyBinary/bodybinary/aio/operations/_download_operations.py @@ -24,7 +24,7 @@ from azure.core.tracing.decorator_async import distributed_trace_async from ... import models as _models -from ..._serialization import Deserializer, Serializer +from ..._utils.serialization import Deserializer, Serializer from ...operations._download_operations import build_error_stream_request from .._configuration import BinaryWithContentTypeApplicationJsonConfiguration diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyBinary/bodybinary/aio/operations/_upload_operations.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyBinary/bodybinary/aio/operations/_upload_operations.py index 86bdd867c3c..6efcfca60e1 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyBinary/bodybinary/aio/operations/_upload_operations.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyBinary/bodybinary/aio/operations/_upload_operations.py @@ -23,7 +23,7 @@ from azure.core.utils import case_insensitive_dict from ... import models as _models -from ..._serialization import Deserializer, Serializer +from ..._utils.serialization import Deserializer, Serializer from ...operations._upload_operations import build_binary_request, build_file_request from .._configuration import BinaryWithContentTypeApplicationJsonConfiguration diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyBinary/bodybinary/models/_models_py3.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyBinary/bodybinary/models/_models_py3.py index 1d1b7707def..109cf147510 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyBinary/bodybinary/models/_models_py3.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyBinary/bodybinary/models/_models_py3.py @@ -8,7 +8,7 @@ from typing import Any, Optional -from .. import _serialization +from .._utils import serialization as _serialization class Error(_serialization.Model): diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyBinary/bodybinary/operations/_download_operations.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyBinary/bodybinary/operations/_download_operations.py index bd71f9353d7..d53e9c12faa 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyBinary/bodybinary/operations/_download_operations.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyBinary/bodybinary/operations/_download_operations.py @@ -26,7 +26,7 @@ from .. import models as _models from .._configuration import BinaryWithContentTypeApplicationJsonConfiguration -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyBinary/bodybinary/operations/_upload_operations.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyBinary/bodybinary/operations/_upload_operations.py index df9af9d69af..2dccfe6ff57 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyBinary/bodybinary/operations/_upload_operations.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyBinary/bodybinary/operations/_upload_operations.py @@ -24,7 +24,7 @@ from .. import models as _models from .._configuration import BinaryWithContentTypeApplicationJsonConfiguration -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyBoolean/bodyboolean/_auto_rest_bool_test_service.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyBoolean/bodyboolean/_auto_rest_bool_test_service.py index 925d929f8b8..b7ed25c8ec8 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyBoolean/bodyboolean/_auto_rest_bool_test_service.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyBoolean/bodyboolean/_auto_rest_bool_test_service.py @@ -16,7 +16,7 @@ from . import models as _models from ._configuration import AutoRestBoolTestServiceConfiguration -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer from .operations import BoolOperations diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyBoolean/bodyboolean/_utils/__init__.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyBoolean/bodyboolean/_utils/__init__.py new file mode 100644 index 00000000000..0af9b28f660 --- /dev/null +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyBoolean/bodyboolean/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/SecurityKeySwagger/securitykeyswagger/_serialization.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyBoolean/bodyboolean/_utils/serialization.py similarity index 100% rename from packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/SecurityKeySwagger/securitykeyswagger/_serialization.py rename to packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyBoolean/bodyboolean/_utils/serialization.py diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyBoolean/bodyboolean/aio/_auto_rest_bool_test_service.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyBoolean/bodyboolean/aio/_auto_rest_bool_test_service.py index e6af036dd3d..3cdd55a0dd3 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyBoolean/bodyboolean/aio/_auto_rest_bool_test_service.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyBoolean/bodyboolean/aio/_auto_rest_bool_test_service.py @@ -15,7 +15,7 @@ from azure.core.rest import AsyncHttpResponse, HttpRequest from .. import models as _models -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import AutoRestBoolTestServiceConfiguration from .operations import BoolOperations diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyBoolean/bodyboolean/aio/operations/_bool_operations.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyBoolean/bodyboolean/aio/operations/_bool_operations.py index a7f2208fb5c..11c100cc43f 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyBoolean/bodyboolean/aio/operations/_bool_operations.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyBoolean/bodyboolean/aio/operations/_bool_operations.py @@ -23,7 +23,7 @@ from azure.core.utils import case_insensitive_dict from ... import models as _models -from ..._serialization import Deserializer, Serializer +from ..._utils.serialization import Deserializer, Serializer from ...operations._bool_operations import ( build_get_false_request, build_get_invalid_request, diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyBoolean/bodyboolean/models/_models_py3.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyBoolean/bodyboolean/models/_models_py3.py index 1d1b7707def..109cf147510 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyBoolean/bodyboolean/models/_models_py3.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyBoolean/bodyboolean/models/_models_py3.py @@ -8,7 +8,7 @@ from typing import Any, Optional -from .. import _serialization +from .._utils import serialization as _serialization class Error(_serialization.Model): diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyBoolean/bodyboolean/operations/_bool_operations.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyBoolean/bodyboolean/operations/_bool_operations.py index 99e3834967b..7d7a80b3cb9 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyBoolean/bodyboolean/operations/_bool_operations.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyBoolean/bodyboolean/operations/_bool_operations.py @@ -24,7 +24,7 @@ from .. import models as _models from .._configuration import AutoRestBoolTestServiceConfiguration -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyByte/bodybyte/_auto_rest_swagger_bat_byte_service.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyByte/bodybyte/_auto_rest_swagger_bat_byte_service.py index 2d816a753ce..1f8dcf4435f 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyByte/bodybyte/_auto_rest_swagger_bat_byte_service.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyByte/bodybyte/_auto_rest_swagger_bat_byte_service.py @@ -16,7 +16,7 @@ from . import models as _models from ._configuration import AutoRestSwaggerBATByteServiceConfiguration -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer from .operations import ByteOperations diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyByte/bodybyte/_utils/__init__.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyByte/bodybyte/_utils/__init__.py new file mode 100644 index 00000000000..0af9b28f660 --- /dev/null +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyByte/bodybyte/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/SecurityKeySwaggerCredentialFlag/securitykeyswaggercredentialflag/_serialization.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyByte/bodybyte/_utils/serialization.py similarity index 100% rename from packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/SecurityKeySwaggerCredentialFlag/securitykeyswaggercredentialflag/_serialization.py rename to packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyByte/bodybyte/_utils/serialization.py diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyByte/bodybyte/aio/_auto_rest_swagger_bat_byte_service.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyByte/bodybyte/aio/_auto_rest_swagger_bat_byte_service.py index ea167041ef3..061a89a9f76 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyByte/bodybyte/aio/_auto_rest_swagger_bat_byte_service.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyByte/bodybyte/aio/_auto_rest_swagger_bat_byte_service.py @@ -15,7 +15,7 @@ from azure.core.rest import AsyncHttpResponse, HttpRequest from .. import models as _models -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import AutoRestSwaggerBATByteServiceConfiguration from .operations import ByteOperations diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyByte/bodybyte/aio/operations/_byte_operations.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyByte/bodybyte/aio/operations/_byte_operations.py index c798f975bea..503b16af62f 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyByte/bodybyte/aio/operations/_byte_operations.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyByte/bodybyte/aio/operations/_byte_operations.py @@ -23,7 +23,7 @@ from azure.core.utils import case_insensitive_dict from ... import models as _models -from ..._serialization import Deserializer, Serializer +from ..._utils.serialization import Deserializer, Serializer from ...operations._byte_operations import ( build_get_empty_request, build_get_invalid_request, diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyByte/bodybyte/models/_models_py3.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyByte/bodybyte/models/_models_py3.py index 1d1b7707def..109cf147510 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyByte/bodybyte/models/_models_py3.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyByte/bodybyte/models/_models_py3.py @@ -8,7 +8,7 @@ from typing import Any, Optional -from .. import _serialization +from .._utils import serialization as _serialization class Error(_serialization.Model): diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyByte/bodybyte/operations/_byte_operations.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyByte/bodybyte/operations/_byte_operations.py index 8d5b624f6c4..e65cd87e98c 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyByte/bodybyte/operations/_byte_operations.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyByte/bodybyte/operations/_byte_operations.py @@ -24,7 +24,7 @@ from .. import models as _models from .._configuration import AutoRestSwaggerBATByteServiceConfiguration -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyByteWithPackageName/bodybytewithpackagename/_class_name.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyByteWithPackageName/bodybytewithpackagename/_class_name.py index 88f3c2c5459..18a12a64817 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyByteWithPackageName/bodybytewithpackagename/_class_name.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyByteWithPackageName/bodybytewithpackagename/_class_name.py @@ -16,7 +16,7 @@ from . import models as _models from ._configuration import ClassNameConfiguration -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer from .operations import ByteOperations diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyByteWithPackageName/bodybytewithpackagename/_utils/__init__.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyByteWithPackageName/bodybytewithpackagename/_utils/__init__.py new file mode 100644 index 00000000000..0af9b28f660 --- /dev/null +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyByteWithPackageName/bodybytewithpackagename/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/UrlMultiCollectionFormat/urlmulticollectionformat/_serialization.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyByteWithPackageName/bodybytewithpackagename/_utils/serialization.py similarity index 100% rename from packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/UrlMultiCollectionFormat/urlmulticollectionformat/_serialization.py rename to packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyByteWithPackageName/bodybytewithpackagename/_utils/serialization.py diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyByteWithPackageName/bodybytewithpackagename/aio/_class_name.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyByteWithPackageName/bodybytewithpackagename/aio/_class_name.py index f91c54ff18a..af762d95285 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyByteWithPackageName/bodybytewithpackagename/aio/_class_name.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyByteWithPackageName/bodybytewithpackagename/aio/_class_name.py @@ -15,7 +15,7 @@ from azure.core.rest import AsyncHttpResponse, HttpRequest from .. import models as _models -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import ClassNameConfiguration from .operations import ByteOperations diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyByteWithPackageName/bodybytewithpackagename/aio/operations/_byte_operations.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyByteWithPackageName/bodybytewithpackagename/aio/operations/_byte_operations.py index 466754719ee..ab0c07f83e9 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyByteWithPackageName/bodybytewithpackagename/aio/operations/_byte_operations.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyByteWithPackageName/bodybytewithpackagename/aio/operations/_byte_operations.py @@ -23,7 +23,7 @@ from azure.core.utils import case_insensitive_dict from ... import models as _models -from ..._serialization import Deserializer, Serializer +from ..._utils.serialization import Deserializer, Serializer from ...operations._byte_operations import ( build_get_empty_request, build_get_invalid_request, diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyByteWithPackageName/bodybytewithpackagename/models/_models_py3.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyByteWithPackageName/bodybytewithpackagename/models/_models_py3.py index 1d1b7707def..109cf147510 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyByteWithPackageName/bodybytewithpackagename/models/_models_py3.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyByteWithPackageName/bodybytewithpackagename/models/_models_py3.py @@ -8,7 +8,7 @@ from typing import Any, Optional -from .. import _serialization +from .._utils import serialization as _serialization class Error(_serialization.Model): diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyByteWithPackageName/bodybytewithpackagename/operations/_byte_operations.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyByteWithPackageName/bodybytewithpackagename/operations/_byte_operations.py index fa61fdd15a8..83602b561d6 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyByteWithPackageName/bodybytewithpackagename/operations/_byte_operations.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyByteWithPackageName/bodybytewithpackagename/operations/_byte_operations.py @@ -24,7 +24,7 @@ from .. import models as _models from .._configuration import ClassNameConfiguration -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyDate/bodydate/_auto_rest_date_test_service.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyDate/bodydate/_auto_rest_date_test_service.py index 9c6b4033298..07326d39d6d 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyDate/bodydate/_auto_rest_date_test_service.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyDate/bodydate/_auto_rest_date_test_service.py @@ -16,7 +16,7 @@ from . import models as _models from ._configuration import AutoRestDateTestServiceConfiguration -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer from .operations import DateOperations diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyDate/bodydate/_utils/__init__.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyDate/bodydate/_utils/__init__.py new file mode 100644 index 00000000000..0af9b28f660 --- /dev/null +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyDate/bodydate/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Xml/xmlservice/_serialization.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyDate/bodydate/_utils/serialization.py similarity index 100% rename from packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Xml/xmlservice/_serialization.py rename to packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyDate/bodydate/_utils/serialization.py diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyDate/bodydate/aio/_auto_rest_date_test_service.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyDate/bodydate/aio/_auto_rest_date_test_service.py index 6768deb0435..4b727743a39 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyDate/bodydate/aio/_auto_rest_date_test_service.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyDate/bodydate/aio/_auto_rest_date_test_service.py @@ -15,7 +15,7 @@ from azure.core.rest import AsyncHttpResponse, HttpRequest from .. import models as _models -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import AutoRestDateTestServiceConfiguration from .operations import DateOperations diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyDate/bodydate/aio/operations/_date_operations.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyDate/bodydate/aio/operations/_date_operations.py index 3c6f6b0edf8..3614b01aab1 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyDate/bodydate/aio/operations/_date_operations.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyDate/bodydate/aio/operations/_date_operations.py @@ -24,7 +24,7 @@ from azure.core.utils import case_insensitive_dict from ... import models as _models -from ..._serialization import Deserializer, Serializer +from ..._utils.serialization import Deserializer, Serializer from ...operations._date_operations import ( build_get_invalid_date_request, build_get_max_date_request, diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyDate/bodydate/models/_models_py3.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyDate/bodydate/models/_models_py3.py index 1d1b7707def..109cf147510 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyDate/bodydate/models/_models_py3.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyDate/bodydate/models/_models_py3.py @@ -8,7 +8,7 @@ from typing import Any, Optional -from .. import _serialization +from .._utils import serialization as _serialization class Error(_serialization.Model): diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyDate/bodydate/operations/_date_operations.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyDate/bodydate/operations/_date_operations.py index 5978a2473b4..98046ddbe01 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyDate/bodydate/operations/_date_operations.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyDate/bodydate/operations/_date_operations.py @@ -25,7 +25,7 @@ from .. import models as _models from .._configuration import AutoRestDateTestServiceConfiguration -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyDateTime/bodydatetime/_auto_rest_date_time_test_service.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyDateTime/bodydatetime/_auto_rest_date_time_test_service.py index c497bec2c45..fab856f8462 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyDateTime/bodydatetime/_auto_rest_date_time_test_service.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyDateTime/bodydatetime/_auto_rest_date_time_test_service.py @@ -16,7 +16,7 @@ from . import models as _models from ._configuration import AutoRestDateTimeTestServiceConfiguration -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer from .operations import DatetimeOperations diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyDateTime/bodydatetime/_utils/__init__.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyDateTime/bodydatetime/_utils/__init__.py new file mode 100644 index 00000000000..0af9b28f660 --- /dev/null +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyDateTime/bodydatetime/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/XmsErrorResponse/xmserrorresponse/_serialization.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyDateTime/bodydatetime/_utils/serialization.py similarity index 100% rename from packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/XmsErrorResponse/xmserrorresponse/_serialization.py rename to packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyDateTime/bodydatetime/_utils/serialization.py diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyDateTime/bodydatetime/aio/_auto_rest_date_time_test_service.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyDateTime/bodydatetime/aio/_auto_rest_date_time_test_service.py index 501b5a2c92c..23e2d973413 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyDateTime/bodydatetime/aio/_auto_rest_date_time_test_service.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyDateTime/bodydatetime/aio/_auto_rest_date_time_test_service.py @@ -15,7 +15,7 @@ from azure.core.rest import AsyncHttpResponse, HttpRequest from .. import models as _models -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import AutoRestDateTimeTestServiceConfiguration from .operations import DatetimeOperations diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyDateTime/bodydatetime/aio/operations/_datetime_operations.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyDateTime/bodydatetime/aio/operations/_datetime_operations.py index efeb0c0c847..61a9ae6fd5f 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyDateTime/bodydatetime/aio/operations/_datetime_operations.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyDateTime/bodydatetime/aio/operations/_datetime_operations.py @@ -25,7 +25,7 @@ from azure.core.utils import case_insensitive_dict from ... import models as _models -from ..._serialization import Deserializer, Serializer +from ..._utils.serialization import Deserializer, Serializer from ...operations._datetime_operations import ( build_get_invalid_request, build_get_local_negative_offset_lowercase_max_date_time_request, diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyDateTime/bodydatetime/models/_models_py3.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyDateTime/bodydatetime/models/_models_py3.py index 1d1b7707def..109cf147510 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyDateTime/bodydatetime/models/_models_py3.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyDateTime/bodydatetime/models/_models_py3.py @@ -8,7 +8,7 @@ from typing import Any, Optional -from .. import _serialization +from .._utils import serialization as _serialization class Error(_serialization.Model): diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyDateTime/bodydatetime/operations/_datetime_operations.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyDateTime/bodydatetime/operations/_datetime_operations.py index d8fea551c29..0217cbf5b76 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyDateTime/bodydatetime/operations/_datetime_operations.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyDateTime/bodydatetime/operations/_datetime_operations.py @@ -26,7 +26,7 @@ from .. import models as _models from .._configuration import AutoRestDateTimeTestServiceConfiguration -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyDateTimeRfc1123/bodydatetimerfc1123/_auto_rest_rfc1123_date_time_test_service.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyDateTimeRfc1123/bodydatetimerfc1123/_auto_rest_rfc1123_date_time_test_service.py index cf105d0017f..08dbbb19027 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyDateTimeRfc1123/bodydatetimerfc1123/_auto_rest_rfc1123_date_time_test_service.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyDateTimeRfc1123/bodydatetimerfc1123/_auto_rest_rfc1123_date_time_test_service.py @@ -16,7 +16,7 @@ from . import models as _models from ._configuration import AutoRestRFC1123DateTimeTestServiceConfiguration -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer from .operations import Datetimerfc1123Operations diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyDateTimeRfc1123/bodydatetimerfc1123/_utils/__init__.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyDateTimeRfc1123/bodydatetimerfc1123/_utils/__init__.py new file mode 100644 index 00000000000..0af9b28f660 --- /dev/null +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyDateTimeRfc1123/bodydatetimerfc1123/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/AdditionalPropertiesVersionTolerant/additionalpropertiesversiontolerant/_serialization.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyDateTimeRfc1123/bodydatetimerfc1123/_utils/serialization.py similarity index 100% rename from packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/AdditionalPropertiesVersionTolerant/additionalpropertiesversiontolerant/_serialization.py rename to packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyDateTimeRfc1123/bodydatetimerfc1123/_utils/serialization.py diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyDateTimeRfc1123/bodydatetimerfc1123/aio/_auto_rest_rfc1123_date_time_test_service.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyDateTimeRfc1123/bodydatetimerfc1123/aio/_auto_rest_rfc1123_date_time_test_service.py index 748c40ccd11..74ee1f09f8c 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyDateTimeRfc1123/bodydatetimerfc1123/aio/_auto_rest_rfc1123_date_time_test_service.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyDateTimeRfc1123/bodydatetimerfc1123/aio/_auto_rest_rfc1123_date_time_test_service.py @@ -15,7 +15,7 @@ from azure.core.rest import AsyncHttpResponse, HttpRequest from .. import models as _models -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import AutoRestRFC1123DateTimeTestServiceConfiguration from .operations import Datetimerfc1123Operations diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyDateTimeRfc1123/bodydatetimerfc1123/aio/operations/_datetimerfc1123_operations.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyDateTimeRfc1123/bodydatetimerfc1123/aio/operations/_datetimerfc1123_operations.py index 7c77b853a3f..137ab82ee1a 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyDateTimeRfc1123/bodydatetimerfc1123/aio/operations/_datetimerfc1123_operations.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyDateTimeRfc1123/bodydatetimerfc1123/aio/operations/_datetimerfc1123_operations.py @@ -24,7 +24,7 @@ from azure.core.utils import case_insensitive_dict from ... import models as _models -from ..._serialization import Deserializer, Serializer +from ..._utils.serialization import Deserializer, Serializer from ...operations._datetimerfc1123_operations import ( build_get_invalid_request, build_get_null_request, diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyDateTimeRfc1123/bodydatetimerfc1123/models/_models_py3.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyDateTimeRfc1123/bodydatetimerfc1123/models/_models_py3.py index 1d1b7707def..109cf147510 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyDateTimeRfc1123/bodydatetimerfc1123/models/_models_py3.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyDateTimeRfc1123/bodydatetimerfc1123/models/_models_py3.py @@ -8,7 +8,7 @@ from typing import Any, Optional -from .. import _serialization +from .._utils import serialization as _serialization class Error(_serialization.Model): diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyDateTimeRfc1123/bodydatetimerfc1123/operations/_datetimerfc1123_operations.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyDateTimeRfc1123/bodydatetimerfc1123/operations/_datetimerfc1123_operations.py index b8814303216..44f310563d3 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyDateTimeRfc1123/bodydatetimerfc1123/operations/_datetimerfc1123_operations.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyDateTimeRfc1123/bodydatetimerfc1123/operations/_datetimerfc1123_operations.py @@ -25,7 +25,7 @@ from .. import models as _models from .._configuration import AutoRestRFC1123DateTimeTestServiceConfiguration -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyDictionary/bodydictionary/_auto_rest_swagger_bat_dictionary_service.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyDictionary/bodydictionary/_auto_rest_swagger_bat_dictionary_service.py index bee14656b86..4c938c6e952 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyDictionary/bodydictionary/_auto_rest_swagger_bat_dictionary_service.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyDictionary/bodydictionary/_auto_rest_swagger_bat_dictionary_service.py @@ -16,7 +16,7 @@ from . import models as _models from ._configuration import AutoRestSwaggerBATDictionaryServiceConfiguration -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer from .operations import DictionaryOperations diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyDictionary/bodydictionary/_utils/__init__.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyDictionary/bodydictionary/_utils/__init__.py new file mode 100644 index 00000000000..0af9b28f660 --- /dev/null +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyDictionary/bodydictionary/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/AnythingVersionTolerant/anythingversiontolerant/_serialization.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyDictionary/bodydictionary/_utils/serialization.py similarity index 100% rename from packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/AnythingVersionTolerant/anythingversiontolerant/_serialization.py rename to packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyDictionary/bodydictionary/_utils/serialization.py diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyDictionary/bodydictionary/aio/_auto_rest_swagger_bat_dictionary_service.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyDictionary/bodydictionary/aio/_auto_rest_swagger_bat_dictionary_service.py index 569d7366ba0..9b71d885cdc 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyDictionary/bodydictionary/aio/_auto_rest_swagger_bat_dictionary_service.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyDictionary/bodydictionary/aio/_auto_rest_swagger_bat_dictionary_service.py @@ -15,7 +15,7 @@ from azure.core.rest import AsyncHttpResponse, HttpRequest from .. import models as _models -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import AutoRestSwaggerBATDictionaryServiceConfiguration from .operations import DictionaryOperations diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyDictionary/bodydictionary/aio/operations/_dictionary_operations.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyDictionary/bodydictionary/aio/operations/_dictionary_operations.py index 5fa6199a1c5..887b3200735 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyDictionary/bodydictionary/aio/operations/_dictionary_operations.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyDictionary/bodydictionary/aio/operations/_dictionary_operations.py @@ -26,7 +26,7 @@ from azure.core.utils import case_insensitive_dict from ... import models as _models -from ..._serialization import Deserializer, Serializer +from ..._utils.serialization import Deserializer, Serializer from ...operations._dictionary_operations import ( build_get_array_empty_request, build_get_array_item_empty_request, diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyDictionary/bodydictionary/models/_models_py3.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyDictionary/bodydictionary/models/_models_py3.py index 21059e5baf1..6b3bac80ece 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyDictionary/bodydictionary/models/_models_py3.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyDictionary/bodydictionary/models/_models_py3.py @@ -8,7 +8,7 @@ from typing import Any, Optional -from .. import _serialization +from .._utils import serialization as _serialization class Error(_serialization.Model): diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyDictionary/bodydictionary/operations/_dictionary_operations.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyDictionary/bodydictionary/operations/_dictionary_operations.py index c850d3209d9..fb3fb85dd7d 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyDictionary/bodydictionary/operations/_dictionary_operations.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyDictionary/bodydictionary/operations/_dictionary_operations.py @@ -27,7 +27,7 @@ from .. import models as _models from .._configuration import AutoRestSwaggerBATDictionaryServiceConfiguration -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyDuration/bodyduration/_auto_rest_duration_test_service.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyDuration/bodyduration/_auto_rest_duration_test_service.py index 7643379f050..99afed42522 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyDuration/bodyduration/_auto_rest_duration_test_service.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyDuration/bodyduration/_auto_rest_duration_test_service.py @@ -16,7 +16,7 @@ from . import models as _models from ._configuration import AutoRestDurationTestServiceConfiguration -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer from .operations import DurationOperations diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyDuration/bodyduration/_utils/__init__.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyDuration/bodyduration/_utils/__init__.py new file mode 100644 index 00000000000..0af9b28f660 --- /dev/null +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyDuration/bodyduration/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyArrayVersionTolerant/bodyarrayversiontolerant/_serialization.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyDuration/bodyduration/_utils/serialization.py similarity index 100% rename from packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyArrayVersionTolerant/bodyarrayversiontolerant/_serialization.py rename to packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyDuration/bodyduration/_utils/serialization.py diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyDuration/bodyduration/aio/_auto_rest_duration_test_service.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyDuration/bodyduration/aio/_auto_rest_duration_test_service.py index 99edfaf2a7f..b6145cdcadd 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyDuration/bodyduration/aio/_auto_rest_duration_test_service.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyDuration/bodyduration/aio/_auto_rest_duration_test_service.py @@ -15,7 +15,7 @@ from azure.core.rest import AsyncHttpResponse, HttpRequest from .. import models as _models -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import AutoRestDurationTestServiceConfiguration from .operations import DurationOperations diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyDuration/bodyduration/aio/operations/_duration_operations.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyDuration/bodyduration/aio/operations/_duration_operations.py index 4b66edf6816..cf92c57b6cc 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyDuration/bodyduration/aio/operations/_duration_operations.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyDuration/bodyduration/aio/operations/_duration_operations.py @@ -24,7 +24,7 @@ from azure.core.utils import case_insensitive_dict from ... import models as _models -from ..._serialization import Deserializer, Serializer +from ..._utils.serialization import Deserializer, Serializer from ...operations._duration_operations import ( build_get_invalid_request, build_get_null_request, diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyDuration/bodyduration/models/_models_py3.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyDuration/bodyduration/models/_models_py3.py index 1d1b7707def..109cf147510 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyDuration/bodyduration/models/_models_py3.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyDuration/bodyduration/models/_models_py3.py @@ -8,7 +8,7 @@ from typing import Any, Optional -from .. import _serialization +from .._utils import serialization as _serialization class Error(_serialization.Model): diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyDuration/bodyduration/operations/_duration_operations.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyDuration/bodyduration/operations/_duration_operations.py index e504a2de33c..187bbb920cb 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyDuration/bodyduration/operations/_duration_operations.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyDuration/bodyduration/operations/_duration_operations.py @@ -25,7 +25,7 @@ from .. import models as _models from .._configuration import AutoRestDurationTestServiceConfiguration -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyFile/bodyfile/_auto_rest_swagger_bat_file_service.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyFile/bodyfile/_auto_rest_swagger_bat_file_service.py index c7965036b6e..fd478206ea9 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyFile/bodyfile/_auto_rest_swagger_bat_file_service.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyFile/bodyfile/_auto_rest_swagger_bat_file_service.py @@ -16,7 +16,7 @@ from . import models as _models from ._configuration import AutoRestSwaggerBATFileServiceConfiguration -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer from .operations import FilesOperations diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyFile/bodyfile/_utils/__init__.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyFile/bodyfile/_utils/__init__.py new file mode 100644 index 00000000000..0af9b28f660 --- /dev/null +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyFile/bodyfile/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyBinaryVersionTolerant/bodybinaryversiontolerant/_serialization.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyFile/bodyfile/_utils/serialization.py similarity index 100% rename from packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyBinaryVersionTolerant/bodybinaryversiontolerant/_serialization.py rename to packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyFile/bodyfile/_utils/serialization.py diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyFile/bodyfile/aio/_auto_rest_swagger_bat_file_service.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyFile/bodyfile/aio/_auto_rest_swagger_bat_file_service.py index 48c7b77419d..a21db654d46 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyFile/bodyfile/aio/_auto_rest_swagger_bat_file_service.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyFile/bodyfile/aio/_auto_rest_swagger_bat_file_service.py @@ -15,7 +15,7 @@ from azure.core.rest import AsyncHttpResponse, HttpRequest from .. import models as _models -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import AutoRestSwaggerBATFileServiceConfiguration from .operations import FilesOperations diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyFile/bodyfile/aio/operations/_files_operations.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyFile/bodyfile/aio/operations/_files_operations.py index 7569f16fb53..26859db0899 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyFile/bodyfile/aio/operations/_files_operations.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyFile/bodyfile/aio/operations/_files_operations.py @@ -24,7 +24,7 @@ from azure.core.tracing.decorator_async import distributed_trace_async from ... import models as _models -from ..._serialization import Deserializer, Serializer +from ..._utils.serialization import Deserializer, Serializer from ...operations._files_operations import ( build_get_empty_file_request, build_get_file_large_request, diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyFile/bodyfile/models/_models_py3.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyFile/bodyfile/models/_models_py3.py index 1d1b7707def..109cf147510 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyFile/bodyfile/models/_models_py3.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyFile/bodyfile/models/_models_py3.py @@ -8,7 +8,7 @@ from typing import Any, Optional -from .. import _serialization +from .._utils import serialization as _serialization class Error(_serialization.Model): diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyFile/bodyfile/operations/_files_operations.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyFile/bodyfile/operations/_files_operations.py index bf95e26a4f0..ead97ed5b4d 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyFile/bodyfile/operations/_files_operations.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyFile/bodyfile/operations/_files_operations.py @@ -26,7 +26,7 @@ from .. import models as _models from .._configuration import AutoRestSwaggerBATFileServiceConfiguration -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyFormData/bodyformdata/_auto_rest_swagger_bat_form_data_service.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyFormData/bodyformdata/_auto_rest_swagger_bat_form_data_service.py index efacf99fe8f..84c75e0f793 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyFormData/bodyformdata/_auto_rest_swagger_bat_form_data_service.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyFormData/bodyformdata/_auto_rest_swagger_bat_form_data_service.py @@ -16,7 +16,7 @@ from . import models as _models from ._configuration import AutoRestSwaggerBATFormDataServiceConfiguration -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer from .operations import FormdataOperations diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyFormData/bodyformdata/_utils/__init__.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyFormData/bodyformdata/_utils/__init__.py new file mode 100644 index 00000000000..0af9b28f660 --- /dev/null +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyFormData/bodyformdata/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyBooleanVersionTolerant/bodybooleanversiontolerant/_serialization.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyFormData/bodyformdata/_utils/serialization.py similarity index 100% rename from packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyBooleanVersionTolerant/bodybooleanversiontolerant/_serialization.py rename to packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyFormData/bodyformdata/_utils/serialization.py diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyFormData/bodyformdata/aio/_auto_rest_swagger_bat_form_data_service.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyFormData/bodyformdata/aio/_auto_rest_swagger_bat_form_data_service.py index 26be4040cd7..aa416952fe6 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyFormData/bodyformdata/aio/_auto_rest_swagger_bat_form_data_service.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyFormData/bodyformdata/aio/_auto_rest_swagger_bat_form_data_service.py @@ -15,7 +15,7 @@ from azure.core.rest import AsyncHttpResponse, HttpRequest from .. import models as _models -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import AutoRestSwaggerBATFormDataServiceConfiguration from .operations import FormdataOperations diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyFormData/bodyformdata/aio/operations/_formdata_operations.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyFormData/bodyformdata/aio/operations/_formdata_operations.py index b390966aa1c..e9da64cd1f1 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyFormData/bodyformdata/aio/operations/_formdata_operations.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyFormData/bodyformdata/aio/operations/_formdata_operations.py @@ -25,7 +25,7 @@ from azure.core.utils import case_insensitive_dict from ... import models as _models -from ..._serialization import Deserializer, Serializer +from ..._utils.serialization import Deserializer, Serializer from ...operations._formdata_operations import ( build_upload_file_request, build_upload_file_via_body_request, diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyFormData/bodyformdata/models/_models_py3.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyFormData/bodyformdata/models/_models_py3.py index ea317c7f3f6..d2aefa92006 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyFormData/bodyformdata/models/_models_py3.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyFormData/bodyformdata/models/_models_py3.py @@ -8,7 +8,7 @@ from typing import Any, IO, List, Optional -from .. import _serialization +from .._utils import serialization as _serialization class Error(_serialization.Model): diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyFormData/bodyformdata/operations/_formdata_operations.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyFormData/bodyformdata/operations/_formdata_operations.py index c4285502f4e..d50211aa4f7 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyFormData/bodyformdata/operations/_formdata_operations.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyFormData/bodyformdata/operations/_formdata_operations.py @@ -26,7 +26,7 @@ from .. import models as _models from .._configuration import AutoRestSwaggerBATFormDataServiceConfiguration -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyFormUrlEncodedData/bodyformurlencodeddata/_body_forms_data_url_encoded.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyFormUrlEncodedData/bodyformurlencodeddata/_body_forms_data_url_encoded.py index e717719c087..4df823b7690 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyFormUrlEncodedData/bodyformurlencodeddata/_body_forms_data_url_encoded.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyFormUrlEncodedData/bodyformurlencodeddata/_body_forms_data_url_encoded.py @@ -16,7 +16,7 @@ from . import models as _models from ._configuration import BodyFormsDataURLEncodedConfiguration -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer from .operations import FormdataurlencodedOperations diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyFormUrlEncodedData/bodyformurlencodeddata/_utils/__init__.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyFormUrlEncodedData/bodyformurlencodeddata/_utils/__init__.py new file mode 100644 index 00000000000..0af9b28f660 --- /dev/null +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyFormUrlEncodedData/bodyformurlencodeddata/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyByteVersionTolerant/bodybyteversiontolerant/_serialization.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyFormUrlEncodedData/bodyformurlencodeddata/_utils/serialization.py similarity index 100% rename from packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyByteVersionTolerant/bodybyteversiontolerant/_serialization.py rename to packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyFormUrlEncodedData/bodyformurlencodeddata/_utils/serialization.py diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyFormUrlEncodedData/bodyformurlencodeddata/aio/_body_forms_data_url_encoded.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyFormUrlEncodedData/bodyformurlencodeddata/aio/_body_forms_data_url_encoded.py index 64d6491192e..48621c04b1c 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyFormUrlEncodedData/bodyformurlencodeddata/aio/_body_forms_data_url_encoded.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyFormUrlEncodedData/bodyformurlencodeddata/aio/_body_forms_data_url_encoded.py @@ -15,7 +15,7 @@ from azure.core.rest import AsyncHttpResponse, HttpRequest from .. import models as _models -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import BodyFormsDataURLEncodedConfiguration from .operations import FormdataurlencodedOperations diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyFormUrlEncodedData/bodyformurlencodeddata/aio/operations/_formdataurlencoded_operations.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyFormUrlEncodedData/bodyformurlencodeddata/aio/operations/_formdataurlencoded_operations.py index 3cc3ada02db..03b7ca7b031 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyFormUrlEncodedData/bodyformurlencodeddata/aio/operations/_formdataurlencoded_operations.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyFormUrlEncodedData/bodyformurlencodeddata/aio/operations/_formdataurlencoded_operations.py @@ -23,7 +23,7 @@ from azure.core.utils import case_insensitive_dict from ... import models as _models -from ..._serialization import Deserializer, Serializer +from ..._utils.serialization import Deserializer, Serializer from ...operations._formdataurlencoded_operations import ( build_partial_constant_body_request, build_update_pet_with_form_request, diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyFormUrlEncodedData/bodyformurlencodeddata/models/_models_py3.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyFormUrlEncodedData/bodyformurlencodeddata/models/_models_py3.py index d684fe1f617..d5cc95580b2 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyFormUrlEncodedData/bodyformurlencodeddata/models/_models_py3.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyFormUrlEncodedData/bodyformurlencodeddata/models/_models_py3.py @@ -8,7 +8,7 @@ from typing import Any, Optional, TYPE_CHECKING, Union -from .. import _serialization +from .._utils import serialization as _serialization if TYPE_CHECKING: from .. import models as _models diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyFormUrlEncodedData/bodyformurlencodeddata/operations/_formdataurlencoded_operations.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyFormUrlEncodedData/bodyformurlencodeddata/operations/_formdataurlencoded_operations.py index a95b1e8e5b1..096495c6723 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyFormUrlEncodedData/bodyformurlencodeddata/operations/_formdataurlencoded_operations.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyFormUrlEncodedData/bodyformurlencodeddata/operations/_formdataurlencoded_operations.py @@ -24,7 +24,7 @@ from .. import models as _models from .._configuration import BodyFormsDataURLEncodedConfiguration -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyInteger/bodyinteger/_auto_rest_integer_test_service.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyInteger/bodyinteger/_auto_rest_integer_test_service.py index b168153ab0e..ed11337baab 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyInteger/bodyinteger/_auto_rest_integer_test_service.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyInteger/bodyinteger/_auto_rest_integer_test_service.py @@ -16,7 +16,7 @@ from . import models as _models from ._configuration import AutoRestIntegerTestServiceConfiguration -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer from .operations import IntOperations diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyInteger/bodyinteger/_utils/__init__.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyInteger/bodyinteger/_utils/__init__.py new file mode 100644 index 00000000000..0af9b28f660 --- /dev/null +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyInteger/bodyinteger/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyComplexVersionTolerant/bodycomplexversiontolerant/_serialization.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyInteger/bodyinteger/_utils/serialization.py similarity index 100% rename from packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyComplexVersionTolerant/bodycomplexversiontolerant/_serialization.py rename to packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyInteger/bodyinteger/_utils/serialization.py diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyInteger/bodyinteger/aio/_auto_rest_integer_test_service.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyInteger/bodyinteger/aio/_auto_rest_integer_test_service.py index 9cddae1b222..7d54bc40347 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyInteger/bodyinteger/aio/_auto_rest_integer_test_service.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyInteger/bodyinteger/aio/_auto_rest_integer_test_service.py @@ -15,7 +15,7 @@ from azure.core.rest import AsyncHttpResponse, HttpRequest from .. import models as _models -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import AutoRestIntegerTestServiceConfiguration from .operations import IntOperations diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyInteger/bodyinteger/aio/operations/_int_operations_operations.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyInteger/bodyinteger/aio/operations/_int_operations_operations.py index 8bef4a693aa..c1ded16c779 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyInteger/bodyinteger/aio/operations/_int_operations_operations.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyInteger/bodyinteger/aio/operations/_int_operations_operations.py @@ -24,7 +24,7 @@ from azure.core.utils import case_insensitive_dict from ... import models as _models -from ..._serialization import Deserializer, Serializer +from ..._utils.serialization import Deserializer, Serializer from ...operations._int_operations_operations import ( build_get_invalid_request, build_get_invalid_unix_time_request, diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyInteger/bodyinteger/models/_models_py3.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyInteger/bodyinteger/models/_models_py3.py index 1d1b7707def..109cf147510 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyInteger/bodyinteger/models/_models_py3.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyInteger/bodyinteger/models/_models_py3.py @@ -8,7 +8,7 @@ from typing import Any, Optional -from .. import _serialization +from .._utils import serialization as _serialization class Error(_serialization.Model): diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyInteger/bodyinteger/operations/_int_operations_operations.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyInteger/bodyinteger/operations/_int_operations_operations.py index 0e600a8b44c..f1a860f57ae 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyInteger/bodyinteger/operations/_int_operations_operations.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyInteger/bodyinteger/operations/_int_operations_operations.py @@ -25,7 +25,7 @@ from .. import models as _models from .._configuration import AutoRestIntegerTestServiceConfiguration -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyNumber/bodynumber/_auto_rest_number_test_service.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyNumber/bodynumber/_auto_rest_number_test_service.py index cfd550c70fe..b8c468cf2af 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyNumber/bodynumber/_auto_rest_number_test_service.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyNumber/bodynumber/_auto_rest_number_test_service.py @@ -16,7 +16,7 @@ from . import models as _models from ._configuration import AutoRestNumberTestServiceConfiguration -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer from .operations import NumberOperations diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyNumber/bodynumber/_utils/__init__.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyNumber/bodynumber/_utils/__init__.py new file mode 100644 index 00000000000..0af9b28f660 --- /dev/null +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyNumber/bodynumber/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyDateTimeRfc1123VersionTolerant/bodydatetimerfc1123versiontolerant/_serialization.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyNumber/bodynumber/_utils/serialization.py similarity index 100% rename from packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyDateTimeRfc1123VersionTolerant/bodydatetimerfc1123versiontolerant/_serialization.py rename to packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyNumber/bodynumber/_utils/serialization.py diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyNumber/bodynumber/aio/_auto_rest_number_test_service.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyNumber/bodynumber/aio/_auto_rest_number_test_service.py index ede7627b551..13e8626eb87 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyNumber/bodynumber/aio/_auto_rest_number_test_service.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyNumber/bodynumber/aio/_auto_rest_number_test_service.py @@ -15,7 +15,7 @@ from azure.core.rest import AsyncHttpResponse, HttpRequest from .. import models as _models -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import AutoRestNumberTestServiceConfiguration from .operations import NumberOperations diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyNumber/bodynumber/aio/operations/_number_operations.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyNumber/bodynumber/aio/operations/_number_operations.py index 1cbc45decf5..cda48f403fe 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyNumber/bodynumber/aio/operations/_number_operations.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyNumber/bodynumber/aio/operations/_number_operations.py @@ -24,7 +24,7 @@ from azure.core.utils import case_insensitive_dict from ... import models as _models -from ..._serialization import Deserializer, Serializer +from ..._utils.serialization import Deserializer, Serializer from ...operations._number_operations import ( build_get_big_decimal_negative_decimal_request, build_get_big_decimal_positive_decimal_request, diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyNumber/bodynumber/models/_models_py3.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyNumber/bodynumber/models/_models_py3.py index 1d1b7707def..109cf147510 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyNumber/bodynumber/models/_models_py3.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyNumber/bodynumber/models/_models_py3.py @@ -8,7 +8,7 @@ from typing import Any, Optional -from .. import _serialization +from .._utils import serialization as _serialization class Error(_serialization.Model): diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyNumber/bodynumber/operations/_number_operations.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyNumber/bodynumber/operations/_number_operations.py index 2416ee3eb5f..6227c239301 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyNumber/bodynumber/operations/_number_operations.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyNumber/bodynumber/operations/_number_operations.py @@ -25,7 +25,7 @@ from .. import models as _models from .._configuration import AutoRestNumberTestServiceConfiguration -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyString/bodystring/_auto_rest_swagger_bat_service.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyString/bodystring/_auto_rest_swagger_bat_service.py index 60727cd8e5d..7014254d8be 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyString/bodystring/_auto_rest_swagger_bat_service.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyString/bodystring/_auto_rest_swagger_bat_service.py @@ -16,7 +16,7 @@ from . import models as _models from ._configuration import AutoRestSwaggerBATServiceConfiguration -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer from .operations import EnumOperations, StringOperations diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyString/bodystring/_utils/__init__.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyString/bodystring/_utils/__init__.py new file mode 100644 index 00000000000..0af9b28f660 --- /dev/null +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyString/bodystring/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyDateTimeVersionTolerant/bodydatetimeversiontolerant/_serialization.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyString/bodystring/_utils/serialization.py similarity index 100% rename from packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyDateTimeVersionTolerant/bodydatetimeversiontolerant/_serialization.py rename to packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyString/bodystring/_utils/serialization.py diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyString/bodystring/aio/_auto_rest_swagger_bat_service.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyString/bodystring/aio/_auto_rest_swagger_bat_service.py index b875996672c..1a8bff82256 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyString/bodystring/aio/_auto_rest_swagger_bat_service.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyString/bodystring/aio/_auto_rest_swagger_bat_service.py @@ -15,7 +15,7 @@ from azure.core.rest import AsyncHttpResponse, HttpRequest from .. import models as _models -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import AutoRestSwaggerBATServiceConfiguration from .operations import EnumOperations, StringOperations diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyString/bodystring/aio/operations/_enum_operations.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyString/bodystring/aio/operations/_enum_operations.py index c8196cdc268..1239ca14213 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyString/bodystring/aio/operations/_enum_operations.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyString/bodystring/aio/operations/_enum_operations.py @@ -23,7 +23,7 @@ from azure.core.utils import case_insensitive_dict from ... import models as _models -from ..._serialization import Deserializer, Serializer +from ..._utils.serialization import Deserializer, Serializer from ...operations._enum_operations import ( build_get_not_expandable_request, build_get_referenced_constant_request, diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyString/bodystring/aio/operations/_string_operations.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyString/bodystring/aio/operations/_string_operations.py index bcc07d80709..fda82b9cb5d 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyString/bodystring/aio/operations/_string_operations.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyString/bodystring/aio/operations/_string_operations.py @@ -23,7 +23,7 @@ from azure.core.utils import case_insensitive_dict from ... import models as _models -from ..._serialization import Deserializer, Serializer +from ..._utils.serialization import Deserializer, Serializer from ...operations._string_operations import ( build_get_base64_encoded_request, build_get_base64_url_encoded_request, diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyString/bodystring/models/_models_py3.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyString/bodystring/models/_models_py3.py index 4a9643cf3a3..0512de43feb 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyString/bodystring/models/_models_py3.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyString/bodystring/models/_models_py3.py @@ -8,7 +8,7 @@ from typing import Any, Optional -from .. import _serialization +from .._utils import serialization as _serialization class Error(_serialization.Model): diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyString/bodystring/operations/_enum_operations.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyString/bodystring/operations/_enum_operations.py index f4193526138..902041fa359 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyString/bodystring/operations/_enum_operations.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyString/bodystring/operations/_enum_operations.py @@ -24,7 +24,7 @@ from .. import models as _models from .._configuration import AutoRestSwaggerBATServiceConfiguration -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyString/bodystring/operations/_string_operations.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyString/bodystring/operations/_string_operations.py index 4c1380363fd..1215ffc27cd 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyString/bodystring/operations/_string_operations.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyString/bodystring/operations/_string_operations.py @@ -24,7 +24,7 @@ from .. import models as _models from .._configuration import AutoRestSwaggerBATServiceConfiguration -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyTime/bodytime/_auto_rest_time_test_service.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyTime/bodytime/_auto_rest_time_test_service.py index 512d818518e..ceec08f7001 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyTime/bodytime/_auto_rest_time_test_service.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyTime/bodytime/_auto_rest_time_test_service.py @@ -16,7 +16,7 @@ from . import models as _models from ._configuration import AutoRestTimeTestServiceConfiguration -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer from .operations import TimeOperations diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyTime/bodytime/_utils/__init__.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyTime/bodytime/_utils/__init__.py new file mode 100644 index 00000000000..0af9b28f660 --- /dev/null +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyTime/bodytime/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyDateVersionTolerant/bodydateversiontolerant/_serialization.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyTime/bodytime/_utils/serialization.py similarity index 100% rename from packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyDateVersionTolerant/bodydateversiontolerant/_serialization.py rename to packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyTime/bodytime/_utils/serialization.py diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyTime/bodytime/aio/_auto_rest_time_test_service.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyTime/bodytime/aio/_auto_rest_time_test_service.py index 4f89aee52af..85e9226f32b 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyTime/bodytime/aio/_auto_rest_time_test_service.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyTime/bodytime/aio/_auto_rest_time_test_service.py @@ -15,7 +15,7 @@ from azure.core.rest import AsyncHttpResponse, HttpRequest from .. import models as _models -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import AutoRestTimeTestServiceConfiguration from .operations import TimeOperations diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyTime/bodytime/aio/operations/_time_operations.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyTime/bodytime/aio/operations/_time_operations.py index b02019aa7ce..a2e5c616052 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyTime/bodytime/aio/operations/_time_operations.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyTime/bodytime/aio/operations/_time_operations.py @@ -24,7 +24,7 @@ from azure.core.utils import case_insensitive_dict from ... import models as _models -from ..._serialization import Deserializer, Serializer +from ..._utils.serialization import Deserializer, Serializer from ...operations._time_operations import build_get_request, build_put_request from .._configuration import AutoRestTimeTestServiceConfiguration diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyTime/bodytime/models/_models_py3.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyTime/bodytime/models/_models_py3.py index 1d1b7707def..109cf147510 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyTime/bodytime/models/_models_py3.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyTime/bodytime/models/_models_py3.py @@ -8,7 +8,7 @@ from typing import Any, Optional -from .. import _serialization +from .._utils import serialization as _serialization class Error(_serialization.Model): diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyTime/bodytime/operations/_time_operations.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyTime/bodytime/operations/_time_operations.py index ce14b58d532..e2737f64df8 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyTime/bodytime/operations/_time_operations.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/BodyTime/bodytime/operations/_time_operations.py @@ -25,7 +25,7 @@ from .. import models as _models from .._configuration import AutoRestTimeTestServiceConfiguration -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ClientEnum/clientenum/_client_with_enum.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ClientEnum/clientenum/_client_with_enum.py index eff66ae0348..56a8101e5cf 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ClientEnum/clientenum/_client_with_enum.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ClientEnum/clientenum/_client_with_enum.py @@ -16,7 +16,7 @@ from . import models as _models from ._configuration import ClientWithEnumConfiguration -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer from .operations import ClientWithEnumOperationsMixin diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ClientEnum/clientenum/_utils/__init__.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ClientEnum/clientenum/_utils/__init__.py new file mode 100644 index 00000000000..0af9b28f660 --- /dev/null +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ClientEnum/clientenum/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyDictionaryVersionTolerant/bodydictionaryversiontolerant/_serialization.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ClientEnum/clientenum/_utils/serialization.py similarity index 100% rename from packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyDictionaryVersionTolerant/bodydictionaryversiontolerant/_serialization.py rename to packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ClientEnum/clientenum/_utils/serialization.py diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ClientEnum/clientenum/_utils/utils.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ClientEnum/clientenum/_utils/utils.py new file mode 100644 index 00000000000..39b612f39a9 --- /dev/null +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ClientEnum/clientenum/_utils/utils.py @@ -0,0 +1,25 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from abc import ABC +from typing import Generic, TYPE_CHECKING, TypeVar + +if TYPE_CHECKING: + from .serialization import Deserializer, Serializer + + +TClient = TypeVar("TClient") +TConfig = TypeVar("TConfig") + + +class ClientMixinABC(ABC, Generic[TClient, TConfig]): + """DO NOT use this class. It is for internal typing use only.""" + + _client: TClient + _config: TConfig + _serialize: "Serializer" + _deserialize: "Deserializer" diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ClientEnum/clientenum/_vendor.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ClientEnum/clientenum/_vendor.py deleted file mode 100644 index f74d78ebfa4..00000000000 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ClientEnum/clientenum/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) AutoRest Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import ClientWithEnumConfiguration - -if TYPE_CHECKING: - from azure.core import PipelineClient - - from ._serialization import Deserializer, Serializer - - -class ClientWithEnumMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "PipelineClient" - _config: ClientWithEnumConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ClientEnum/clientenum/aio/_client_with_enum.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ClientEnum/clientenum/aio/_client_with_enum.py index b4a94507ab2..9b3e6e0b7ba 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ClientEnum/clientenum/aio/_client_with_enum.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ClientEnum/clientenum/aio/_client_with_enum.py @@ -15,7 +15,7 @@ from azure.core.rest import AsyncHttpResponse, HttpRequest from .. import models as _models -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import ClientWithEnumConfiguration from .operations import ClientWithEnumOperationsMixin diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ClientEnum/clientenum/aio/_vendor.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ClientEnum/clientenum/aio/_vendor.py deleted file mode 100644 index 121f3fa2125..00000000000 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ClientEnum/clientenum/aio/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) AutoRest Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import ClientWithEnumConfiguration - -if TYPE_CHECKING: - from azure.core import AsyncPipelineClient - - from .._serialization import Deserializer, Serializer - - -class ClientWithEnumMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "AsyncPipelineClient" - _config: ClientWithEnumConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ClientEnum/clientenum/aio/operations/_client_with_enum_operations.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ClientEnum/clientenum/aio/operations/_client_with_enum_operations.py index 2c6366368b4..efe933189bf 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ClientEnum/clientenum/aio/operations/_client_with_enum_operations.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ClientEnum/clientenum/aio/operations/_client_with_enum_operations.py @@ -9,6 +9,7 @@ from collections.abc import MutableMapping from typing import Any, Callable, Dict, Optional, TypeVar +from azure.core import AsyncPipelineClient from azure.core.exceptions import ( ClientAuthenticationError, HttpResponseError, @@ -21,14 +22,15 @@ from azure.core.rest import AsyncHttpResponse, HttpRequest from azure.core.tracing.decorator_async import distributed_trace_async +from ..._utils.utils import ClientMixinABC from ...operations._client_with_enum_operations import build_head_request -from .._vendor import ClientWithEnumMixinABC +from .._configuration import ClientWithEnumConfiguration T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, AsyncHttpResponse], T, Dict[str, Any]], Any]] -class ClientWithEnumOperationsMixin(ClientWithEnumMixinABC): +class ClientWithEnumOperationsMixin(ClientMixinABC[AsyncPipelineClient, ClientWithEnumConfiguration]): @distributed_trace_async async def head(self, **kwargs: Any) -> None: diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ClientEnum/clientenum/models/_models_py3.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ClientEnum/clientenum/models/_models_py3.py index 1d1b7707def..109cf147510 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ClientEnum/clientenum/models/_models_py3.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ClientEnum/clientenum/models/_models_py3.py @@ -8,7 +8,7 @@ from typing import Any, Optional -from .. import _serialization +from .._utils import serialization as _serialization class Error(_serialization.Model): diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ClientEnum/clientenum/operations/_client_with_enum_operations.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ClientEnum/clientenum/operations/_client_with_enum_operations.py index 5af82576f27..d0a80a31a8e 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ClientEnum/clientenum/operations/_client_with_enum_operations.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ClientEnum/clientenum/operations/_client_with_enum_operations.py @@ -8,6 +8,7 @@ from collections.abc import MutableMapping from typing import Any, Callable, Dict, Optional, TypeVar, Union +from azure.core import PipelineClient from azure.core.exceptions import ( ClientAuthenticationError, HttpResponseError, @@ -22,8 +23,9 @@ from azure.core.utils import case_insensitive_dict from .. import models as _models -from .._serialization import Serializer -from .._vendor import ClientWithEnumMixinABC +from .._configuration import ClientWithEnumConfiguration +from .._utils.serialization import Serializer +from .._utils.utils import ClientMixinABC T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] @@ -44,7 +46,7 @@ def build_head_request(*, x_ms_enum: Union[str, _models.Enum0], **kwargs: Any) - return HttpRequest(method="HEAD", url=_url, headers=_headers, **kwargs) -class ClientWithEnumOperationsMixin(ClientWithEnumMixinABC): +class ClientWithEnumOperationsMixin(ClientMixinABC[PipelineClient, ClientWithEnumConfiguration]): @distributed_trace def head(self, **kwargs: Any) -> None: # pylint: disable=inconsistent-return-statements diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Constants/constants/_auto_rest_swagger_constant_service.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Constants/constants/_auto_rest_swagger_constant_service.py index a35a30f78b4..d6358e02604 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Constants/constants/_auto_rest_swagger_constant_service.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Constants/constants/_auto_rest_swagger_constant_service.py @@ -16,7 +16,7 @@ from . import models as _models from ._configuration import AutoRestSwaggerConstantServiceConfiguration -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer from .operations import ContantsOperations diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Constants/constants/_utils/__init__.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Constants/constants/_utils/__init__.py new file mode 100644 index 00000000000..0af9b28f660 --- /dev/null +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Constants/constants/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyDurationVersionTolerant/bodydurationversiontolerant/_serialization.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Constants/constants/_utils/serialization.py similarity index 100% rename from packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyDurationVersionTolerant/bodydurationversiontolerant/_serialization.py rename to packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Constants/constants/_utils/serialization.py diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Constants/constants/aio/_auto_rest_swagger_constant_service.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Constants/constants/aio/_auto_rest_swagger_constant_service.py index a65b8ff64a3..68fc1044126 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Constants/constants/aio/_auto_rest_swagger_constant_service.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Constants/constants/aio/_auto_rest_swagger_constant_service.py @@ -15,7 +15,7 @@ from azure.core.rest import AsyncHttpResponse, HttpRequest from .. import models as _models -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import AutoRestSwaggerConstantServiceConfiguration from .operations import ContantsOperations diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Constants/constants/aio/operations/_contants_operations.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Constants/constants/aio/operations/_contants_operations.py index 081acf41662..e7457973fd0 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Constants/constants/aio/operations/_contants_operations.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Constants/constants/aio/operations/_contants_operations.py @@ -23,7 +23,7 @@ from azure.core.utils import case_insensitive_dict from ... import models as _models -from ..._serialization import Deserializer, Serializer +from ..._utils.serialization import Deserializer, Serializer from ...operations._contants_operations import ( build_put_client_constants_request, build_put_model_as_string_no_required_one_value_default_request, diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Constants/constants/models/_models_py3.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Constants/constants/models/_models_py3.py index 3f916138cc1..649f3681a60 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Constants/constants/models/_models_py3.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Constants/constants/models/_models_py3.py @@ -8,7 +8,7 @@ from typing import Any, Literal, Optional, TYPE_CHECKING, Union -from .. import _serialization +from .._utils import serialization as _serialization if TYPE_CHECKING: from .. import models as _models diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Constants/constants/operations/_contants_operations.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Constants/constants/operations/_contants_operations.py index c773029d90d..89ec0a2f906 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Constants/constants/operations/_contants_operations.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Constants/constants/operations/_contants_operations.py @@ -25,7 +25,7 @@ from .. import models as _models from .._configuration import AutoRestSwaggerConstantServiceConfiguration -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/CustomBaseUriMoreOptions/custombaseurlmoreoptions/_auto_rest_parameterized_custom_host_test_client.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/CustomBaseUriMoreOptions/custombaseurlmoreoptions/_auto_rest_parameterized_custom_host_test_client.py index 1e29d08faab..c06d791f868 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/CustomBaseUriMoreOptions/custombaseurlmoreoptions/_auto_rest_parameterized_custom_host_test_client.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/CustomBaseUriMoreOptions/custombaseurlmoreoptions/_auto_rest_parameterized_custom_host_test_client.py @@ -16,7 +16,7 @@ from . import models as _models from ._configuration import AutoRestParameterizedCustomHostTestClientConfiguration -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer from .operations import PathsOperations diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/CustomBaseUriMoreOptions/custombaseurlmoreoptions/_utils/__init__.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/CustomBaseUriMoreOptions/custombaseurlmoreoptions/_utils/__init__.py new file mode 100644 index 00000000000..0af9b28f660 --- /dev/null +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/CustomBaseUriMoreOptions/custombaseurlmoreoptions/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyFileVersionTolerant/bodyfileversiontolerant/_serialization.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/CustomBaseUriMoreOptions/custombaseurlmoreoptions/_utils/serialization.py similarity index 100% rename from packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyFileVersionTolerant/bodyfileversiontolerant/_serialization.py rename to packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/CustomBaseUriMoreOptions/custombaseurlmoreoptions/_utils/serialization.py diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/CustomBaseUriMoreOptions/custombaseurlmoreoptions/aio/_auto_rest_parameterized_custom_host_test_client.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/CustomBaseUriMoreOptions/custombaseurlmoreoptions/aio/_auto_rest_parameterized_custom_host_test_client.py index 0e812ec669b..b7025a26a44 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/CustomBaseUriMoreOptions/custombaseurlmoreoptions/aio/_auto_rest_parameterized_custom_host_test_client.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/CustomBaseUriMoreOptions/custombaseurlmoreoptions/aio/_auto_rest_parameterized_custom_host_test_client.py @@ -15,7 +15,7 @@ from azure.core.rest import AsyncHttpResponse, HttpRequest from .. import models as _models -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import AutoRestParameterizedCustomHostTestClientConfiguration from .operations import PathsOperations diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/CustomBaseUriMoreOptions/custombaseurlmoreoptions/aio/operations/_paths_operations.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/CustomBaseUriMoreOptions/custombaseurlmoreoptions/aio/operations/_paths_operations.py index 62a2aea5e1e..8ad8f5a6a1d 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/CustomBaseUriMoreOptions/custombaseurlmoreoptions/aio/operations/_paths_operations.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/CustomBaseUriMoreOptions/custombaseurlmoreoptions/aio/operations/_paths_operations.py @@ -22,7 +22,7 @@ from azure.core.tracing.decorator_async import distributed_trace_async from ... import models as _models -from ..._serialization import Deserializer, Serializer +from ..._utils.serialization import Deserializer, Serializer from ...operations._paths_operations import build_get_empty_request from .._configuration import AutoRestParameterizedCustomHostTestClientConfiguration diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/CustomBaseUriMoreOptions/custombaseurlmoreoptions/models/_models_py3.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/CustomBaseUriMoreOptions/custombaseurlmoreoptions/models/_models_py3.py index 1d1b7707def..109cf147510 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/CustomBaseUriMoreOptions/custombaseurlmoreoptions/models/_models_py3.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/CustomBaseUriMoreOptions/custombaseurlmoreoptions/models/_models_py3.py @@ -8,7 +8,7 @@ from typing import Any, Optional -from .. import _serialization +from .._utils import serialization as _serialization class Error(_serialization.Model): diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/CustomBaseUriMoreOptions/custombaseurlmoreoptions/operations/_paths_operations.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/CustomBaseUriMoreOptions/custombaseurlmoreoptions/operations/_paths_operations.py index 7c9b7fe4190..574eff9f8b7 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/CustomBaseUriMoreOptions/custombaseurlmoreoptions/operations/_paths_operations.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/CustomBaseUriMoreOptions/custombaseurlmoreoptions/operations/_paths_operations.py @@ -24,7 +24,7 @@ from .. import models as _models from .._configuration import AutoRestParameterizedCustomHostTestClientConfiguration -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ErrorWithSecrets/errorwithsecrets/_error_with_secrets.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ErrorWithSecrets/errorwithsecrets/_error_with_secrets.py index a694454bd0b..03f3a4762bc 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ErrorWithSecrets/errorwithsecrets/_error_with_secrets.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ErrorWithSecrets/errorwithsecrets/_error_with_secrets.py @@ -16,7 +16,7 @@ from . import models as _models from ._configuration import ErrorWithSecretsConfiguration -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer from .operations import ErrorWithSecretsOperationsMixin diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ErrorWithSecrets/errorwithsecrets/_utils/__init__.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ErrorWithSecrets/errorwithsecrets/_utils/__init__.py new file mode 100644 index 00000000000..0af9b28f660 --- /dev/null +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ErrorWithSecrets/errorwithsecrets/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyFormDataVersionTolerant/bodyformdataversiontolerant/_serialization.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ErrorWithSecrets/errorwithsecrets/_utils/serialization.py similarity index 100% rename from packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyFormDataVersionTolerant/bodyformdataversiontolerant/_serialization.py rename to packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ErrorWithSecrets/errorwithsecrets/_utils/serialization.py diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ErrorWithSecrets/errorwithsecrets/_utils/utils.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ErrorWithSecrets/errorwithsecrets/_utils/utils.py new file mode 100644 index 00000000000..39b612f39a9 --- /dev/null +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ErrorWithSecrets/errorwithsecrets/_utils/utils.py @@ -0,0 +1,25 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from abc import ABC +from typing import Generic, TYPE_CHECKING, TypeVar + +if TYPE_CHECKING: + from .serialization import Deserializer, Serializer + + +TClient = TypeVar("TClient") +TConfig = TypeVar("TConfig") + + +class ClientMixinABC(ABC, Generic[TClient, TConfig]): + """DO NOT use this class. It is for internal typing use only.""" + + _client: TClient + _config: TConfig + _serialize: "Serializer" + _deserialize: "Deserializer" diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ErrorWithSecrets/errorwithsecrets/_vendor.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ErrorWithSecrets/errorwithsecrets/_vendor.py deleted file mode 100644 index fb1aa891cce..00000000000 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ErrorWithSecrets/errorwithsecrets/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) AutoRest Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import ErrorWithSecretsConfiguration - -if TYPE_CHECKING: - from azure.core import PipelineClient - - from ._serialization import Deserializer, Serializer - - -class ErrorWithSecretsMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "PipelineClient" - _config: ErrorWithSecretsConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ErrorWithSecrets/errorwithsecrets/aio/_error_with_secrets.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ErrorWithSecrets/errorwithsecrets/aio/_error_with_secrets.py index cef6bbbccf0..0570c352fc2 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ErrorWithSecrets/errorwithsecrets/aio/_error_with_secrets.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ErrorWithSecrets/errorwithsecrets/aio/_error_with_secrets.py @@ -15,7 +15,7 @@ from azure.core.rest import AsyncHttpResponse, HttpRequest from .. import models as _models -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import ErrorWithSecretsConfiguration from .operations import ErrorWithSecretsOperationsMixin diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ErrorWithSecrets/errorwithsecrets/aio/_vendor.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ErrorWithSecrets/errorwithsecrets/aio/_vendor.py deleted file mode 100644 index e000cbd9842..00000000000 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ErrorWithSecrets/errorwithsecrets/aio/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) AutoRest Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import ErrorWithSecretsConfiguration - -if TYPE_CHECKING: - from azure.core import AsyncPipelineClient - - from .._serialization import Deserializer, Serializer - - -class ErrorWithSecretsMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "AsyncPipelineClient" - _config: ErrorWithSecretsConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ErrorWithSecrets/errorwithsecrets/aio/operations/_error_with_secrets_operations.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ErrorWithSecrets/errorwithsecrets/aio/operations/_error_with_secrets_operations.py index 0afea1ffa84..f50d0dd7ee6 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ErrorWithSecrets/errorwithsecrets/aio/operations/_error_with_secrets_operations.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ErrorWithSecrets/errorwithsecrets/aio/operations/_error_with_secrets_operations.py @@ -9,6 +9,7 @@ from collections.abc import MutableMapping from typing import Any, Callable, Dict, Optional, TypeVar +from azure.core import AsyncPipelineClient from azure.core.exceptions import ( ClientAuthenticationError, HttpResponseError, @@ -22,17 +23,18 @@ from azure.core.tracing.decorator_async import distributed_trace_async from ... import models as _models +from ..._utils.utils import ClientMixinABC from ...operations._error_with_secrets_operations import ( build_create_secret_request, build_get_error_with_secrets_request, ) -from .._vendor import ErrorWithSecretsMixinABC +from .._configuration import ErrorWithSecretsConfiguration T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, AsyncHttpResponse], T, Dict[str, Any]], Any]] -class ErrorWithSecretsOperationsMixin(ErrorWithSecretsMixinABC): +class ErrorWithSecretsOperationsMixin(ClientMixinABC[AsyncPipelineClient, ErrorWithSecretsConfiguration]): @distributed_trace_async async def create_secret(self, **kwargs: Any) -> _models.SecretResponse: diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ErrorWithSecrets/errorwithsecrets/models/_models_py3.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ErrorWithSecrets/errorwithsecrets/models/_models_py3.py index 0721c41ba08..5331dd82e22 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ErrorWithSecrets/errorwithsecrets/models/_models_py3.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ErrorWithSecrets/errorwithsecrets/models/_models_py3.py @@ -8,7 +8,7 @@ from typing import Any, Dict, List, Optional, TYPE_CHECKING, Union -from .. import _serialization +from .._utils import serialization as _serialization if TYPE_CHECKING: from .. import models as _models diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ErrorWithSecrets/errorwithsecrets/operations/_error_with_secrets_operations.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ErrorWithSecrets/errorwithsecrets/operations/_error_with_secrets_operations.py index 1042c8e913c..4d93eca79e9 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ErrorWithSecrets/errorwithsecrets/operations/_error_with_secrets_operations.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ErrorWithSecrets/errorwithsecrets/operations/_error_with_secrets_operations.py @@ -8,6 +8,7 @@ from collections.abc import MutableMapping from typing import Any, Callable, Dict, Optional, TypeVar +from azure.core import PipelineClient from azure.core.exceptions import ( ClientAuthenticationError, HttpResponseError, @@ -22,8 +23,9 @@ from azure.core.utils import case_insensitive_dict from .. import models as _models -from .._serialization import Serializer -from .._vendor import ErrorWithSecretsMixinABC +from .._configuration import ErrorWithSecretsConfiguration +from .._utils.serialization import Serializer +from .._utils.utils import ClientMixinABC T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] @@ -60,7 +62,7 @@ def build_get_error_with_secrets_request(**kwargs: Any) -> HttpRequest: return HttpRequest(method="GET", url=_url, headers=_headers, **kwargs) -class ErrorWithSecretsOperationsMixin(ErrorWithSecretsMixinABC): +class ErrorWithSecretsOperationsMixin(ClientMixinABC[PipelineClient, ErrorWithSecretsConfiguration]): @distributed_trace def create_secret(self, **kwargs: Any) -> _models.SecretResponse: diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ExtensibleEnums/extensibleenumsswagger/_pet_store_inc.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ExtensibleEnums/extensibleenumsswagger/_pet_store_inc.py index 000dfd95eb9..338b740558c 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ExtensibleEnums/extensibleenumsswagger/_pet_store_inc.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ExtensibleEnums/extensibleenumsswagger/_pet_store_inc.py @@ -16,7 +16,7 @@ from . import models as _models from ._configuration import PetStoreIncConfiguration -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer from .operations import PetOperations diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ExtensibleEnums/extensibleenumsswagger/_utils/__init__.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ExtensibleEnums/extensibleenumsswagger/_utils/__init__.py new file mode 100644 index 00000000000..0af9b28f660 --- /dev/null +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ExtensibleEnums/extensibleenumsswagger/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyFormUrlEncodedDataVersionTolerant/bodyformurlencodeddataversiontolerant/_serialization.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ExtensibleEnums/extensibleenumsswagger/_utils/serialization.py similarity index 100% rename from packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyFormUrlEncodedDataVersionTolerant/bodyformurlencodeddataversiontolerant/_serialization.py rename to packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ExtensibleEnums/extensibleenumsswagger/_utils/serialization.py diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ExtensibleEnums/extensibleenumsswagger/aio/_pet_store_inc.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ExtensibleEnums/extensibleenumsswagger/aio/_pet_store_inc.py index 00763655f60..4c99309a65b 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ExtensibleEnums/extensibleenumsswagger/aio/_pet_store_inc.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ExtensibleEnums/extensibleenumsswagger/aio/_pet_store_inc.py @@ -15,7 +15,7 @@ from azure.core.rest import AsyncHttpResponse, HttpRequest from .. import models as _models -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import PetStoreIncConfiguration from .operations import PetOperations diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ExtensibleEnums/extensibleenumsswagger/aio/operations/_pet_operations.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ExtensibleEnums/extensibleenumsswagger/aio/operations/_pet_operations.py index 286df5418f9..abeaf371ed3 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ExtensibleEnums/extensibleenumsswagger/aio/operations/_pet_operations.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ExtensibleEnums/extensibleenumsswagger/aio/operations/_pet_operations.py @@ -24,7 +24,7 @@ from azure.core.utils import case_insensitive_dict from ... import models as _models -from ..._serialization import Deserializer, Serializer +from ..._utils.serialization import Deserializer, Serializer from ...operations._pet_operations import build_add_pet_request, build_get_by_pet_id_request from .._configuration import PetStoreIncConfiguration diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ExtensibleEnums/extensibleenumsswagger/models/_models_py3.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ExtensibleEnums/extensibleenumsswagger/models/_models_py3.py index 34a5f6ea52b..157fe9af036 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ExtensibleEnums/extensibleenumsswagger/models/_models_py3.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ExtensibleEnums/extensibleenumsswagger/models/_models_py3.py @@ -8,7 +8,7 @@ from typing import Any, Optional, TYPE_CHECKING, Union -from .. import _serialization +from .._utils import serialization as _serialization if TYPE_CHECKING: from .. import models as _models diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ExtensibleEnums/extensibleenumsswagger/operations/_pet_operations.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ExtensibleEnums/extensibleenumsswagger/operations/_pet_operations.py index 7ba6f98420a..628ce4956d3 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ExtensibleEnums/extensibleenumsswagger/operations/_pet_operations.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ExtensibleEnums/extensibleenumsswagger/operations/_pet_operations.py @@ -25,7 +25,7 @@ from .. import models as _models from .._configuration import PetStoreIncConfiguration -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Header/header/_auto_rest_swagger_bat_header_service.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Header/header/_auto_rest_swagger_bat_header_service.py index 7dad12189c9..67bf8f1c59d 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Header/header/_auto_rest_swagger_bat_header_service.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Header/header/_auto_rest_swagger_bat_header_service.py @@ -16,7 +16,7 @@ from . import models as _models from ._configuration import AutoRestSwaggerBATHeaderServiceConfiguration -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer from .operations import HeaderOperations diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Header/header/_utils/__init__.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Header/header/_utils/__init__.py new file mode 100644 index 00000000000..0af9b28f660 --- /dev/null +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Header/header/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyIntegerVersionTolerant/bodyintegerversiontolerant/_serialization.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Header/header/_utils/serialization.py similarity index 100% rename from packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyIntegerVersionTolerant/bodyintegerversiontolerant/_serialization.py rename to packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Header/header/_utils/serialization.py diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Header/header/aio/_auto_rest_swagger_bat_header_service.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Header/header/aio/_auto_rest_swagger_bat_header_service.py index 100e519edf5..b0b86936111 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Header/header/aio/_auto_rest_swagger_bat_header_service.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Header/header/aio/_auto_rest_swagger_bat_header_service.py @@ -15,7 +15,7 @@ from azure.core.rest import AsyncHttpResponse, HttpRequest from .. import models as _models -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import AutoRestSwaggerBATHeaderServiceConfiguration from .operations import HeaderOperations diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Header/header/aio/operations/_header_operations.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Header/header/aio/operations/_header_operations.py index 5de6500e647..15408472301 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Header/header/aio/operations/_header_operations.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Header/header/aio/operations/_header_operations.py @@ -24,7 +24,7 @@ from azure.core.tracing.decorator_async import distributed_trace_async from ... import models as _models -from ..._serialization import Deserializer, Serializer +from ..._utils.serialization import Deserializer, Serializer from ...operations._header_operations import ( build_custom_request_id_request, build_param_bool_request, diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Header/header/models/_models_py3.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Header/header/models/_models_py3.py index 1d1b7707def..109cf147510 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Header/header/models/_models_py3.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Header/header/models/_models_py3.py @@ -8,7 +8,7 @@ from typing import Any, Optional -from .. import _serialization +from .._utils import serialization as _serialization class Error(_serialization.Model): diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Header/header/operations/_header_operations.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Header/header/operations/_header_operations.py index 891978e5c06..7b38ac4ba32 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Header/header/operations/_header_operations.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Header/header/operations/_header_operations.py @@ -26,7 +26,7 @@ from .. import models as _models from .._configuration import AutoRestSwaggerBATHeaderServiceConfiguration -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Http/httpinfrastructure/_auto_rest_http_infrastructure_test_service.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Http/httpinfrastructure/_auto_rest_http_infrastructure_test_service.py index 09db2dc2eae..0aeb041b2f0 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Http/httpinfrastructure/_auto_rest_http_infrastructure_test_service.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Http/httpinfrastructure/_auto_rest_http_infrastructure_test_service.py @@ -17,7 +17,7 @@ from . import models as _models from ._configuration import AutoRestHttpInfrastructureTestServiceConfiguration -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer from .operations import ( HttpClientFailureOperations, HttpFailureOperations, diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Http/httpinfrastructure/_utils/__init__.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Http/httpinfrastructure/_utils/__init__.py new file mode 100644 index 00000000000..0af9b28f660 --- /dev/null +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Http/httpinfrastructure/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyNumberVersionTolerant/bodynumberversiontolerant/_serialization.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Http/httpinfrastructure/_utils/serialization.py similarity index 100% rename from packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyNumberVersionTolerant/bodynumberversiontolerant/_serialization.py rename to packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Http/httpinfrastructure/_utils/serialization.py diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Http/httpinfrastructure/aio/_auto_rest_http_infrastructure_test_service.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Http/httpinfrastructure/aio/_auto_rest_http_infrastructure_test_service.py index 32296ce1cb4..03154ee926f 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Http/httpinfrastructure/aio/_auto_rest_http_infrastructure_test_service.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Http/httpinfrastructure/aio/_auto_rest_http_infrastructure_test_service.py @@ -16,7 +16,7 @@ from azure.core.rest import AsyncHttpResponse, HttpRequest from .. import models as _models -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import AutoRestHttpInfrastructureTestServiceConfiguration from .operations import ( HttpClientFailureOperations, diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Http/httpinfrastructure/aio/operations/_http_client_failure_operations.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Http/httpinfrastructure/aio/operations/_http_client_failure_operations.py index b0a6f6b676f..dc40330b4a7 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Http/httpinfrastructure/aio/operations/_http_client_failure_operations.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Http/httpinfrastructure/aio/operations/_http_client_failure_operations.py @@ -24,7 +24,7 @@ from azure.core.utils import case_insensitive_dict from ... import models as _models -from ..._serialization import Deserializer, Serializer +from ..._utils.serialization import Deserializer, Serializer from ...operations._http_client_failure_operations import ( build_delete400_request, build_delete407_request, diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Http/httpinfrastructure/aio/operations/_http_failure_operations.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Http/httpinfrastructure/aio/operations/_http_failure_operations.py index 75e67f8ecf3..13978972119 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Http/httpinfrastructure/aio/operations/_http_failure_operations.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Http/httpinfrastructure/aio/operations/_http_failure_operations.py @@ -22,7 +22,7 @@ from azure.core.tracing.decorator_async import distributed_trace_async from ... import models as _models -from ..._serialization import Deserializer, Serializer +from ..._utils.serialization import Deserializer, Serializer from ...operations._http_failure_operations import ( build_get_empty_error_request, build_get_no_model_empty_request, diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Http/httpinfrastructure/aio/operations/_http_redirects_operations.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Http/httpinfrastructure/aio/operations/_http_redirects_operations.py index 589d3bff28f..c63118efbee 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Http/httpinfrastructure/aio/operations/_http_redirects_operations.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Http/httpinfrastructure/aio/operations/_http_redirects_operations.py @@ -23,7 +23,7 @@ from azure.core.utils import case_insensitive_dict from ... import models as _models -from ..._serialization import Deserializer, Serializer +from ..._utils.serialization import Deserializer, Serializer from ...operations._http_redirects_operations import ( build_delete307_request, build_get300_request, diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Http/httpinfrastructure/aio/operations/_http_retry_operations.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Http/httpinfrastructure/aio/operations/_http_retry_operations.py index e0263e674c7..ed768fe5cf0 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Http/httpinfrastructure/aio/operations/_http_retry_operations.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Http/httpinfrastructure/aio/operations/_http_retry_operations.py @@ -23,7 +23,7 @@ from azure.core.utils import case_insensitive_dict from ... import models as _models -from ..._serialization import Deserializer, Serializer +from ..._utils.serialization import Deserializer, Serializer from ...operations._http_retry_operations import ( build_delete503_request, build_get502_request, diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Http/httpinfrastructure/aio/operations/_http_server_failure_operations.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Http/httpinfrastructure/aio/operations/_http_server_failure_operations.py index ab6d5dc124f..85df71ca4b6 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Http/httpinfrastructure/aio/operations/_http_server_failure_operations.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Http/httpinfrastructure/aio/operations/_http_server_failure_operations.py @@ -23,7 +23,7 @@ from azure.core.utils import case_insensitive_dict from ... import models as _models -from ..._serialization import Deserializer, Serializer +from ..._utils.serialization import Deserializer, Serializer from ...operations._http_server_failure_operations import ( build_delete505_request, build_get501_request, diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Http/httpinfrastructure/aio/operations/_http_success_operations.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Http/httpinfrastructure/aio/operations/_http_success_operations.py index 5593c3d09a1..f4e307f9093 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Http/httpinfrastructure/aio/operations/_http_success_operations.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Http/httpinfrastructure/aio/operations/_http_success_operations.py @@ -24,7 +24,7 @@ from azure.core.utils import case_insensitive_dict from ... import models as _models -from ..._serialization import Deserializer, Serializer +from ..._utils.serialization import Deserializer, Serializer from ...operations._http_success_operations import ( build_delete200_request, build_delete202_request, diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Http/httpinfrastructure/aio/operations/_multiple_responses_operations.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Http/httpinfrastructure/aio/operations/_multiple_responses_operations.py index 46b3c0cfa70..009f1e30a04 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Http/httpinfrastructure/aio/operations/_multiple_responses_operations.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Http/httpinfrastructure/aio/operations/_multiple_responses_operations.py @@ -23,7 +23,7 @@ from azure.core.tracing.decorator_async import distributed_trace_async from ... import models as _models -from ..._serialization import Deserializer, Serializer +from ..._utils.serialization import Deserializer, Serializer from ...operations._multiple_responses_operations import ( build_get200_model201_model_default_error200_valid_request, build_get200_model201_model_default_error201_valid_request, diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Http/httpinfrastructure/models/_models_py3.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Http/httpinfrastructure/models/_models_py3.py index 76c457e360d..3c2a6b39aa6 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Http/httpinfrastructure/models/_models_py3.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Http/httpinfrastructure/models/_models_py3.py @@ -8,7 +8,7 @@ from typing import Any, Optional -from .. import _serialization +from .._utils import serialization as _serialization class MyException(_serialization.Model): diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Http/httpinfrastructure/operations/_http_client_failure_operations.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Http/httpinfrastructure/operations/_http_client_failure_operations.py index f4f34436c2b..46c41e18da5 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Http/httpinfrastructure/operations/_http_client_failure_operations.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Http/httpinfrastructure/operations/_http_client_failure_operations.py @@ -25,7 +25,7 @@ from .. import models as _models from .._configuration import AutoRestHttpInfrastructureTestServiceConfiguration -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Http/httpinfrastructure/operations/_http_failure_operations.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Http/httpinfrastructure/operations/_http_failure_operations.py index c21d734de89..a33e6936356 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Http/httpinfrastructure/operations/_http_failure_operations.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Http/httpinfrastructure/operations/_http_failure_operations.py @@ -24,7 +24,7 @@ from .. import models as _models from .._configuration import AutoRestHttpInfrastructureTestServiceConfiguration -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Http/httpinfrastructure/operations/_http_redirects_operations.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Http/httpinfrastructure/operations/_http_redirects_operations.py index fce24fbd359..4e8d079673a 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Http/httpinfrastructure/operations/_http_redirects_operations.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Http/httpinfrastructure/operations/_http_redirects_operations.py @@ -25,7 +25,7 @@ from .. import models as _models from .._configuration import AutoRestHttpInfrastructureTestServiceConfiguration -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Http/httpinfrastructure/operations/_http_retry_operations.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Http/httpinfrastructure/operations/_http_retry_operations.py index 7ae5c6dc9ca..97a4cbfaa73 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Http/httpinfrastructure/operations/_http_retry_operations.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Http/httpinfrastructure/operations/_http_retry_operations.py @@ -24,7 +24,7 @@ from .. import models as _models from .._configuration import AutoRestHttpInfrastructureTestServiceConfiguration -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Http/httpinfrastructure/operations/_http_server_failure_operations.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Http/httpinfrastructure/operations/_http_server_failure_operations.py index 61f30f1bc4f..33480a79e16 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Http/httpinfrastructure/operations/_http_server_failure_operations.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Http/httpinfrastructure/operations/_http_server_failure_operations.py @@ -24,7 +24,7 @@ from .. import models as _models from .._configuration import AutoRestHttpInfrastructureTestServiceConfiguration -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Http/httpinfrastructure/operations/_http_success_operations.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Http/httpinfrastructure/operations/_http_success_operations.py index 7e469c0563a..6facac47f55 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Http/httpinfrastructure/operations/_http_success_operations.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Http/httpinfrastructure/operations/_http_success_operations.py @@ -25,7 +25,7 @@ from .. import models as _models from .._configuration import AutoRestHttpInfrastructureTestServiceConfiguration -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Http/httpinfrastructure/operations/_multiple_responses_operations.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Http/httpinfrastructure/operations/_multiple_responses_operations.py index ad4938d0a74..d28bb5c8b06 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Http/httpinfrastructure/operations/_multiple_responses_operations.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Http/httpinfrastructure/operations/_multiple_responses_operations.py @@ -25,7 +25,7 @@ from .. import models as _models from .._configuration import AutoRestHttpInfrastructureTestServiceConfiguration -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/IncorrectErrorResponse/incorrecterrorresponse/_incorrect_returned_error_model.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/IncorrectErrorResponse/incorrecterrorresponse/_incorrect_returned_error_model.py index 2d9f549ee01..b0ac1c48787 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/IncorrectErrorResponse/incorrecterrorresponse/_incorrect_returned_error_model.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/IncorrectErrorResponse/incorrecterrorresponse/_incorrect_returned_error_model.py @@ -16,7 +16,7 @@ from . import models as _models from ._configuration import IncorrectReturnedErrorModelConfiguration -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer from .operations import IncorrectReturnedErrorModelOperationsMixin diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/IncorrectErrorResponse/incorrecterrorresponse/_utils/__init__.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/IncorrectErrorResponse/incorrecterrorresponse/_utils/__init__.py new file mode 100644 index 00000000000..0af9b28f660 --- /dev/null +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/IncorrectErrorResponse/incorrecterrorresponse/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyStringVersionTolerant/bodystringversiontolerant/_serialization.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/IncorrectErrorResponse/incorrecterrorresponse/_utils/serialization.py similarity index 100% rename from packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyStringVersionTolerant/bodystringversiontolerant/_serialization.py rename to packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/IncorrectErrorResponse/incorrecterrorresponse/_utils/serialization.py diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/IncorrectErrorResponse/incorrecterrorresponse/_utils/utils.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/IncorrectErrorResponse/incorrecterrorresponse/_utils/utils.py new file mode 100644 index 00000000000..39b612f39a9 --- /dev/null +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/IncorrectErrorResponse/incorrecterrorresponse/_utils/utils.py @@ -0,0 +1,25 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from abc import ABC +from typing import Generic, TYPE_CHECKING, TypeVar + +if TYPE_CHECKING: + from .serialization import Deserializer, Serializer + + +TClient = TypeVar("TClient") +TConfig = TypeVar("TConfig") + + +class ClientMixinABC(ABC, Generic[TClient, TConfig]): + """DO NOT use this class. It is for internal typing use only.""" + + _client: TClient + _config: TConfig + _serialize: "Serializer" + _deserialize: "Deserializer" diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/IncorrectErrorResponse/incorrecterrorresponse/_vendor.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/IncorrectErrorResponse/incorrecterrorresponse/_vendor.py deleted file mode 100644 index dc5c02fbead..00000000000 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/IncorrectErrorResponse/incorrecterrorresponse/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) AutoRest Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import IncorrectReturnedErrorModelConfiguration - -if TYPE_CHECKING: - from azure.core import PipelineClient - - from ._serialization import Deserializer, Serializer - - -class IncorrectReturnedErrorModelMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "PipelineClient" - _config: IncorrectReturnedErrorModelConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/IncorrectErrorResponse/incorrecterrorresponse/aio/_incorrect_returned_error_model.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/IncorrectErrorResponse/incorrecterrorresponse/aio/_incorrect_returned_error_model.py index 58c1bf3a26e..9a0ac4ef591 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/IncorrectErrorResponse/incorrecterrorresponse/aio/_incorrect_returned_error_model.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/IncorrectErrorResponse/incorrecterrorresponse/aio/_incorrect_returned_error_model.py @@ -15,7 +15,7 @@ from azure.core.rest import AsyncHttpResponse, HttpRequest from .. import models as _models -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import IncorrectReturnedErrorModelConfiguration from .operations import IncorrectReturnedErrorModelOperationsMixin diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/IncorrectErrorResponse/incorrecterrorresponse/aio/_vendor.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/IncorrectErrorResponse/incorrecterrorresponse/aio/_vendor.py deleted file mode 100644 index 5f03a29a82f..00000000000 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/IncorrectErrorResponse/incorrecterrorresponse/aio/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) AutoRest Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import IncorrectReturnedErrorModelConfiguration - -if TYPE_CHECKING: - from azure.core import AsyncPipelineClient - - from .._serialization import Deserializer, Serializer - - -class IncorrectReturnedErrorModelMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "AsyncPipelineClient" - _config: IncorrectReturnedErrorModelConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/IncorrectErrorResponse/incorrecterrorresponse/aio/operations/_incorrect_returned_error_model_operations.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/IncorrectErrorResponse/incorrecterrorresponse/aio/operations/_incorrect_returned_error_model_operations.py index 384afb503ca..9c6b3e62da7 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/IncorrectErrorResponse/incorrecterrorresponse/aio/operations/_incorrect_returned_error_model_operations.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/IncorrectErrorResponse/incorrecterrorresponse/aio/operations/_incorrect_returned_error_model_operations.py @@ -9,6 +9,7 @@ from collections.abc import MutableMapping from typing import Any, Callable, Dict, Optional, TypeVar +from azure.core import AsyncPipelineClient from azure.core.exceptions import ( ClientAuthenticationError, HttpResponseError, @@ -21,14 +22,17 @@ from azure.core.rest import AsyncHttpResponse, HttpRequest from azure.core.tracing.decorator_async import distributed_trace_async +from ..._utils.utils import ClientMixinABC from ...operations._incorrect_returned_error_model_operations import build_get_incorrect_error_from_server_request -from .._vendor import IncorrectReturnedErrorModelMixinABC +from .._configuration import IncorrectReturnedErrorModelConfiguration T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, AsyncHttpResponse], T, Dict[str, Any]], Any]] -class IncorrectReturnedErrorModelOperationsMixin(IncorrectReturnedErrorModelMixinABC): # pylint: disable=name-too-long +class IncorrectReturnedErrorModelOperationsMixin( # pylint: disable=name-too-long + ClientMixinABC[AsyncPipelineClient, IncorrectReturnedErrorModelConfiguration] +): @distributed_trace_async async def get_incorrect_error_from_server(self, **kwargs: Any) -> None: diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/IncorrectErrorResponse/incorrecterrorresponse/models/_models_py3.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/IncorrectErrorResponse/incorrecterrorresponse/models/_models_py3.py index 1d1b7707def..109cf147510 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/IncorrectErrorResponse/incorrecterrorresponse/models/_models_py3.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/IncorrectErrorResponse/incorrecterrorresponse/models/_models_py3.py @@ -8,7 +8,7 @@ from typing import Any, Optional -from .. import _serialization +from .._utils import serialization as _serialization class Error(_serialization.Model): diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/IncorrectErrorResponse/incorrecterrorresponse/operations/_incorrect_returned_error_model_operations.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/IncorrectErrorResponse/incorrecterrorresponse/operations/_incorrect_returned_error_model_operations.py index 1d113fe064b..4bf83e34cb4 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/IncorrectErrorResponse/incorrecterrorresponse/operations/_incorrect_returned_error_model_operations.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/IncorrectErrorResponse/incorrecterrorresponse/operations/_incorrect_returned_error_model_operations.py @@ -8,6 +8,7 @@ from collections.abc import MutableMapping from typing import Any, Callable, Dict, Optional, TypeVar +from azure.core import PipelineClient from azure.core.exceptions import ( ClientAuthenticationError, HttpResponseError, @@ -20,8 +21,9 @@ from azure.core.rest import HttpRequest, HttpResponse from azure.core.tracing.decorator import distributed_trace -from .._serialization import Serializer -from .._vendor import IncorrectReturnedErrorModelMixinABC +from .._configuration import IncorrectReturnedErrorModelConfiguration +from .._utils.serialization import Serializer +from .._utils.utils import ClientMixinABC T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] @@ -37,7 +39,9 @@ def build_get_incorrect_error_from_server_request(**kwargs: Any) -> HttpRequest: return HttpRequest(method="GET", url=_url, **kwargs) -class IncorrectReturnedErrorModelOperationsMixin(IncorrectReturnedErrorModelMixinABC): # pylint: disable=name-too-long +class IncorrectReturnedErrorModelOperationsMixin( # pylint: disable=name-too-long + ClientMixinABC[PipelineClient, IncorrectReturnedErrorModelConfiguration] +): @distributed_trace def get_incorrect_error_from_server(self, **kwargs: Any) -> None: # pylint: disable=inconsistent-return-statements diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/InternalOperation/internaloperation/_media_types_client.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/InternalOperation/internaloperation/_media_types_client.py index c48c0243ca5..e788c653022 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/InternalOperation/internaloperation/_media_types_client.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/InternalOperation/internaloperation/_media_types_client.py @@ -16,7 +16,7 @@ from . import models as _models from ._configuration import MediaTypesClientConfiguration -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer from .operations import MediaTypesClientOperationsMixin diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/InternalOperation/internaloperation/_utils/__init__.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/InternalOperation/internaloperation/_utils/__init__.py new file mode 100644 index 00000000000..0af9b28f660 --- /dev/null +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/InternalOperation/internaloperation/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyTimeVersionTolerant/bodytimeversiontolerant/_serialization.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/InternalOperation/internaloperation/_utils/serialization.py similarity index 100% rename from packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyTimeVersionTolerant/bodytimeversiontolerant/_serialization.py rename to packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/InternalOperation/internaloperation/_utils/serialization.py diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/InternalOperation/internaloperation/_utils/utils.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/InternalOperation/internaloperation/_utils/utils.py new file mode 100644 index 00000000000..39b612f39a9 --- /dev/null +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/InternalOperation/internaloperation/_utils/utils.py @@ -0,0 +1,25 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from abc import ABC +from typing import Generic, TYPE_CHECKING, TypeVar + +if TYPE_CHECKING: + from .serialization import Deserializer, Serializer + + +TClient = TypeVar("TClient") +TConfig = TypeVar("TConfig") + + +class ClientMixinABC(ABC, Generic[TClient, TConfig]): + """DO NOT use this class. It is for internal typing use only.""" + + _client: TClient + _config: TConfig + _serialize: "Serializer" + _deserialize: "Deserializer" diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/InternalOperation/internaloperation/_vendor.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/InternalOperation/internaloperation/_vendor.py index 89badf10b3f..5be4c2f4033 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/InternalOperation/internaloperation/_vendor.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/InternalOperation/internaloperation/_vendor.py @@ -13,7 +13,7 @@ if TYPE_CHECKING: from azure.core import PipelineClient - from ._serialization import Deserializer, Serializer + from ._utils.serialization import Deserializer, Serializer class MediaTypesClientMixinABC(ABC): diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/InternalOperation/internaloperation/_vendor/__init__.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/InternalOperation/internaloperation/_vendor/__init__.py new file mode 100644 index 00000000000..0af9b28f660 --- /dev/null +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/InternalOperation/internaloperation/_vendor/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ClientEnumVersionTolerant/clientenumversiontolerant/_serialization.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/InternalOperation/internaloperation/_vendor/serialization.py similarity index 100% rename from packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ClientEnumVersionTolerant/clientenumversiontolerant/_serialization.py rename to packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/InternalOperation/internaloperation/_vendor/serialization.py diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/InternalOperation/internaloperation/_vendor/utils.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/InternalOperation/internaloperation/_vendor/utils.py new file mode 100644 index 00000000000..39b612f39a9 --- /dev/null +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/InternalOperation/internaloperation/_vendor/utils.py @@ -0,0 +1,25 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from abc import ABC +from typing import Generic, TYPE_CHECKING, TypeVar + +if TYPE_CHECKING: + from .serialization import Deserializer, Serializer + + +TClient = TypeVar("TClient") +TConfig = TypeVar("TConfig") + + +class ClientMixinABC(ABC, Generic[TClient, TConfig]): + """DO NOT use this class. It is for internal typing use only.""" + + _client: TClient + _config: TConfig + _serialize: "Serializer" + _deserialize: "Deserializer" diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/InternalOperation/internaloperation/aio/_media_types_client.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/InternalOperation/internaloperation/aio/_media_types_client.py index 1c9231e20d6..ba7bbcea103 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/InternalOperation/internaloperation/aio/_media_types_client.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/InternalOperation/internaloperation/aio/_media_types_client.py @@ -15,7 +15,7 @@ from azure.core.rest import AsyncHttpResponse, HttpRequest from .. import models as _models -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import MediaTypesClientConfiguration from .operations import MediaTypesClientOperationsMixin diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/InternalOperation/internaloperation/aio/_vendor.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/InternalOperation/internaloperation/aio/_vendor.py index 09bfff1a7fa..fab931f8fdd 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/InternalOperation/internaloperation/aio/_vendor.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/InternalOperation/internaloperation/aio/_vendor.py @@ -13,7 +13,7 @@ if TYPE_CHECKING: from azure.core import AsyncPipelineClient - from .._serialization import Deserializer, Serializer + from .._utils.serialization import Deserializer, Serializer class MediaTypesClientMixinABC(ABC): diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/InternalOperation/internaloperation/aio/operations/_media_types_client_operations.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/InternalOperation/internaloperation/aio/operations/_media_types_client_operations.py index af24ba7a13a..9eb7b290d84 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/InternalOperation/internaloperation/aio/operations/_media_types_client_operations.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/InternalOperation/internaloperation/aio/operations/_media_types_client_operations.py @@ -10,6 +10,7 @@ from io import IOBase from typing import Any, Callable, Dict, IO, Optional, TypeVar, Union, overload +from azure.core import AsyncPipelineClient from azure.core.exceptions import ( ClientAuthenticationError, HttpResponseError, @@ -24,6 +25,7 @@ from azure.core.utils import case_insensitive_dict from ... import models as _models +from ..._utils.utils import ClientMixinABC from ...operations._media_types_client_operations import ( build_analyze_body_no_accept_header_request, build_analyze_body_request, @@ -33,13 +35,13 @@ build_content_type_with_encoding_request, build_put_text_and_json_body_request, ) -from .._vendor import MediaTypesClientMixinABC +from .._configuration import MediaTypesClientConfiguration T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, AsyncHttpResponse], T, Dict[str, Any]], Any]] -class MediaTypesClientOperationsMixin(MediaTypesClientMixinABC): +class MediaTypesClientOperationsMixin(ClientMixinABC[AsyncPipelineClient, MediaTypesClientConfiguration]): @overload async def analyze_body( diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/InternalOperation/internaloperation/models/_models_py3.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/InternalOperation/internaloperation/models/_models_py3.py index cb4813a0e1c..e2048ca3d3f 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/InternalOperation/internaloperation/models/_models_py3.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/InternalOperation/internaloperation/models/_models_py3.py @@ -8,7 +8,7 @@ from typing import Any, Optional -from .. import _serialization +from .._utils import serialization as _serialization class SourcePath(_serialization.Model): diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/InternalOperation/internaloperation/operations/_media_types_client_operations.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/InternalOperation/internaloperation/operations/_media_types_client_operations.py index 581ee5be70c..2b8777bb02d 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/InternalOperation/internaloperation/operations/_media_types_client_operations.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/InternalOperation/internaloperation/operations/_media_types_client_operations.py @@ -9,6 +9,7 @@ from io import IOBase from typing import Any, Callable, Dict, IO, Optional, TypeVar, Union, overload +from azure.core import PipelineClient from azure.core.exceptions import ( ClientAuthenticationError, HttpResponseError, @@ -23,8 +24,9 @@ from azure.core.utils import case_insensitive_dict from .. import models as _models -from .._serialization import Serializer -from .._vendor import MediaTypesClientMixinABC +from .._configuration import MediaTypesClientConfiguration +from .._utils.serialization import Serializer +from .._utils.utils import ClientMixinABC T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] @@ -153,7 +155,7 @@ def build_put_text_and_json_body_request(*, content: str, **kwargs: Any) -> Http return HttpRequest(method="POST", url=_url, headers=_headers, content=content, **kwargs) -class MediaTypesClientOperationsMixin(MediaTypesClientMixinABC): +class MediaTypesClientOperationsMixin(ClientMixinABC[PipelineClient, MediaTypesClientConfiguration]): @overload def analyze_body( diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/MediaTypes/mediatypes/_media_types_client.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/MediaTypes/mediatypes/_media_types_client.py index c48c0243ca5..e788c653022 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/MediaTypes/mediatypes/_media_types_client.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/MediaTypes/mediatypes/_media_types_client.py @@ -16,7 +16,7 @@ from . import models as _models from ._configuration import MediaTypesClientConfiguration -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer from .operations import MediaTypesClientOperationsMixin diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/MediaTypes/mediatypes/_utils/__init__.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/MediaTypes/mediatypes/_utils/__init__.py new file mode 100644 index 00000000000..0af9b28f660 --- /dev/null +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/MediaTypes/mediatypes/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ConstantsVersionTolerant/constantsversiontolerant/_serialization.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/MediaTypes/mediatypes/_utils/serialization.py similarity index 100% rename from packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ConstantsVersionTolerant/constantsversiontolerant/_serialization.py rename to packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/MediaTypes/mediatypes/_utils/serialization.py diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/MediaTypes/mediatypes/_utils/utils.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/MediaTypes/mediatypes/_utils/utils.py new file mode 100644 index 00000000000..39b612f39a9 --- /dev/null +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/MediaTypes/mediatypes/_utils/utils.py @@ -0,0 +1,25 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from abc import ABC +from typing import Generic, TYPE_CHECKING, TypeVar + +if TYPE_CHECKING: + from .serialization import Deserializer, Serializer + + +TClient = TypeVar("TClient") +TConfig = TypeVar("TConfig") + + +class ClientMixinABC(ABC, Generic[TClient, TConfig]): + """DO NOT use this class. It is for internal typing use only.""" + + _client: TClient + _config: TConfig + _serialize: "Serializer" + _deserialize: "Deserializer" diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/MediaTypes/mediatypes/_vendor.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/MediaTypes/mediatypes/_vendor.py deleted file mode 100644 index 89badf10b3f..00000000000 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/MediaTypes/mediatypes/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) AutoRest Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import MediaTypesClientConfiguration - -if TYPE_CHECKING: - from azure.core import PipelineClient - - from ._serialization import Deserializer, Serializer - - -class MediaTypesClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "PipelineClient" - _config: MediaTypesClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/MediaTypes/mediatypes/aio/_media_types_client.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/MediaTypes/mediatypes/aio/_media_types_client.py index 1c9231e20d6..ba7bbcea103 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/MediaTypes/mediatypes/aio/_media_types_client.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/MediaTypes/mediatypes/aio/_media_types_client.py @@ -15,7 +15,7 @@ from azure.core.rest import AsyncHttpResponse, HttpRequest from .. import models as _models -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import MediaTypesClientConfiguration from .operations import MediaTypesClientOperationsMixin diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/MediaTypes/mediatypes/aio/_vendor.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/MediaTypes/mediatypes/aio/_vendor.py deleted file mode 100644 index 09bfff1a7fa..00000000000 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/MediaTypes/mediatypes/aio/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) AutoRest Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import MediaTypesClientConfiguration - -if TYPE_CHECKING: - from azure.core import AsyncPipelineClient - - from .._serialization import Deserializer, Serializer - - -class MediaTypesClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "AsyncPipelineClient" - _config: MediaTypesClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/MediaTypes/mediatypes/aio/operations/_media_types_client_operations.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/MediaTypes/mediatypes/aio/operations/_media_types_client_operations.py index 0698fc4f8b5..be8d87f27a9 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/MediaTypes/mediatypes/aio/operations/_media_types_client_operations.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/MediaTypes/mediatypes/aio/operations/_media_types_client_operations.py @@ -10,6 +10,7 @@ from io import IOBase from typing import Any, Callable, Dict, IO, Optional, TypeVar, Union, overload +from azure.core import AsyncPipelineClient from azure.core.exceptions import ( ClientAuthenticationError, HttpResponseError, @@ -24,6 +25,7 @@ from azure.core.utils import case_insensitive_dict from ... import models as _models +from ..._utils.utils import ClientMixinABC from ...operations._media_types_client_operations import ( build_analyze_body_no_accept_header_request, build_analyze_body_request, @@ -33,13 +35,13 @@ build_content_type_with_encoding_request, build_put_text_and_json_body_request, ) -from .._vendor import MediaTypesClientMixinABC +from .._configuration import MediaTypesClientConfiguration T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, AsyncHttpResponse], T, Dict[str, Any]], Any]] -class MediaTypesClientOperationsMixin(MediaTypesClientMixinABC): +class MediaTypesClientOperationsMixin(ClientMixinABC[AsyncPipelineClient, MediaTypesClientConfiguration]): @overload async def analyze_body( diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/MediaTypes/mediatypes/models/_models_py3.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/MediaTypes/mediatypes/models/_models_py3.py index cb4813a0e1c..e2048ca3d3f 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/MediaTypes/mediatypes/models/_models_py3.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/MediaTypes/mediatypes/models/_models_py3.py @@ -8,7 +8,7 @@ from typing import Any, Optional -from .. import _serialization +from .._utils import serialization as _serialization class SourcePath(_serialization.Model): diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/MediaTypes/mediatypes/operations/_media_types_client_operations.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/MediaTypes/mediatypes/operations/_media_types_client_operations.py index f0e2411819d..b4ec855f3fb 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/MediaTypes/mediatypes/operations/_media_types_client_operations.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/MediaTypes/mediatypes/operations/_media_types_client_operations.py @@ -9,6 +9,7 @@ from io import IOBase from typing import Any, Callable, Dict, IO, Optional, TypeVar, Union, overload +from azure.core import PipelineClient from azure.core.exceptions import ( ClientAuthenticationError, HttpResponseError, @@ -23,8 +24,9 @@ from azure.core.utils import case_insensitive_dict from .. import models as _models -from .._serialization import Serializer -from .._vendor import MediaTypesClientMixinABC +from .._configuration import MediaTypesClientConfiguration +from .._utils.serialization import Serializer +from .._utils.utils import ClientMixinABC T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] @@ -153,7 +155,7 @@ def build_put_text_and_json_body_request(*, content: str, **kwargs: Any) -> Http return HttpRequest(method="POST", url=_url, headers=_headers, content=content, **kwargs) -class MediaTypesClientOperationsMixin(MediaTypesClientMixinABC): +class MediaTypesClientOperationsMixin(ClientMixinABC[PipelineClient, MediaTypesClientConfiguration]): @overload def analyze_body( diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/MergePatchJson/mergepatchjson/_merge_patch_json_client.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/MergePatchJson/mergepatchjson/_merge_patch_json_client.py index 06a621d5a37..96372eacfea 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/MergePatchJson/mergepatchjson/_merge_patch_json_client.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/MergePatchJson/mergepatchjson/_merge_patch_json_client.py @@ -15,7 +15,7 @@ from azure.core.rest import HttpRequest, HttpResponse from ._configuration import MergePatchJsonClientConfiguration -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer from .operations import MergePatchJsonClientOperationsMixin diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/MergePatchJson/mergepatchjson/_utils/__init__.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/MergePatchJson/mergepatchjson/_utils/__init__.py new file mode 100644 index 00000000000..0af9b28f660 --- /dev/null +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/MergePatchJson/mergepatchjson/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/CustomBaseUriMoreOptionsVersionTolerant/custombaseurlmoreoptionsversiontolerant/_serialization.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/MergePatchJson/mergepatchjson/_utils/serialization.py similarity index 100% rename from packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/CustomBaseUriMoreOptionsVersionTolerant/custombaseurlmoreoptionsversiontolerant/_serialization.py rename to packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/MergePatchJson/mergepatchjson/_utils/serialization.py diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/MergePatchJson/mergepatchjson/_utils/utils.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/MergePatchJson/mergepatchjson/_utils/utils.py new file mode 100644 index 00000000000..39b612f39a9 --- /dev/null +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/MergePatchJson/mergepatchjson/_utils/utils.py @@ -0,0 +1,25 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from abc import ABC +from typing import Generic, TYPE_CHECKING, TypeVar + +if TYPE_CHECKING: + from .serialization import Deserializer, Serializer + + +TClient = TypeVar("TClient") +TConfig = TypeVar("TConfig") + + +class ClientMixinABC(ABC, Generic[TClient, TConfig]): + """DO NOT use this class. It is for internal typing use only.""" + + _client: TClient + _config: TConfig + _serialize: "Serializer" + _deserialize: "Deserializer" diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/MergePatchJson/mergepatchjson/_vendor.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/MergePatchJson/mergepatchjson/_vendor.py deleted file mode 100644 index 8295b4aa6c6..00000000000 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/MergePatchJson/mergepatchjson/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) AutoRest Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import MergePatchJsonClientConfiguration - -if TYPE_CHECKING: - from azure.core import PipelineClient - - from ._serialization import Deserializer, Serializer - - -class MergePatchJsonClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "PipelineClient" - _config: MergePatchJsonClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/MergePatchJson/mergepatchjson/aio/_merge_patch_json_client.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/MergePatchJson/mergepatchjson/aio/_merge_patch_json_client.py index bb330133d10..ca83746899f 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/MergePatchJson/mergepatchjson/aio/_merge_patch_json_client.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/MergePatchJson/mergepatchjson/aio/_merge_patch_json_client.py @@ -14,7 +14,7 @@ from azure.core.pipeline import policies from azure.core.rest import AsyncHttpResponse, HttpRequest -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import MergePatchJsonClientConfiguration from .operations import MergePatchJsonClientOperationsMixin diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/MergePatchJson/mergepatchjson/aio/_vendor.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/MergePatchJson/mergepatchjson/aio/_vendor.py deleted file mode 100644 index ef83da259a4..00000000000 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/MergePatchJson/mergepatchjson/aio/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) AutoRest Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import MergePatchJsonClientConfiguration - -if TYPE_CHECKING: - from azure.core import AsyncPipelineClient - - from .._serialization import Deserializer, Serializer - - -class MergePatchJsonClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "AsyncPipelineClient" - _config: MergePatchJsonClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/MergePatchJson/mergepatchjson/aio/operations/_merge_patch_json_client_operations.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/MergePatchJson/mergepatchjson/aio/operations/_merge_patch_json_client_operations.py index a83983e4df1..56548464bfe 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/MergePatchJson/mergepatchjson/aio/operations/_merge_patch_json_client_operations.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/MergePatchJson/mergepatchjson/aio/operations/_merge_patch_json_client_operations.py @@ -9,6 +9,7 @@ from collections.abc import MutableMapping from typing import Any, Callable, Dict, Optional, TypeVar +from azure.core import AsyncPipelineClient from azure.core.exceptions import ( ClientAuthenticationError, HttpResponseError, @@ -22,15 +23,16 @@ from azure.core.tracing.decorator_async import distributed_trace_async from azure.core.utils import case_insensitive_dict +from ..._utils.utils import ClientMixinABC from ...operations._merge_patch_json_client_operations import build_patch_single_request -from .._vendor import MergePatchJsonClientMixinABC +from .._configuration import MergePatchJsonClientConfiguration JSON = MutableMapping[str, Any] T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, AsyncHttpResponse], T, Dict[str, Any]], Any]] -class MergePatchJsonClientOperationsMixin(MergePatchJsonClientMixinABC): +class MergePatchJsonClientOperationsMixin(ClientMixinABC[AsyncPipelineClient, MergePatchJsonClientConfiguration]): @distributed_trace_async async def patch_single(self, body: JSON, **kwargs: Any) -> None: diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/MergePatchJson/mergepatchjson/operations/_merge_patch_json_client_operations.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/MergePatchJson/mergepatchjson/operations/_merge_patch_json_client_operations.py index fbca0907cd0..8189bb4f669 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/MergePatchJson/mergepatchjson/operations/_merge_patch_json_client_operations.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/MergePatchJson/mergepatchjson/operations/_merge_patch_json_client_operations.py @@ -8,6 +8,7 @@ from collections.abc import MutableMapping from typing import Any, Callable, Dict, Optional, TypeVar +from azure.core import PipelineClient from azure.core.exceptions import ( ClientAuthenticationError, HttpResponseError, @@ -21,8 +22,9 @@ from azure.core.tracing.decorator import distributed_trace from azure.core.utils import case_insensitive_dict -from .._serialization import Serializer -from .._vendor import MergePatchJsonClientMixinABC +from .._configuration import MergePatchJsonClientConfiguration +from .._utils.serialization import Serializer +from .._utils.utils import ClientMixinABC JSON = MutableMapping[str, Any] T = TypeVar("T") @@ -49,7 +51,7 @@ def build_patch_single_request(*, json: JSON, **kwargs: Any) -> HttpRequest: return HttpRequest(method="PATCH", url=_url, headers=_headers, json=json, **kwargs) -class MergePatchJsonClientOperationsMixin(MergePatchJsonClientMixinABC): +class MergePatchJsonClientOperationsMixin(ClientMixinABC[PipelineClient, MergePatchJsonClientConfiguration]): @distributed_trace def patch_single(self, body: JSON, **kwargs: Any) -> None: # pylint: disable=inconsistent-return-statements diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ModelFlattening/modelflattening/_auto_rest_resource_flattening_test_service.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ModelFlattening/modelflattening/_auto_rest_resource_flattening_test_service.py index 17d9824bed4..c6e00d33017 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ModelFlattening/modelflattening/_auto_rest_resource_flattening_test_service.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ModelFlattening/modelflattening/_auto_rest_resource_flattening_test_service.py @@ -16,7 +16,7 @@ from . import models as _models from ._configuration import AutoRestResourceFlatteningTestServiceConfiguration -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer from .operations import AutoRestResourceFlatteningTestServiceOperationsMixin diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ModelFlattening/modelflattening/_utils/__init__.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ModelFlattening/modelflattening/_utils/__init__.py new file mode 100644 index 00000000000..0af9b28f660 --- /dev/null +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ModelFlattening/modelflattening/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/CustomBaseUriVersionTolerant/custombaseurlversiontolerant/_serialization.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ModelFlattening/modelflattening/_utils/serialization.py similarity index 100% rename from packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/CustomBaseUriVersionTolerant/custombaseurlversiontolerant/_serialization.py rename to packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ModelFlattening/modelflattening/_utils/serialization.py diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ModelFlattening/modelflattening/_utils/utils.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ModelFlattening/modelflattening/_utils/utils.py new file mode 100644 index 00000000000..39b612f39a9 --- /dev/null +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ModelFlattening/modelflattening/_utils/utils.py @@ -0,0 +1,25 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from abc import ABC +from typing import Generic, TYPE_CHECKING, TypeVar + +if TYPE_CHECKING: + from .serialization import Deserializer, Serializer + + +TClient = TypeVar("TClient") +TConfig = TypeVar("TConfig") + + +class ClientMixinABC(ABC, Generic[TClient, TConfig]): + """DO NOT use this class. It is for internal typing use only.""" + + _client: TClient + _config: TConfig + _serialize: "Serializer" + _deserialize: "Deserializer" diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ModelFlattening/modelflattening/_vendor.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ModelFlattening/modelflattening/_vendor.py deleted file mode 100644 index fb5eb8adf2b..00000000000 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ModelFlattening/modelflattening/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) AutoRest Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import AutoRestResourceFlatteningTestServiceConfiguration - -if TYPE_CHECKING: - from azure.core import PipelineClient - - from ._serialization import Deserializer, Serializer - - -class AutoRestResourceFlatteningTestServiceMixinABC(ABC): # pylint: disable=name-too-long - """DO NOT use this class. It is for internal typing use only.""" - - _client: "PipelineClient" - _config: AutoRestResourceFlatteningTestServiceConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ModelFlattening/modelflattening/aio/_auto_rest_resource_flattening_test_service.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ModelFlattening/modelflattening/aio/_auto_rest_resource_flattening_test_service.py index 1730604d458..d9977d2a94d 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ModelFlattening/modelflattening/aio/_auto_rest_resource_flattening_test_service.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ModelFlattening/modelflattening/aio/_auto_rest_resource_flattening_test_service.py @@ -15,7 +15,7 @@ from azure.core.rest import AsyncHttpResponse, HttpRequest from .. import models as _models -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import AutoRestResourceFlatteningTestServiceConfiguration from .operations import AutoRestResourceFlatteningTestServiceOperationsMixin diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ModelFlattening/modelflattening/aio/_vendor.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ModelFlattening/modelflattening/aio/_vendor.py deleted file mode 100644 index bb2abe11703..00000000000 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ModelFlattening/modelflattening/aio/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) AutoRest Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import AutoRestResourceFlatteningTestServiceConfiguration - -if TYPE_CHECKING: - from azure.core import AsyncPipelineClient - - from .._serialization import Deserializer, Serializer - - -class AutoRestResourceFlatteningTestServiceMixinABC(ABC): # pylint: disable=name-too-long - """DO NOT use this class. It is for internal typing use only.""" - - _client: "AsyncPipelineClient" - _config: AutoRestResourceFlatteningTestServiceConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ModelFlattening/modelflattening/aio/operations/_auto_rest_resource_flattening_test_service_operations.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ModelFlattening/modelflattening/aio/operations/_auto_rest_resource_flattening_test_service_operations.py index f6411ab3a8d..5b0e42478d8 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ModelFlattening/modelflattening/aio/operations/_auto_rest_resource_flattening_test_service_operations.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ModelFlattening/modelflattening/aio/operations/_auto_rest_resource_flattening_test_service_operations.py @@ -10,6 +10,7 @@ from io import IOBase from typing import Any, Callable, Dict, IO, List, Literal, Optional, TypeVar, Union, overload +from azure.core import AsyncPipelineClient from azure.core.exceptions import ( ClientAuthenticationError, HttpResponseError, @@ -24,6 +25,7 @@ from azure.core.utils import case_insensitive_dict from ... import models as _models +from ..._utils.utils import ClientMixinABC from ...operations._auto_rest_resource_flattening_test_service_operations import ( build_get_array_request, build_get_dictionary_request, @@ -37,14 +39,14 @@ build_put_simple_product_with_grouping_request, build_put_wrapped_array_request, ) -from .._vendor import AutoRestResourceFlatteningTestServiceMixinABC +from .._configuration import AutoRestResourceFlatteningTestServiceConfiguration T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, AsyncHttpResponse], T, Dict[str, Any]], Any]] class AutoRestResourceFlatteningTestServiceOperationsMixin( # pylint: disable=name-too-long - AutoRestResourceFlatteningTestServiceMixinABC + ClientMixinABC[AsyncPipelineClient, AutoRestResourceFlatteningTestServiceConfiguration] ): @overload diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ModelFlattening/modelflattening/models/_models_py3.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ModelFlattening/modelflattening/models/_models_py3.py index 7634af12e33..80966428f5b 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ModelFlattening/modelflattening/models/_models_py3.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ModelFlattening/modelflattening/models/_models_py3.py @@ -8,7 +8,7 @@ from typing import Any, Dict, List, Literal, Optional, TYPE_CHECKING -from .. import _serialization +from .._utils import serialization as _serialization if TYPE_CHECKING: from .. import models as _models diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ModelFlattening/modelflattening/operations/_auto_rest_resource_flattening_test_service_operations.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ModelFlattening/modelflattening/operations/_auto_rest_resource_flattening_test_service_operations.py index c979f5d30f7..ab6c97710bf 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ModelFlattening/modelflattening/operations/_auto_rest_resource_flattening_test_service_operations.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ModelFlattening/modelflattening/operations/_auto_rest_resource_flattening_test_service_operations.py @@ -10,6 +10,7 @@ from io import IOBase from typing import Any, Callable, Dict, IO, List, Literal, Optional, TypeVar, Union, overload +from azure.core import PipelineClient from azure.core.exceptions import ( ClientAuthenticationError, HttpResponseError, @@ -24,8 +25,9 @@ from azure.core.utils import case_insensitive_dict from .. import models as _models -from .._serialization import Serializer -from .._vendor import AutoRestResourceFlatteningTestServiceMixinABC +from .._configuration import AutoRestResourceFlatteningTestServiceConfiguration +from .._utils.serialization import Serializer +from .._utils.utils import ClientMixinABC T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] @@ -217,7 +219,7 @@ def build_put_simple_product_with_grouping_request( # pylint: disable=name-too- class AutoRestResourceFlatteningTestServiceOperationsMixin( # pylint: disable=name-too-long - AutoRestResourceFlatteningTestServiceMixinABC + ClientMixinABC[PipelineClient, AutoRestResourceFlatteningTestServiceConfiguration] ): @overload diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/MultipleInheritance/multipleinheritance/_multiple_inheritance_service_client.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/MultipleInheritance/multipleinheritance/_multiple_inheritance_service_client.py index 7f7da7567e9..30586b888c5 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/MultipleInheritance/multipleinheritance/_multiple_inheritance_service_client.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/MultipleInheritance/multipleinheritance/_multiple_inheritance_service_client.py @@ -16,7 +16,7 @@ from . import models as _models from ._configuration import MultipleInheritanceServiceClientConfiguration -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer from .operations import MultipleInheritanceServiceClientOperationsMixin diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/MultipleInheritance/multipleinheritance/_utils/__init__.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/MultipleInheritance/multipleinheritance/_utils/__init__.py new file mode 100644 index 00000000000..0af9b28f660 --- /dev/null +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/MultipleInheritance/multipleinheritance/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ErrorWithSecretsVersionTolerant/errorwithsecretsversiontolerant/_serialization.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/MultipleInheritance/multipleinheritance/_utils/serialization.py similarity index 100% rename from packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ErrorWithSecretsVersionTolerant/errorwithsecretsversiontolerant/_serialization.py rename to packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/MultipleInheritance/multipleinheritance/_utils/serialization.py diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/MultipleInheritance/multipleinheritance/_utils/utils.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/MultipleInheritance/multipleinheritance/_utils/utils.py new file mode 100644 index 00000000000..39b612f39a9 --- /dev/null +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/MultipleInheritance/multipleinheritance/_utils/utils.py @@ -0,0 +1,25 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from abc import ABC +from typing import Generic, TYPE_CHECKING, TypeVar + +if TYPE_CHECKING: + from .serialization import Deserializer, Serializer + + +TClient = TypeVar("TClient") +TConfig = TypeVar("TConfig") + + +class ClientMixinABC(ABC, Generic[TClient, TConfig]): + """DO NOT use this class. It is for internal typing use only.""" + + _client: TClient + _config: TConfig + _serialize: "Serializer" + _deserialize: "Deserializer" diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/MultipleInheritance/multipleinheritance/_vendor.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/MultipleInheritance/multipleinheritance/_vendor.py deleted file mode 100644 index 8a74180edd6..00000000000 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/MultipleInheritance/multipleinheritance/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) AutoRest Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import MultipleInheritanceServiceClientConfiguration - -if TYPE_CHECKING: - from azure.core import PipelineClient - - from ._serialization import Deserializer, Serializer - - -class MultipleInheritanceServiceClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "PipelineClient" - _config: MultipleInheritanceServiceClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/MultipleInheritance/multipleinheritance/aio/_multiple_inheritance_service_client.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/MultipleInheritance/multipleinheritance/aio/_multiple_inheritance_service_client.py index ee3602ee6d7..ff7b9962f32 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/MultipleInheritance/multipleinheritance/aio/_multiple_inheritance_service_client.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/MultipleInheritance/multipleinheritance/aio/_multiple_inheritance_service_client.py @@ -15,7 +15,7 @@ from azure.core.rest import AsyncHttpResponse, HttpRequest from .. import models as _models -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import MultipleInheritanceServiceClientConfiguration from .operations import MultipleInheritanceServiceClientOperationsMixin diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/MultipleInheritance/multipleinheritance/aio/_vendor.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/MultipleInheritance/multipleinheritance/aio/_vendor.py deleted file mode 100644 index 457fe8c5636..00000000000 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/MultipleInheritance/multipleinheritance/aio/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) AutoRest Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import MultipleInheritanceServiceClientConfiguration - -if TYPE_CHECKING: - from azure.core import AsyncPipelineClient - - from .._serialization import Deserializer, Serializer - - -class MultipleInheritanceServiceClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "AsyncPipelineClient" - _config: MultipleInheritanceServiceClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/MultipleInheritance/multipleinheritance/aio/operations/_multiple_inheritance_service_client_operations.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/MultipleInheritance/multipleinheritance/aio/operations/_multiple_inheritance_service_client_operations.py index 302d04cb6e8..837f7060fed 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/MultipleInheritance/multipleinheritance/aio/operations/_multiple_inheritance_service_client_operations.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/MultipleInheritance/multipleinheritance/aio/operations/_multiple_inheritance_service_client_operations.py @@ -10,6 +10,7 @@ from io import IOBase from typing import Any, Callable, Dict, IO, Optional, TypeVar, Union, overload +from azure.core import AsyncPipelineClient from azure.core.exceptions import ( ClientAuthenticationError, HttpResponseError, @@ -24,6 +25,7 @@ from azure.core.utils import case_insensitive_dict from ... import models as _models +from ..._utils.utils import ClientMixinABC from ...operations._multiple_inheritance_service_client_operations import ( build_get_cat_request, build_get_feline_request, @@ -36,14 +38,14 @@ build_put_kitten_request, build_put_pet_request, ) -from .._vendor import MultipleInheritanceServiceClientMixinABC +from .._configuration import MultipleInheritanceServiceClientConfiguration T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, AsyncHttpResponse], T, Dict[str, Any]], Any]] class MultipleInheritanceServiceClientOperationsMixin( # pylint: disable=name-too-long - MultipleInheritanceServiceClientMixinABC + ClientMixinABC[AsyncPipelineClient, MultipleInheritanceServiceClientConfiguration] ): @distributed_trace_async diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/MultipleInheritance/multipleinheritance/models/_models_py3.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/MultipleInheritance/multipleinheritance/models/_models_py3.py index 163d41e5353..8e3bd23258f 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/MultipleInheritance/multipleinheritance/models/_models_py3.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/MultipleInheritance/multipleinheritance/models/_models_py3.py @@ -8,7 +8,7 @@ from typing import Any, Optional -from .. import _serialization +from .._utils import serialization as _serialization class Feline(_serialization.Model): diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/MultipleInheritance/multipleinheritance/operations/_multiple_inheritance_service_client_operations.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/MultipleInheritance/multipleinheritance/operations/_multiple_inheritance_service_client_operations.py index 86f8a0672e8..94c5ff2b616 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/MultipleInheritance/multipleinheritance/operations/_multiple_inheritance_service_client_operations.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/MultipleInheritance/multipleinheritance/operations/_multiple_inheritance_service_client_operations.py @@ -9,6 +9,7 @@ from io import IOBase from typing import Any, Callable, Dict, IO, Optional, TypeVar, Union, overload +from azure.core import PipelineClient from azure.core.exceptions import ( ClientAuthenticationError, HttpResponseError, @@ -23,8 +24,9 @@ from azure.core.utils import case_insensitive_dict from .. import models as _models -from .._serialization import Serializer -from .._vendor import MultipleInheritanceServiceClientMixinABC +from .._configuration import MultipleInheritanceServiceClientConfiguration +from .._utils.serialization import Serializer +from .._utils.utils import ClientMixinABC T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] @@ -189,7 +191,7 @@ def build_put_kitten_request(**kwargs: Any) -> HttpRequest: class MultipleInheritanceServiceClientOperationsMixin( # pylint: disable=name-too-long - MultipleInheritanceServiceClientMixinABC + ClientMixinABC[PipelineClient, MultipleInheritanceServiceClientConfiguration] ): @distributed_trace diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/NoOperations/nooperations/_utils/__init__.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/NoOperations/nooperations/_utils/__init__.py new file mode 100644 index 00000000000..0af9b28f660 --- /dev/null +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/NoOperations/nooperations/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ExtensibleEnumsVersionTolerant/extensibleenumsswaggerversiontolerant/_serialization.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/NoOperations/nooperations/_utils/serialization.py similarity index 100% rename from packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ExtensibleEnumsVersionTolerant/extensibleenumsswaggerversiontolerant/_serialization.py rename to packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/NoOperations/nooperations/_utils/serialization.py diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/NoOperations/nooperations/models/_models_py3.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/NoOperations/nooperations/models/_models_py3.py index 1d1b7707def..109cf147510 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/NoOperations/nooperations/models/_models_py3.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/NoOperations/nooperations/models/_models_py3.py @@ -8,7 +8,7 @@ from typing import Any, Optional -from .. import _serialization +from .._utils import serialization as _serialization class Error(_serialization.Model): diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/NonStringEnums/nonstringenums/_non_string_enums_client.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/NonStringEnums/nonstringenums/_non_string_enums_client.py index d53265c3255..3b35778d3d0 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/NonStringEnums/nonstringenums/_non_string_enums_client.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/NonStringEnums/nonstringenums/_non_string_enums_client.py @@ -15,7 +15,7 @@ from azure.core.rest import HttpRequest, HttpResponse from ._configuration import NonStringEnumsClientConfiguration -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer from .operations import FloatOperations, IntOperations diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/NonStringEnums/nonstringenums/_utils/__init__.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/NonStringEnums/nonstringenums/_utils/__init__.py new file mode 100644 index 00000000000..0af9b28f660 --- /dev/null +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/NonStringEnums/nonstringenums/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/HeaderVersionTolerant/headerversiontolerant/_serialization.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/NonStringEnums/nonstringenums/_utils/serialization.py similarity index 100% rename from packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/HeaderVersionTolerant/headerversiontolerant/_serialization.py rename to packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/NonStringEnums/nonstringenums/_utils/serialization.py diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/NonStringEnums/nonstringenums/aio/_non_string_enums_client.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/NonStringEnums/nonstringenums/aio/_non_string_enums_client.py index fcde7fdc6b0..12153721831 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/NonStringEnums/nonstringenums/aio/_non_string_enums_client.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/NonStringEnums/nonstringenums/aio/_non_string_enums_client.py @@ -14,7 +14,7 @@ from azure.core.pipeline import policies from azure.core.rest import AsyncHttpResponse, HttpRequest -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import NonStringEnumsClientConfiguration from .operations import FloatOperations, IntOperations diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/NonStringEnums/nonstringenums/aio/operations/_float_operations.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/NonStringEnums/nonstringenums/aio/operations/_float_operations.py index 89564535760..2a43288f3e8 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/NonStringEnums/nonstringenums/aio/operations/_float_operations.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/NonStringEnums/nonstringenums/aio/operations/_float_operations.py @@ -23,7 +23,7 @@ from azure.core.utils import case_insensitive_dict from ... import models as _models -from ..._serialization import Deserializer, Serializer +from ..._utils.serialization import Deserializer, Serializer from ...operations._float_operations import build_get_request, build_put_request from .._configuration import NonStringEnumsClientConfiguration diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/NonStringEnums/nonstringenums/aio/operations/_int_operations_operations.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/NonStringEnums/nonstringenums/aio/operations/_int_operations_operations.py index 5402adf12c6..0d4ac168f77 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/NonStringEnums/nonstringenums/aio/operations/_int_operations_operations.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/NonStringEnums/nonstringenums/aio/operations/_int_operations_operations.py @@ -23,7 +23,7 @@ from azure.core.utils import case_insensitive_dict from ... import models as _models -from ..._serialization import Deserializer, Serializer +from ..._utils.serialization import Deserializer, Serializer from ...operations._int_operations_operations import build_get_request, build_put_request from .._configuration import NonStringEnumsClientConfiguration diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/NonStringEnums/nonstringenums/operations/_float_operations.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/NonStringEnums/nonstringenums/operations/_float_operations.py index 9e836568639..be278354f97 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/NonStringEnums/nonstringenums/operations/_float_operations.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/NonStringEnums/nonstringenums/operations/_float_operations.py @@ -24,7 +24,7 @@ from .. import models as _models from .._configuration import NonStringEnumsClientConfiguration -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/NonStringEnums/nonstringenums/operations/_int_operations_operations.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/NonStringEnums/nonstringenums/operations/_int_operations_operations.py index c1db8d20eea..dacf5c83d8f 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/NonStringEnums/nonstringenums/operations/_int_operations_operations.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/NonStringEnums/nonstringenums/operations/_int_operations_operations.py @@ -24,7 +24,7 @@ from .. import models as _models from .._configuration import NonStringEnumsClientConfiguration -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ObjectType/objecttype/_object_type_client.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ObjectType/objecttype/_object_type_client.py index b0285fb8017..61598d3cd87 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ObjectType/objecttype/_object_type_client.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ObjectType/objecttype/_object_type_client.py @@ -15,7 +15,7 @@ from azure.core.rest import HttpRequest, HttpResponse from ._configuration import ObjectTypeClientConfiguration -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer from .operations import ObjectTypeClientOperationsMixin diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ObjectType/objecttype/_utils/__init__.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ObjectType/objecttype/_utils/__init__.py new file mode 100644 index 00000000000..0af9b28f660 --- /dev/null +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ObjectType/objecttype/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/HttpVersionTolerant/httpinfrastructureversiontolerant/_serialization.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ObjectType/objecttype/_utils/serialization.py similarity index 100% rename from packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/HttpVersionTolerant/httpinfrastructureversiontolerant/_serialization.py rename to packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ObjectType/objecttype/_utils/serialization.py diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ObjectType/objecttype/_utils/utils.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ObjectType/objecttype/_utils/utils.py new file mode 100644 index 00000000000..39b612f39a9 --- /dev/null +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ObjectType/objecttype/_utils/utils.py @@ -0,0 +1,25 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from abc import ABC +from typing import Generic, TYPE_CHECKING, TypeVar + +if TYPE_CHECKING: + from .serialization import Deserializer, Serializer + + +TClient = TypeVar("TClient") +TConfig = TypeVar("TConfig") + + +class ClientMixinABC(ABC, Generic[TClient, TConfig]): + """DO NOT use this class. It is for internal typing use only.""" + + _client: TClient + _config: TConfig + _serialize: "Serializer" + _deserialize: "Deserializer" diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ObjectType/objecttype/_vendor.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ObjectType/objecttype/_vendor.py deleted file mode 100644 index e42ff8bdaa8..00000000000 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ObjectType/objecttype/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) AutoRest Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import ObjectTypeClientConfiguration - -if TYPE_CHECKING: - from azure.core import PipelineClient - - from ._serialization import Deserializer, Serializer - - -class ObjectTypeClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "PipelineClient" - _config: ObjectTypeClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ObjectType/objecttype/aio/_object_type_client.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ObjectType/objecttype/aio/_object_type_client.py index f2bc4a911de..c4ede2535d0 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ObjectType/objecttype/aio/_object_type_client.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ObjectType/objecttype/aio/_object_type_client.py @@ -14,7 +14,7 @@ from azure.core.pipeline import policies from azure.core.rest import AsyncHttpResponse, HttpRequest -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import ObjectTypeClientConfiguration from .operations import ObjectTypeClientOperationsMixin diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ObjectType/objecttype/aio/_vendor.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ObjectType/objecttype/aio/_vendor.py deleted file mode 100644 index 7773f545cb3..00000000000 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ObjectType/objecttype/aio/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) AutoRest Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import ObjectTypeClientConfiguration - -if TYPE_CHECKING: - from azure.core import AsyncPipelineClient - - from .._serialization import Deserializer, Serializer - - -class ObjectTypeClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "AsyncPipelineClient" - _config: ObjectTypeClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ObjectType/objecttype/aio/operations/_object_type_client_operations.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ObjectType/objecttype/aio/operations/_object_type_client_operations.py index dc5e62a4bab..1227759dd89 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ObjectType/objecttype/aio/operations/_object_type_client_operations.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ObjectType/objecttype/aio/operations/_object_type_client_operations.py @@ -9,6 +9,7 @@ from collections.abc import MutableMapping from typing import Any, Callable, Dict, Optional, TypeVar +from azure.core import AsyncPipelineClient from azure.core.exceptions import ( ClientAuthenticationError, HttpResponseError, @@ -22,15 +23,16 @@ from azure.core.tracing.decorator_async import distributed_trace_async from azure.core.utils import case_insensitive_dict +from ..._utils.utils import ClientMixinABC from ...operations._object_type_client_operations import build_get_request, build_put_request -from .._vendor import ObjectTypeClientMixinABC +from .._configuration import ObjectTypeClientConfiguration JSON = MutableMapping[str, Any] T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, AsyncHttpResponse], T, Dict[str, Any]], Any]] -class ObjectTypeClientOperationsMixin(ObjectTypeClientMixinABC): +class ObjectTypeClientOperationsMixin(ClientMixinABC[AsyncPipelineClient, ObjectTypeClientConfiguration]): @distributed_trace_async async def get(self, **kwargs: Any) -> JSON: diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ObjectType/objecttype/operations/_object_type_client_operations.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ObjectType/objecttype/operations/_object_type_client_operations.py index c0f8e1bbf91..d7ebbc0bc2c 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ObjectType/objecttype/operations/_object_type_client_operations.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ObjectType/objecttype/operations/_object_type_client_operations.py @@ -8,6 +8,7 @@ from collections.abc import MutableMapping from typing import Any, Callable, Dict, Optional, TypeVar +from azure.core import PipelineClient from azure.core.exceptions import ( ClientAuthenticationError, HttpResponseError, @@ -21,8 +22,9 @@ from azure.core.tracing.decorator import distributed_trace from azure.core.utils import case_insensitive_dict -from .._serialization import Serializer -from .._vendor import ObjectTypeClientMixinABC +from .._configuration import ObjectTypeClientConfiguration +from .._utils.serialization import Serializer +from .._utils.utils import ClientMixinABC JSON = MutableMapping[str, Any] T = TypeVar("T") @@ -63,7 +65,7 @@ def build_put_request(*, json: JSON, **kwargs: Any) -> HttpRequest: return HttpRequest(method="PUT", url=_url, headers=_headers, json=json, **kwargs) -class ObjectTypeClientOperationsMixin(ObjectTypeClientMixinABC): +class ObjectTypeClientOperationsMixin(ClientMixinABC[PipelineClient, ObjectTypeClientConfiguration]): @distributed_trace def get(self, **kwargs: Any) -> JSON: diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/PackageModeDataPlane/packagemode/_anything_client.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/PackageModeDataPlane/packagemode/_anything_client.py index a4653139be9..f1360522921 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/PackageModeDataPlane/packagemode/_anything_client.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/PackageModeDataPlane/packagemode/_anything_client.py @@ -15,7 +15,7 @@ from azure.core.rest import HttpRequest, HttpResponse from ._configuration import AnythingClientConfiguration -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer from .operations import AnythingClientOperationsMixin diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/PackageModeDataPlane/packagemode/_utils/__init__.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/PackageModeDataPlane/packagemode/_utils/__init__.py new file mode 100644 index 00000000000..0af9b28f660 --- /dev/null +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/PackageModeDataPlane/packagemode/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/IncorrectErrorResponseVersionTolerant/incorrecterrorresponseversiontolerant/_serialization.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/PackageModeDataPlane/packagemode/_utils/serialization.py similarity index 100% rename from packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/IncorrectErrorResponseVersionTolerant/incorrecterrorresponseversiontolerant/_serialization.py rename to packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/PackageModeDataPlane/packagemode/_utils/serialization.py diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/PackageModeDataPlane/packagemode/_utils/utils.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/PackageModeDataPlane/packagemode/_utils/utils.py new file mode 100644 index 00000000000..39b612f39a9 --- /dev/null +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/PackageModeDataPlane/packagemode/_utils/utils.py @@ -0,0 +1,25 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from abc import ABC +from typing import Generic, TYPE_CHECKING, TypeVar + +if TYPE_CHECKING: + from .serialization import Deserializer, Serializer + + +TClient = TypeVar("TClient") +TConfig = TypeVar("TConfig") + + +class ClientMixinABC(ABC, Generic[TClient, TConfig]): + """DO NOT use this class. It is for internal typing use only.""" + + _client: TClient + _config: TConfig + _serialize: "Serializer" + _deserialize: "Deserializer" diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/PackageModeDataPlane/packagemode/_vendor.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/PackageModeDataPlane/packagemode/_vendor.py index db0a5a9a33b..6736ce6ca19 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/PackageModeDataPlane/packagemode/_vendor.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/PackageModeDataPlane/packagemode/_vendor.py @@ -13,7 +13,7 @@ if TYPE_CHECKING: from azure.core import PipelineClient - from ._serialization import Deserializer, Serializer + from ._utils.serialization import Deserializer, Serializer class AnythingClientMixinABC(ABC): diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/PackageModeDataPlane/packagemode/_vendor/__init__.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/PackageModeDataPlane/packagemode/_vendor/__init__.py new file mode 100644 index 00000000000..0af9b28f660 --- /dev/null +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/PackageModeDataPlane/packagemode/_vendor/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/MediaTypesVersionTolerant/mediatypesversiontolerant/_serialization.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/PackageModeDataPlane/packagemode/_vendor/serialization.py similarity index 100% rename from packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/MediaTypesVersionTolerant/mediatypesversiontolerant/_serialization.py rename to packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/PackageModeDataPlane/packagemode/_vendor/serialization.py diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/PackageModeDataPlane/packagemode/_vendor/utils.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/PackageModeDataPlane/packagemode/_vendor/utils.py new file mode 100644 index 00000000000..39b612f39a9 --- /dev/null +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/PackageModeDataPlane/packagemode/_vendor/utils.py @@ -0,0 +1,25 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from abc import ABC +from typing import Generic, TYPE_CHECKING, TypeVar + +if TYPE_CHECKING: + from .serialization import Deserializer, Serializer + + +TClient = TypeVar("TClient") +TConfig = TypeVar("TConfig") + + +class ClientMixinABC(ABC, Generic[TClient, TConfig]): + """DO NOT use this class. It is for internal typing use only.""" + + _client: TClient + _config: TConfig + _serialize: "Serializer" + _deserialize: "Deserializer" diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/PackageModeDataPlane/packagemode/aio/_anything_client.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/PackageModeDataPlane/packagemode/aio/_anything_client.py index f2e6e6d527e..9784837beb0 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/PackageModeDataPlane/packagemode/aio/_anything_client.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/PackageModeDataPlane/packagemode/aio/_anything_client.py @@ -14,7 +14,7 @@ from azure.core.pipeline import policies from azure.core.rest import AsyncHttpResponse, HttpRequest -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import AnythingClientConfiguration from .operations import AnythingClientOperationsMixin diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/PackageModeDataPlane/packagemode/aio/_vendor.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/PackageModeDataPlane/packagemode/aio/_vendor.py index c99b54eef8d..f36cb669e99 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/PackageModeDataPlane/packagemode/aio/_vendor.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/PackageModeDataPlane/packagemode/aio/_vendor.py @@ -13,7 +13,7 @@ if TYPE_CHECKING: from azure.core import AsyncPipelineClient - from .._serialization import Deserializer, Serializer + from .._utils.serialization import Deserializer, Serializer class AnythingClientMixinABC(ABC): diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/PackageModeDataPlane/packagemode/aio/operations/_anything_client_operations.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/PackageModeDataPlane/packagemode/aio/operations/_anything_client_operations.py index 38235f6d05d..89c2a9c97c7 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/PackageModeDataPlane/packagemode/aio/operations/_anything_client_operations.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/PackageModeDataPlane/packagemode/aio/operations/_anything_client_operations.py @@ -9,6 +9,7 @@ from collections.abc import MutableMapping from typing import Any, Callable, Dict, Optional, TypeVar +from azure.core import AsyncPipelineClient from azure.core.exceptions import ( ClientAuthenticationError, HttpResponseError, @@ -22,6 +23,7 @@ from azure.core.tracing.decorator_async import distributed_trace_async from azure.core.utils import case_insensitive_dict +from ..._utils.utils import ClientMixinABC from ...operations._anything_client_operations import ( build_get_array_request, build_get_object_request, @@ -30,13 +32,13 @@ build_put_object_request, build_put_string_request, ) -from .._vendor import AnythingClientMixinABC +from .._configuration import AnythingClientConfiguration T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, AsyncHttpResponse], T, Dict[str, Any]], Any]] -class AnythingClientOperationsMixin(AnythingClientMixinABC): +class AnythingClientOperationsMixin(ClientMixinABC[AsyncPipelineClient, AnythingClientConfiguration]): @distributed_trace_async async def get_object(self, **kwargs: Any) -> Any: diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/PackageModeDataPlane/packagemode/operations/_anything_client_operations.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/PackageModeDataPlane/packagemode/operations/_anything_client_operations.py index ecfdc70b82b..eb6560b328a 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/PackageModeDataPlane/packagemode/operations/_anything_client_operations.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/PackageModeDataPlane/packagemode/operations/_anything_client_operations.py @@ -8,6 +8,7 @@ from collections.abc import MutableMapping from typing import Any, Callable, Dict, Optional, TypeVar +from azure.core import PipelineClient from azure.core.exceptions import ( ClientAuthenticationError, HttpResponseError, @@ -21,8 +22,9 @@ from azure.core.tracing.decorator import distributed_trace from azure.core.utils import case_insensitive_dict -from .._serialization import Serializer -from .._vendor import AnythingClientMixinABC +from .._configuration import AnythingClientConfiguration +from .._utils.serialization import Serializer +from .._utils.utils import ClientMixinABC T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] @@ -115,7 +117,7 @@ def build_put_array_request(*, json: Any, **kwargs: Any) -> HttpRequest: return HttpRequest(method="PUT", url=_url, headers=_headers, json=json, **kwargs) -class AnythingClientOperationsMixin(AnythingClientMixinABC): +class AnythingClientOperationsMixin(ClientMixinABC[PipelineClient, AnythingClientConfiguration]): @distributed_trace def get_object(self, **kwargs: Any) -> Any: diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ParameterFlattening/parameterflattening/_auto_rest_parameter_flattening.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ParameterFlattening/parameterflattening/_auto_rest_parameter_flattening.py index 5231cba152a..3e2c23c2ddd 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ParameterFlattening/parameterflattening/_auto_rest_parameter_flattening.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ParameterFlattening/parameterflattening/_auto_rest_parameter_flattening.py @@ -16,7 +16,7 @@ from . import models as _models from ._configuration import AutoRestParameterFlatteningConfiguration -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer from .operations import AvailabilitySetsOperations diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ParameterFlattening/parameterflattening/_utils/__init__.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ParameterFlattening/parameterflattening/_utils/__init__.py new file mode 100644 index 00000000000..0af9b28f660 --- /dev/null +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ParameterFlattening/parameterflattening/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/MergePatchJsonVersionTolerant/mergepatchjsonversiontolerant/_serialization.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ParameterFlattening/parameterflattening/_utils/serialization.py similarity index 100% rename from packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/MergePatchJsonVersionTolerant/mergepatchjsonversiontolerant/_serialization.py rename to packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ParameterFlattening/parameterflattening/_utils/serialization.py diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ParameterFlattening/parameterflattening/aio/_auto_rest_parameter_flattening.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ParameterFlattening/parameterflattening/aio/_auto_rest_parameter_flattening.py index 8b59c92e4de..eb0e2049f51 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ParameterFlattening/parameterflattening/aio/_auto_rest_parameter_flattening.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ParameterFlattening/parameterflattening/aio/_auto_rest_parameter_flattening.py @@ -15,7 +15,7 @@ from azure.core.rest import AsyncHttpResponse, HttpRequest from .. import models as _models -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import AutoRestParameterFlatteningConfiguration from .operations import AvailabilitySetsOperations diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ParameterFlattening/parameterflattening/aio/operations/_availability_sets_operations.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ParameterFlattening/parameterflattening/aio/operations/_availability_sets_operations.py index 50d6e581463..c0feec48526 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ParameterFlattening/parameterflattening/aio/operations/_availability_sets_operations.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ParameterFlattening/parameterflattening/aio/operations/_availability_sets_operations.py @@ -23,7 +23,7 @@ from azure.core.utils import case_insensitive_dict from ... import models as _models -from ..._serialization import Deserializer, Serializer +from ..._utils.serialization import Deserializer, Serializer from ...operations._availability_sets_operations import build_update_request from .._configuration import AutoRestParameterFlatteningConfiguration diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ParameterFlattening/parameterflattening/models/_models_py3.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ParameterFlattening/parameterflattening/models/_models_py3.py index a4b43946566..e612cb0fb25 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ParameterFlattening/parameterflattening/models/_models_py3.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ParameterFlattening/parameterflattening/models/_models_py3.py @@ -8,7 +8,7 @@ from typing import Any, Dict -from .. import _serialization +from .._utils import serialization as _serialization class AvailabilitySetUpdateParameters(_serialization.Model): diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ParameterFlattening/parameterflattening/operations/_availability_sets_operations.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ParameterFlattening/parameterflattening/operations/_availability_sets_operations.py index 1fea36ab25c..80992657976 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ParameterFlattening/parameterflattening/operations/_availability_sets_operations.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ParameterFlattening/parameterflattening/operations/_availability_sets_operations.py @@ -24,7 +24,7 @@ from .. import models as _models from .._configuration import AutoRestParameterFlatteningConfiguration -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ParameterizedEndpoint/parameterizedendpoint/_parmaterized_endpoint_client.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ParameterizedEndpoint/parameterizedendpoint/_parmaterized_endpoint_client.py index 88c32415461..d7103ebb238 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ParameterizedEndpoint/parameterizedendpoint/_parmaterized_endpoint_client.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ParameterizedEndpoint/parameterizedendpoint/_parmaterized_endpoint_client.py @@ -15,7 +15,7 @@ from azure.core.rest import HttpRequest, HttpResponse from ._configuration import ParmaterizedEndpointClientConfiguration -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer from .operations import ParmaterizedEndpointClientOperationsMixin diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ParameterizedEndpoint/parameterizedendpoint/_utils/__init__.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ParameterizedEndpoint/parameterizedendpoint/_utils/__init__.py new file mode 100644 index 00000000000..0af9b28f660 --- /dev/null +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ParameterizedEndpoint/parameterizedendpoint/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ModelFlatteningVersionTolerant/modelflatteningversiontolerant/_serialization.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ParameterizedEndpoint/parameterizedendpoint/_utils/serialization.py similarity index 100% rename from packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ModelFlatteningVersionTolerant/modelflatteningversiontolerant/_serialization.py rename to packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ParameterizedEndpoint/parameterizedendpoint/_utils/serialization.py diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ParameterizedEndpoint/parameterizedendpoint/_utils/utils.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ParameterizedEndpoint/parameterizedendpoint/_utils/utils.py new file mode 100644 index 00000000000..39b612f39a9 --- /dev/null +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ParameterizedEndpoint/parameterizedendpoint/_utils/utils.py @@ -0,0 +1,25 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from abc import ABC +from typing import Generic, TYPE_CHECKING, TypeVar + +if TYPE_CHECKING: + from .serialization import Deserializer, Serializer + + +TClient = TypeVar("TClient") +TConfig = TypeVar("TConfig") + + +class ClientMixinABC(ABC, Generic[TClient, TConfig]): + """DO NOT use this class. It is for internal typing use only.""" + + _client: TClient + _config: TConfig + _serialize: "Serializer" + _deserialize: "Deserializer" diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ParameterizedEndpoint/parameterizedendpoint/_vendor.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ParameterizedEndpoint/parameterizedendpoint/_vendor.py deleted file mode 100644 index a9e7ad280de..00000000000 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ParameterizedEndpoint/parameterizedendpoint/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) AutoRest Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import ParmaterizedEndpointClientConfiguration - -if TYPE_CHECKING: - from azure.core import PipelineClient - - from ._serialization import Deserializer, Serializer - - -class ParmaterizedEndpointClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "PipelineClient" - _config: ParmaterizedEndpointClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ParameterizedEndpoint/parameterizedendpoint/aio/_parmaterized_endpoint_client.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ParameterizedEndpoint/parameterizedendpoint/aio/_parmaterized_endpoint_client.py index e6394fdf22f..10504b6d224 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ParameterizedEndpoint/parameterizedendpoint/aio/_parmaterized_endpoint_client.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ParameterizedEndpoint/parameterizedendpoint/aio/_parmaterized_endpoint_client.py @@ -14,7 +14,7 @@ from azure.core.pipeline import policies from azure.core.rest import AsyncHttpResponse, HttpRequest -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import ParmaterizedEndpointClientConfiguration from .operations import ParmaterizedEndpointClientOperationsMixin diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ParameterizedEndpoint/parameterizedendpoint/aio/_vendor.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ParameterizedEndpoint/parameterizedendpoint/aio/_vendor.py deleted file mode 100644 index 32921e9fc7d..00000000000 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ParameterizedEndpoint/parameterizedendpoint/aio/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) AutoRest Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import ParmaterizedEndpointClientConfiguration - -if TYPE_CHECKING: - from azure.core import AsyncPipelineClient - - from .._serialization import Deserializer, Serializer - - -class ParmaterizedEndpointClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "AsyncPipelineClient" - _config: ParmaterizedEndpointClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ParameterizedEndpoint/parameterizedendpoint/aio/operations/_parmaterized_endpoint_client_operations.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ParameterizedEndpoint/parameterizedendpoint/aio/operations/_parmaterized_endpoint_client_operations.py index a4af1f2afbc..ba8c4ce124d 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ParameterizedEndpoint/parameterizedendpoint/aio/operations/_parmaterized_endpoint_client_operations.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ParameterizedEndpoint/parameterizedendpoint/aio/operations/_parmaterized_endpoint_client_operations.py @@ -9,6 +9,7 @@ from collections.abc import MutableMapping from typing import Any, Callable, Dict, Optional, TypeVar +from azure.core import AsyncPipelineClient from azure.core.exceptions import ( ClientAuthenticationError, HttpResponseError, @@ -21,14 +22,17 @@ from azure.core.rest import AsyncHttpResponse, HttpRequest from azure.core.tracing.decorator_async import distributed_trace_async +from ..._utils.utils import ClientMixinABC from ...operations._parmaterized_endpoint_client_operations import build_get_request -from .._vendor import ParmaterizedEndpointClientMixinABC +from .._configuration import ParmaterizedEndpointClientConfiguration T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, AsyncHttpResponse], T, Dict[str, Any]], Any]] -class ParmaterizedEndpointClientOperationsMixin(ParmaterizedEndpointClientMixinABC): # pylint: disable=name-too-long +class ParmaterizedEndpointClientOperationsMixin( # pylint: disable=name-too-long + ClientMixinABC[AsyncPipelineClient, ParmaterizedEndpointClientConfiguration] +): @distributed_trace_async async def get(self, **kwargs: Any) -> None: diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ParameterizedEndpoint/parameterizedendpoint/operations/_parmaterized_endpoint_client_operations.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ParameterizedEndpoint/parameterizedendpoint/operations/_parmaterized_endpoint_client_operations.py index 8680b446d2d..0c71808b14f 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ParameterizedEndpoint/parameterizedendpoint/operations/_parmaterized_endpoint_client_operations.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ParameterizedEndpoint/parameterizedendpoint/operations/_parmaterized_endpoint_client_operations.py @@ -8,6 +8,7 @@ from collections.abc import MutableMapping from typing import Any, Callable, Dict, Optional, TypeVar +from azure.core import PipelineClient from azure.core.exceptions import ( ClientAuthenticationError, HttpResponseError, @@ -20,8 +21,9 @@ from azure.core.rest import HttpRequest, HttpResponse from azure.core.tracing.decorator import distributed_trace -from .._serialization import Serializer -from .._vendor import ParmaterizedEndpointClientMixinABC +from .._configuration import ParmaterizedEndpointClientConfiguration +from .._utils.serialization import Serializer +from .._utils.utils import ClientMixinABC T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] @@ -37,7 +39,9 @@ def build_get_request(**kwargs: Any) -> HttpRequest: return HttpRequest(method="GET", url=_url, **kwargs) -class ParmaterizedEndpointClientOperationsMixin(ParmaterizedEndpointClientMixinABC): # pylint: disable=name-too-long +class ParmaterizedEndpointClientOperationsMixin( # pylint: disable=name-too-long + ClientMixinABC[PipelineClient, ParmaterizedEndpointClientConfiguration] +): @distributed_trace def get(self, **kwargs: Any) -> None: # pylint: disable=inconsistent-return-statements diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Report/report/_auto_rest_report_service.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Report/report/_auto_rest_report_service.py index 95cfbdd6176..41899dc3246 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Report/report/_auto_rest_report_service.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Report/report/_auto_rest_report_service.py @@ -16,7 +16,7 @@ from . import models as _models from ._configuration import AutoRestReportServiceConfiguration -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer from .operations import AutoRestReportServiceOperationsMixin diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Report/report/_utils/__init__.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Report/report/_utils/__init__.py new file mode 100644 index 00000000000..0af9b28f660 --- /dev/null +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Report/report/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/MultipleInheritanceVersionTolerant/multipleinheritanceversiontolerant/_serialization.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Report/report/_utils/serialization.py similarity index 100% rename from packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/MultipleInheritanceVersionTolerant/multipleinheritanceversiontolerant/_serialization.py rename to packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Report/report/_utils/serialization.py diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Report/report/_utils/utils.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Report/report/_utils/utils.py new file mode 100644 index 00000000000..39b612f39a9 --- /dev/null +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Report/report/_utils/utils.py @@ -0,0 +1,25 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from abc import ABC +from typing import Generic, TYPE_CHECKING, TypeVar + +if TYPE_CHECKING: + from .serialization import Deserializer, Serializer + + +TClient = TypeVar("TClient") +TConfig = TypeVar("TConfig") + + +class ClientMixinABC(ABC, Generic[TClient, TConfig]): + """DO NOT use this class. It is for internal typing use only.""" + + _client: TClient + _config: TConfig + _serialize: "Serializer" + _deserialize: "Deserializer" diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Report/report/_vendor.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Report/report/_vendor.py deleted file mode 100644 index 823d06e3b42..00000000000 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Report/report/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) AutoRest Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import AutoRestReportServiceConfiguration - -if TYPE_CHECKING: - from azure.core import PipelineClient - - from ._serialization import Deserializer, Serializer - - -class AutoRestReportServiceMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "PipelineClient" - _config: AutoRestReportServiceConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Report/report/aio/_auto_rest_report_service.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Report/report/aio/_auto_rest_report_service.py index d9b09147805..14af2152cc7 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Report/report/aio/_auto_rest_report_service.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Report/report/aio/_auto_rest_report_service.py @@ -15,7 +15,7 @@ from azure.core.rest import AsyncHttpResponse, HttpRequest from .. import models as _models -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import AutoRestReportServiceConfiguration from .operations import AutoRestReportServiceOperationsMixin diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Report/report/aio/_vendor.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Report/report/aio/_vendor.py deleted file mode 100644 index 4777573d29a..00000000000 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Report/report/aio/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) AutoRest Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import AutoRestReportServiceConfiguration - -if TYPE_CHECKING: - from azure.core import AsyncPipelineClient - - from .._serialization import Deserializer, Serializer - - -class AutoRestReportServiceMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "AsyncPipelineClient" - _config: AutoRestReportServiceConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Report/report/aio/operations/_auto_rest_report_service_operations.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Report/report/aio/operations/_auto_rest_report_service_operations.py index 8e54dd5df18..c2eeca770f1 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Report/report/aio/operations/_auto_rest_report_service_operations.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Report/report/aio/operations/_auto_rest_report_service_operations.py @@ -9,6 +9,7 @@ from collections.abc import MutableMapping from typing import Any, Callable, Dict, Optional, TypeVar +from azure.core import AsyncPipelineClient from azure.core.exceptions import ( ClientAuthenticationError, HttpResponseError, @@ -22,17 +23,18 @@ from azure.core.tracing.decorator_async import distributed_trace_async from ... import models as _models +from ..._utils.utils import ClientMixinABC from ...operations._auto_rest_report_service_operations import ( build_get_optional_report_request, build_get_report_request, ) -from .._vendor import AutoRestReportServiceMixinABC +from .._configuration import AutoRestReportServiceConfiguration T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, AsyncHttpResponse], T, Dict[str, Any]], Any]] -class AutoRestReportServiceOperationsMixin(AutoRestReportServiceMixinABC): +class AutoRestReportServiceOperationsMixin(ClientMixinABC[AsyncPipelineClient, AutoRestReportServiceConfiguration]): @distributed_trace_async async def get_report(self, qualifier: Optional[str] = None, **kwargs: Any) -> Dict[str, int]: diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Report/report/models/_models_py3.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Report/report/models/_models_py3.py index 1d1b7707def..109cf147510 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Report/report/models/_models_py3.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Report/report/models/_models_py3.py @@ -8,7 +8,7 @@ from typing import Any, Optional -from .. import _serialization +from .._utils import serialization as _serialization class Error(_serialization.Model): diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Report/report/operations/_auto_rest_report_service_operations.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Report/report/operations/_auto_rest_report_service_operations.py index 2943eaf5da1..7e14a392d05 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Report/report/operations/_auto_rest_report_service_operations.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Report/report/operations/_auto_rest_report_service_operations.py @@ -8,6 +8,7 @@ from collections.abc import MutableMapping from typing import Any, Callable, Dict, Optional, TypeVar +from azure.core import PipelineClient from azure.core.exceptions import ( ClientAuthenticationError, HttpResponseError, @@ -22,8 +23,9 @@ from azure.core.utils import case_insensitive_dict from .. import models as _models -from .._serialization import Serializer -from .._vendor import AutoRestReportServiceMixinABC +from .._configuration import AutoRestReportServiceConfiguration +from .._utils.serialization import Serializer +from .._utils.utils import ClientMixinABC T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] @@ -70,7 +72,7 @@ def build_get_optional_report_request(*, qualifier: Optional[str] = None, **kwar return HttpRequest(method="GET", url=_url, params=_params, headers=_headers, **kwargs) -class AutoRestReportServiceOperationsMixin(AutoRestReportServiceMixinABC): +class AutoRestReportServiceOperationsMixin(ClientMixinABC[PipelineClient, AutoRestReportServiceConfiguration]): @distributed_trace def get_report(self, qualifier: Optional[str] = None, **kwargs: Any) -> Dict[str, int]: diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ReservedWords/reservedwords/_reserved_words_client.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ReservedWords/reservedwords/_reserved_words_client.py index 865068d1b7f..3498661d56d 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ReservedWords/reservedwords/_reserved_words_client.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ReservedWords/reservedwords/_reserved_words_client.py @@ -16,7 +16,7 @@ from . import models as _models from ._configuration import ReservedWordsClientConfiguration -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer from .operations import ImportOperations, ReservedWordsClientOperationsMixin diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ReservedWords/reservedwords/_utils/__init__.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ReservedWords/reservedwords/_utils/__init__.py new file mode 100644 index 00000000000..0af9b28f660 --- /dev/null +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ReservedWords/reservedwords/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/NoNamespaceFlagVersionTolerant/anything_client/_serialization.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ReservedWords/reservedwords/_utils/serialization.py similarity index 100% rename from packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/NoNamespaceFlagVersionTolerant/anything_client/_serialization.py rename to packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ReservedWords/reservedwords/_utils/serialization.py diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ReservedWords/reservedwords/_utils/utils.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ReservedWords/reservedwords/_utils/utils.py new file mode 100644 index 00000000000..39b612f39a9 --- /dev/null +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ReservedWords/reservedwords/_utils/utils.py @@ -0,0 +1,25 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from abc import ABC +from typing import Generic, TYPE_CHECKING, TypeVar + +if TYPE_CHECKING: + from .serialization import Deserializer, Serializer + + +TClient = TypeVar("TClient") +TConfig = TypeVar("TConfig") + + +class ClientMixinABC(ABC, Generic[TClient, TConfig]): + """DO NOT use this class. It is for internal typing use only.""" + + _client: TClient + _config: TConfig + _serialize: "Serializer" + _deserialize: "Deserializer" diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ReservedWords/reservedwords/_vendor.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ReservedWords/reservedwords/_vendor.py deleted file mode 100644 index 7cd90c432bd..00000000000 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ReservedWords/reservedwords/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) AutoRest Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import ReservedWordsClientConfiguration - -if TYPE_CHECKING: - from azure.core import PipelineClient - - from ._serialization import Deserializer, Serializer - - -class ReservedWordsClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "PipelineClient" - _config: ReservedWordsClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ReservedWords/reservedwords/aio/_reserved_words_client.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ReservedWords/reservedwords/aio/_reserved_words_client.py index 66442549bed..5010b6d6707 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ReservedWords/reservedwords/aio/_reserved_words_client.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ReservedWords/reservedwords/aio/_reserved_words_client.py @@ -15,7 +15,7 @@ from azure.core.rest import AsyncHttpResponse, HttpRequest from .. import models as _models -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import ReservedWordsClientConfiguration from .operations import ImportOperations, ReservedWordsClientOperationsMixin diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ReservedWords/reservedwords/aio/_vendor.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ReservedWords/reservedwords/aio/_vendor.py deleted file mode 100644 index 8640c639b98..00000000000 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ReservedWords/reservedwords/aio/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) AutoRest Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import ReservedWordsClientConfiguration - -if TYPE_CHECKING: - from azure.core import AsyncPipelineClient - - from .._serialization import Deserializer, Serializer - - -class ReservedWordsClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "AsyncPipelineClient" - _config: ReservedWordsClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ReservedWords/reservedwords/aio/operations/_import_operations_operations.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ReservedWords/reservedwords/aio/operations/_import_operations_operations.py index f5d94437a20..a63b25f8616 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ReservedWords/reservedwords/aio/operations/_import_operations_operations.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ReservedWords/reservedwords/aio/operations/_import_operations_operations.py @@ -22,7 +22,7 @@ from azure.core.tracing.decorator_async import distributed_trace_async from ... import models as _models -from ..._serialization import Deserializer, Serializer +from ..._utils.serialization import Deserializer, Serializer from ...operations._import_operations_operations import build_operation_one_request from .._configuration import ReservedWordsClientConfiguration diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ReservedWords/reservedwords/aio/operations/_reserved_words_client_operations.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ReservedWords/reservedwords/aio/operations/_reserved_words_client_operations.py index 6727d4352bb..9530b373328 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ReservedWords/reservedwords/aio/operations/_reserved_words_client_operations.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ReservedWords/reservedwords/aio/operations/_reserved_words_client_operations.py @@ -9,6 +9,7 @@ from collections.abc import MutableMapping from typing import Any, Callable, Dict, IO, List, Optional, TypeVar, Union +from azure.core import AsyncPipelineClient from azure.core.exceptions import ( ClientAuthenticationError, HttpResponseError, @@ -23,6 +24,7 @@ from azure.core.utils import case_insensitive_dict from ... import models as _models +from ..._utils.utils import ClientMixinABC from ...operations._reserved_words_client_operations import ( build_operation_with_content_param_request, build_operation_with_data_param_request, @@ -31,14 +33,14 @@ build_operation_with_url_request, build_reserved_enum_request, ) -from .._vendor import ReservedWordsClientMixinABC +from .._configuration import ReservedWordsClientConfiguration JSON = MutableMapping[str, Any] T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, AsyncHttpResponse], T, Dict[str, Any]], Any]] -class ReservedWordsClientOperationsMixin(ReservedWordsClientMixinABC): +class ReservedWordsClientOperationsMixin(ClientMixinABC[AsyncPipelineClient, ReservedWordsClientConfiguration]): @distributed_trace_async async def operation_with_content_param(self, content: IO[bytes], **kwargs: Any) -> JSON: diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ReservedWords/reservedwords/models/_models_py3.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ReservedWords/reservedwords/models/_models_py3.py index 8c2865473be..d917e1fac4e 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ReservedWords/reservedwords/models/_models_py3.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ReservedWords/reservedwords/models/_models_py3.py @@ -8,7 +8,7 @@ from typing import Any, IO -from .. import _serialization +from .._utils import serialization as _serialization class PathsJaneoqReservedwordsOperationDataPutRequestbodyContentApplicationXWwwFormUrlencodedSchema( diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ReservedWords/reservedwords/operations/_import_operations_operations.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ReservedWords/reservedwords/operations/_import_operations_operations.py index 8e40171f402..395087f1a8f 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ReservedWords/reservedwords/operations/_import_operations_operations.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ReservedWords/reservedwords/operations/_import_operations_operations.py @@ -24,7 +24,7 @@ from .. import models as _models from .._configuration import ReservedWordsClientConfiguration -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer JSON = MutableMapping[str, Any] T = TypeVar("T") diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ReservedWords/reservedwords/operations/_reserved_words_client_operations.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ReservedWords/reservedwords/operations/_reserved_words_client_operations.py index b379ffa7a18..b95ef5e68b8 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ReservedWords/reservedwords/operations/_reserved_words_client_operations.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/ReservedWords/reservedwords/operations/_reserved_words_client_operations.py @@ -8,6 +8,7 @@ from collections.abc import MutableMapping from typing import Any, Callable, Dict, IO, List, Optional, TypeVar, Union +from azure.core import PipelineClient from azure.core.exceptions import ( ClientAuthenticationError, HttpResponseError, @@ -22,8 +23,9 @@ from azure.core.utils import case_insensitive_dict from .. import models as _models -from .._serialization import Serializer -from .._vendor import ReservedWordsClientMixinABC +from .._configuration import ReservedWordsClientConfiguration +from .._utils.serialization import Serializer +from .._utils.utils import ClientMixinABC JSON = MutableMapping[str, Any] T = TypeVar("T") @@ -143,7 +145,7 @@ def build_reserved_enum_request(*, enum_parameter: Union[str, _models.MyEnum], * return HttpRequest(method="GET", url=_url, headers=_headers, **kwargs) -class ReservedWordsClientOperationsMixin(ReservedWordsClientMixinABC): +class ReservedWordsClientOperationsMixin(ClientMixinABC[PipelineClient, ReservedWordsClientConfiguration]): @distributed_trace def operation_with_content_param(self, content: IO[bytes], **kwargs: Any) -> JSON: diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/SecurityAadSwagger/securityaadswagger/_autorest_security_aad.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/SecurityAadSwagger/securityaadswagger/_autorest_security_aad.py index 3404aa612af..46198eac398 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/SecurityAadSwagger/securityaadswagger/_autorest_security_aad.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/SecurityAadSwagger/securityaadswagger/_autorest_security_aad.py @@ -15,7 +15,7 @@ from azure.core.rest import HttpRequest, HttpResponse from ._configuration import AutorestSecurityAadConfiguration -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer from .operations import AutorestSecurityAadOperationsMixin if TYPE_CHECKING: diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/SecurityAadSwagger/securityaadswagger/_utils/__init__.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/SecurityAadSwagger/securityaadswagger/_utils/__init__.py new file mode 100644 index 00000000000..0af9b28f660 --- /dev/null +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/SecurityAadSwagger/securityaadswagger/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/NoOperationsVersionTolerant/nooperationsversiontolerant/_serialization.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/SecurityAadSwagger/securityaadswagger/_utils/serialization.py similarity index 100% rename from packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/NoOperationsVersionTolerant/nooperationsversiontolerant/_serialization.py rename to packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/SecurityAadSwagger/securityaadswagger/_utils/serialization.py diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/SecurityAadSwagger/securityaadswagger/_utils/utils.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/SecurityAadSwagger/securityaadswagger/_utils/utils.py new file mode 100644 index 00000000000..39b612f39a9 --- /dev/null +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/SecurityAadSwagger/securityaadswagger/_utils/utils.py @@ -0,0 +1,25 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from abc import ABC +from typing import Generic, TYPE_CHECKING, TypeVar + +if TYPE_CHECKING: + from .serialization import Deserializer, Serializer + + +TClient = TypeVar("TClient") +TConfig = TypeVar("TConfig") + + +class ClientMixinABC(ABC, Generic[TClient, TConfig]): + """DO NOT use this class. It is for internal typing use only.""" + + _client: TClient + _config: TConfig + _serialize: "Serializer" + _deserialize: "Deserializer" diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/SecurityAadSwagger/securityaadswagger/_vendor.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/SecurityAadSwagger/securityaadswagger/_vendor.py deleted file mode 100644 index 4bac3abea25..00000000000 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/SecurityAadSwagger/securityaadswagger/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) AutoRest Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import AutorestSecurityAadConfiguration - -if TYPE_CHECKING: - from azure.core import PipelineClient - - from ._serialization import Deserializer, Serializer - - -class AutorestSecurityAadMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "PipelineClient" - _config: AutorestSecurityAadConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/SecurityAadSwagger/securityaadswagger/aio/_autorest_security_aad.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/SecurityAadSwagger/securityaadswagger/aio/_autorest_security_aad.py index fe4150bd072..3e39cb46ebb 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/SecurityAadSwagger/securityaadswagger/aio/_autorest_security_aad.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/SecurityAadSwagger/securityaadswagger/aio/_autorest_security_aad.py @@ -14,7 +14,7 @@ from azure.core.pipeline import policies from azure.core.rest import AsyncHttpResponse, HttpRequest -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import AutorestSecurityAadConfiguration from .operations import AutorestSecurityAadOperationsMixin diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/SecurityAadSwagger/securityaadswagger/aio/_vendor.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/SecurityAadSwagger/securityaadswagger/aio/_vendor.py deleted file mode 100644 index 3b07efefdc0..00000000000 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/SecurityAadSwagger/securityaadswagger/aio/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) AutoRest Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import AutorestSecurityAadConfiguration - -if TYPE_CHECKING: - from azure.core import AsyncPipelineClient - - from .._serialization import Deserializer, Serializer - - -class AutorestSecurityAadMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "AsyncPipelineClient" - _config: AutorestSecurityAadConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/SecurityAadSwagger/securityaadswagger/aio/operations/_autorest_security_aad_operations.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/SecurityAadSwagger/securityaadswagger/aio/operations/_autorest_security_aad_operations.py index 7ccf0701845..6078a7bb085 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/SecurityAadSwagger/securityaadswagger/aio/operations/_autorest_security_aad_operations.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/SecurityAadSwagger/securityaadswagger/aio/operations/_autorest_security_aad_operations.py @@ -9,6 +9,7 @@ from collections.abc import MutableMapping from typing import Any, Callable, Dict, Optional, TypeVar +from azure.core import AsyncPipelineClient from azure.core.exceptions import ( ClientAuthenticationError, HttpResponseError, @@ -21,14 +22,15 @@ from azure.core.rest import AsyncHttpResponse, HttpRequest from azure.core.tracing.decorator_async import distributed_trace_async +from ..._utils.utils import ClientMixinABC from ...operations._autorest_security_aad_operations import build_head_request -from .._vendor import AutorestSecurityAadMixinABC +from .._configuration import AutorestSecurityAadConfiguration T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, AsyncHttpResponse], T, Dict[str, Any]], Any]] -class AutorestSecurityAadOperationsMixin(AutorestSecurityAadMixinABC): +class AutorestSecurityAadOperationsMixin(ClientMixinABC[AsyncPipelineClient, AutorestSecurityAadConfiguration]): @distributed_trace_async async def head(self, **kwargs: Any) -> None: diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/SecurityAadSwagger/securityaadswagger/operations/_autorest_security_aad_operations.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/SecurityAadSwagger/securityaadswagger/operations/_autorest_security_aad_operations.py index d9e8e4c1c47..fd7ae9aae6e 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/SecurityAadSwagger/securityaadswagger/operations/_autorest_security_aad_operations.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/SecurityAadSwagger/securityaadswagger/operations/_autorest_security_aad_operations.py @@ -8,6 +8,7 @@ from collections.abc import MutableMapping from typing import Any, Callable, Dict, Optional, TypeVar +from azure.core import PipelineClient from azure.core.exceptions import ( ClientAuthenticationError, HttpResponseError, @@ -20,8 +21,9 @@ from azure.core.rest import HttpRequest, HttpResponse from azure.core.tracing.decorator import distributed_trace -from .._serialization import Serializer -from .._vendor import AutorestSecurityAadMixinABC +from .._configuration import AutorestSecurityAadConfiguration +from .._utils.serialization import Serializer +from .._utils.utils import ClientMixinABC T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] @@ -37,7 +39,7 @@ def build_head_request(**kwargs: Any) -> HttpRequest: return HttpRequest(method="HEAD", url=_url, **kwargs) -class AutorestSecurityAadOperationsMixin(AutorestSecurityAadMixinABC): +class AutorestSecurityAadOperationsMixin(ClientMixinABC[PipelineClient, AutorestSecurityAadConfiguration]): @distributed_trace def head(self, **kwargs: Any) -> None: # pylint: disable=inconsistent-return-statements diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/SecurityAadSwaggerCredentialFlag/securityaadswaggercredentialflag/_security_aad_swagger_credential_flag.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/SecurityAadSwaggerCredentialFlag/securityaadswaggercredentialflag/_security_aad_swagger_credential_flag.py index 914ba651db3..685951fb47e 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/SecurityAadSwaggerCredentialFlag/securityaadswaggercredentialflag/_security_aad_swagger_credential_flag.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/SecurityAadSwaggerCredentialFlag/securityaadswaggercredentialflag/_security_aad_swagger_credential_flag.py @@ -16,7 +16,7 @@ from azure.core.rest import HttpRequest, HttpResponse from ._configuration import SecurityAadSwaggerCredentialFlagConfiguration -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer from .operations import SecurityAadSwaggerCredentialFlagOperationsMixin diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/SecurityAadSwaggerCredentialFlag/securityaadswaggercredentialflag/_utils/__init__.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/SecurityAadSwaggerCredentialFlag/securityaadswaggercredentialflag/_utils/__init__.py new file mode 100644 index 00000000000..0af9b28f660 --- /dev/null +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/SecurityAadSwaggerCredentialFlag/securityaadswaggercredentialflag/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/NonStringEnumsVersionTolerant/nonstringenumsversiontolerant/_serialization.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/SecurityAadSwaggerCredentialFlag/securityaadswaggercredentialflag/_utils/serialization.py similarity index 100% rename from packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/NonStringEnumsVersionTolerant/nonstringenumsversiontolerant/_serialization.py rename to packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/SecurityAadSwaggerCredentialFlag/securityaadswaggercredentialflag/_utils/serialization.py diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/SecurityAadSwaggerCredentialFlag/securityaadswaggercredentialflag/_utils/utils.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/SecurityAadSwaggerCredentialFlag/securityaadswaggercredentialflag/_utils/utils.py new file mode 100644 index 00000000000..39b612f39a9 --- /dev/null +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/SecurityAadSwaggerCredentialFlag/securityaadswaggercredentialflag/_utils/utils.py @@ -0,0 +1,25 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from abc import ABC +from typing import Generic, TYPE_CHECKING, TypeVar + +if TYPE_CHECKING: + from .serialization import Deserializer, Serializer + + +TClient = TypeVar("TClient") +TConfig = TypeVar("TConfig") + + +class ClientMixinABC(ABC, Generic[TClient, TConfig]): + """DO NOT use this class. It is for internal typing use only.""" + + _client: TClient + _config: TConfig + _serialize: "Serializer" + _deserialize: "Deserializer" diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/SecurityAadSwaggerCredentialFlag/securityaadswaggercredentialflag/_vendor.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/SecurityAadSwaggerCredentialFlag/securityaadswaggercredentialflag/_vendor.py deleted file mode 100644 index 02ca98dcd44..00000000000 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/SecurityAadSwaggerCredentialFlag/securityaadswaggercredentialflag/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) AutoRest Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import SecurityAadSwaggerCredentialFlagConfiguration - -if TYPE_CHECKING: - from azure.core import PipelineClient - - from ._serialization import Deserializer, Serializer - - -class SecurityAadSwaggerCredentialFlagMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "PipelineClient" - _config: SecurityAadSwaggerCredentialFlagConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/SecurityAadSwaggerCredentialFlag/securityaadswaggercredentialflag/aio/_security_aad_swagger_credential_flag.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/SecurityAadSwaggerCredentialFlag/securityaadswaggercredentialflag/aio/_security_aad_swagger_credential_flag.py index 817d2a5a669..aa6491007ee 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/SecurityAadSwaggerCredentialFlag/securityaadswaggercredentialflag/aio/_security_aad_swagger_credential_flag.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/SecurityAadSwaggerCredentialFlag/securityaadswaggercredentialflag/aio/_security_aad_swagger_credential_flag.py @@ -15,7 +15,7 @@ from azure.core.pipeline import policies from azure.core.rest import AsyncHttpResponse, HttpRequest -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import SecurityAadSwaggerCredentialFlagConfiguration from .operations import SecurityAadSwaggerCredentialFlagOperationsMixin diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/SecurityAadSwaggerCredentialFlag/securityaadswaggercredentialflag/aio/_vendor.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/SecurityAadSwaggerCredentialFlag/securityaadswaggercredentialflag/aio/_vendor.py deleted file mode 100644 index 8097e6e5627..00000000000 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/SecurityAadSwaggerCredentialFlag/securityaadswaggercredentialflag/aio/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) AutoRest Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import SecurityAadSwaggerCredentialFlagConfiguration - -if TYPE_CHECKING: - from azure.core import AsyncPipelineClient - - from .._serialization import Deserializer, Serializer - - -class SecurityAadSwaggerCredentialFlagMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "AsyncPipelineClient" - _config: SecurityAadSwaggerCredentialFlagConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/SecurityAadSwaggerCredentialFlag/securityaadswaggercredentialflag/aio/operations/_security_aad_swagger_credential_flag_operations.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/SecurityAadSwaggerCredentialFlag/securityaadswaggercredentialflag/aio/operations/_security_aad_swagger_credential_flag_operations.py index 8584db2ff62..5058b885dcb 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/SecurityAadSwaggerCredentialFlag/securityaadswaggercredentialflag/aio/operations/_security_aad_swagger_credential_flag_operations.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/SecurityAadSwaggerCredentialFlag/securityaadswaggercredentialflag/aio/operations/_security_aad_swagger_credential_flag_operations.py @@ -9,6 +9,7 @@ from collections.abc import MutableMapping from typing import Any, Callable, Dict, Optional, TypeVar +from azure.core import AsyncPipelineClient from azure.core.exceptions import ( ClientAuthenticationError, HttpResponseError, @@ -21,15 +22,16 @@ from azure.core.rest import AsyncHttpResponse, HttpRequest from azure.core.tracing.decorator_async import distributed_trace_async +from ..._utils.utils import ClientMixinABC from ...operations._security_aad_swagger_credential_flag_operations import build_head_request -from .._vendor import SecurityAadSwaggerCredentialFlagMixinABC +from .._configuration import SecurityAadSwaggerCredentialFlagConfiguration T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, AsyncHttpResponse], T, Dict[str, Any]], Any]] class SecurityAadSwaggerCredentialFlagOperationsMixin( # pylint: disable=name-too-long - SecurityAadSwaggerCredentialFlagMixinABC + ClientMixinABC[AsyncPipelineClient, SecurityAadSwaggerCredentialFlagConfiguration] ): @distributed_trace_async diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/SecurityAadSwaggerCredentialFlag/securityaadswaggercredentialflag/operations/_security_aad_swagger_credential_flag_operations.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/SecurityAadSwaggerCredentialFlag/securityaadswaggercredentialflag/operations/_security_aad_swagger_credential_flag_operations.py index f8d65192bed..9eb7464c6ab 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/SecurityAadSwaggerCredentialFlag/securityaadswaggercredentialflag/operations/_security_aad_swagger_credential_flag_operations.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/SecurityAadSwaggerCredentialFlag/securityaadswaggercredentialflag/operations/_security_aad_swagger_credential_flag_operations.py @@ -8,6 +8,7 @@ from collections.abc import MutableMapping from typing import Any, Callable, Dict, Optional, TypeVar +from azure.core import PipelineClient from azure.core.exceptions import ( ClientAuthenticationError, HttpResponseError, @@ -20,8 +21,9 @@ from azure.core.rest import HttpRequest, HttpResponse from azure.core.tracing.decorator import distributed_trace -from .._serialization import Serializer -from .._vendor import SecurityAadSwaggerCredentialFlagMixinABC +from .._configuration import SecurityAadSwaggerCredentialFlagConfiguration +from .._utils.serialization import Serializer +from .._utils.utils import ClientMixinABC T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] @@ -38,7 +40,7 @@ def build_head_request(**kwargs: Any) -> HttpRequest: class SecurityAadSwaggerCredentialFlagOperationsMixin( # pylint: disable=name-too-long - SecurityAadSwaggerCredentialFlagMixinABC + ClientMixinABC[PipelineClient, SecurityAadSwaggerCredentialFlagConfiguration] ): @distributed_trace diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/SecurityKeySwagger/securitykeyswagger/_autorest_security_key.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/SecurityKeySwagger/securitykeyswagger/_autorest_security_key.py index 32f7d0217bd..87fa9a90c50 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/SecurityKeySwagger/securitykeyswagger/_autorest_security_key.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/SecurityKeySwagger/securitykeyswagger/_autorest_security_key.py @@ -16,7 +16,7 @@ from azure.core.rest import HttpRequest, HttpResponse from ._configuration import AutorestSecurityKeyConfiguration -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer from .operations import AutorestSecurityKeyOperationsMixin diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/SecurityKeySwagger/securitykeyswagger/_utils/__init__.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/SecurityKeySwagger/securitykeyswagger/_utils/__init__.py new file mode 100644 index 00000000000..0af9b28f660 --- /dev/null +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/SecurityKeySwagger/securitykeyswagger/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ObjectTypeVersionTolerant/objecttypeversiontolerant/_serialization.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/SecurityKeySwagger/securitykeyswagger/_utils/serialization.py similarity index 100% rename from packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ObjectTypeVersionTolerant/objecttypeversiontolerant/_serialization.py rename to packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/SecurityKeySwagger/securitykeyswagger/_utils/serialization.py diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/SecurityKeySwagger/securitykeyswagger/_utils/utils.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/SecurityKeySwagger/securitykeyswagger/_utils/utils.py new file mode 100644 index 00000000000..39b612f39a9 --- /dev/null +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/SecurityKeySwagger/securitykeyswagger/_utils/utils.py @@ -0,0 +1,25 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from abc import ABC +from typing import Generic, TYPE_CHECKING, TypeVar + +if TYPE_CHECKING: + from .serialization import Deserializer, Serializer + + +TClient = TypeVar("TClient") +TConfig = TypeVar("TConfig") + + +class ClientMixinABC(ABC, Generic[TClient, TConfig]): + """DO NOT use this class. It is for internal typing use only.""" + + _client: TClient + _config: TConfig + _serialize: "Serializer" + _deserialize: "Deserializer" diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/SecurityKeySwagger/securitykeyswagger/_vendor.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/SecurityKeySwagger/securitykeyswagger/_vendor.py deleted file mode 100644 index d615edd04da..00000000000 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/SecurityKeySwagger/securitykeyswagger/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) AutoRest Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import AutorestSecurityKeyConfiguration - -if TYPE_CHECKING: - from azure.core import PipelineClient - - from ._serialization import Deserializer, Serializer - - -class AutorestSecurityKeyMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "PipelineClient" - _config: AutorestSecurityKeyConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/SecurityKeySwagger/securitykeyswagger/aio/_autorest_security_key.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/SecurityKeySwagger/securitykeyswagger/aio/_autorest_security_key.py index 63b53235585..728707551cc 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/SecurityKeySwagger/securitykeyswagger/aio/_autorest_security_key.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/SecurityKeySwagger/securitykeyswagger/aio/_autorest_security_key.py @@ -15,7 +15,7 @@ from azure.core.pipeline import policies from azure.core.rest import AsyncHttpResponse, HttpRequest -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import AutorestSecurityKeyConfiguration from .operations import AutorestSecurityKeyOperationsMixin diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/SecurityKeySwagger/securitykeyswagger/aio/_vendor.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/SecurityKeySwagger/securitykeyswagger/aio/_vendor.py deleted file mode 100644 index cf209892619..00000000000 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/SecurityKeySwagger/securitykeyswagger/aio/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) AutoRest Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import AutorestSecurityKeyConfiguration - -if TYPE_CHECKING: - from azure.core import AsyncPipelineClient - - from .._serialization import Deserializer, Serializer - - -class AutorestSecurityKeyMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "AsyncPipelineClient" - _config: AutorestSecurityKeyConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/SecurityKeySwagger/securitykeyswagger/aio/operations/_autorest_security_key_operations.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/SecurityKeySwagger/securitykeyswagger/aio/operations/_autorest_security_key_operations.py index 8a56465c8de..f85ff3ce671 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/SecurityKeySwagger/securitykeyswagger/aio/operations/_autorest_security_key_operations.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/SecurityKeySwagger/securitykeyswagger/aio/operations/_autorest_security_key_operations.py @@ -9,6 +9,7 @@ from collections.abc import MutableMapping from typing import Any, Callable, Dict, Optional, TypeVar +from azure.core import AsyncPipelineClient from azure.core.exceptions import ( ClientAuthenticationError, HttpResponseError, @@ -21,14 +22,15 @@ from azure.core.rest import AsyncHttpResponse, HttpRequest from azure.core.tracing.decorator_async import distributed_trace_async +from ..._utils.utils import ClientMixinABC from ...operations._autorest_security_key_operations import build_head_request -from .._vendor import AutorestSecurityKeyMixinABC +from .._configuration import AutorestSecurityKeyConfiguration T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, AsyncHttpResponse], T, Dict[str, Any]], Any]] -class AutorestSecurityKeyOperationsMixin(AutorestSecurityKeyMixinABC): +class AutorestSecurityKeyOperationsMixin(ClientMixinABC[AsyncPipelineClient, AutorestSecurityKeyConfiguration]): @distributed_trace_async async def head(self, **kwargs: Any) -> None: diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/SecurityKeySwagger/securitykeyswagger/operations/_autorest_security_key_operations.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/SecurityKeySwagger/securitykeyswagger/operations/_autorest_security_key_operations.py index 757602a598a..a644da1e087 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/SecurityKeySwagger/securitykeyswagger/operations/_autorest_security_key_operations.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/SecurityKeySwagger/securitykeyswagger/operations/_autorest_security_key_operations.py @@ -8,6 +8,7 @@ from collections.abc import MutableMapping from typing import Any, Callable, Dict, Optional, TypeVar +from azure.core import PipelineClient from azure.core.exceptions import ( ClientAuthenticationError, HttpResponseError, @@ -20,8 +21,9 @@ from azure.core.rest import HttpRequest, HttpResponse from azure.core.tracing.decorator import distributed_trace -from .._serialization import Serializer -from .._vendor import AutorestSecurityKeyMixinABC +from .._configuration import AutorestSecurityKeyConfiguration +from .._utils.serialization import Serializer +from .._utils.utils import ClientMixinABC T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] @@ -37,7 +39,7 @@ def build_head_request(**kwargs: Any) -> HttpRequest: return HttpRequest(method="HEAD", url=_url, **kwargs) -class AutorestSecurityKeyOperationsMixin(AutorestSecurityKeyMixinABC): +class AutorestSecurityKeyOperationsMixin(ClientMixinABC[PipelineClient, AutorestSecurityKeyConfiguration]): @distributed_trace def head(self, **kwargs: Any) -> None: # pylint: disable=inconsistent-return-statements diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/SecurityKeySwaggerCredentialFlag/securitykeyswaggercredentialflag/_security_key_swagger_credential_flag.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/SecurityKeySwaggerCredentialFlag/securitykeyswaggercredentialflag/_security_key_swagger_credential_flag.py index df5086605b6..0702c5c791d 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/SecurityKeySwaggerCredentialFlag/securitykeyswaggercredentialflag/_security_key_swagger_credential_flag.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/SecurityKeySwaggerCredentialFlag/securitykeyswaggercredentialflag/_security_key_swagger_credential_flag.py @@ -15,7 +15,7 @@ from azure.core.rest import HttpRequest, HttpResponse from ._configuration import SecurityKeySwaggerCredentialFlagConfiguration -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer from .operations import SecurityKeySwaggerCredentialFlagOperationsMixin if TYPE_CHECKING: diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/SecurityKeySwaggerCredentialFlag/securitykeyswaggercredentialflag/_utils/__init__.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/SecurityKeySwaggerCredentialFlag/securitykeyswaggercredentialflag/_utils/__init__.py new file mode 100644 index 00000000000..0af9b28f660 --- /dev/null +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/SecurityKeySwaggerCredentialFlag/securitykeyswaggercredentialflag/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ParameterFlatteningVersionTolerant/parameterflatteningversiontolerant/_serialization.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/SecurityKeySwaggerCredentialFlag/securitykeyswaggercredentialflag/_utils/serialization.py similarity index 100% rename from packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ParameterFlatteningVersionTolerant/parameterflatteningversiontolerant/_serialization.py rename to packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/SecurityKeySwaggerCredentialFlag/securitykeyswaggercredentialflag/_utils/serialization.py diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/SecurityKeySwaggerCredentialFlag/securitykeyswaggercredentialflag/_utils/utils.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/SecurityKeySwaggerCredentialFlag/securitykeyswaggercredentialflag/_utils/utils.py new file mode 100644 index 00000000000..39b612f39a9 --- /dev/null +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/SecurityKeySwaggerCredentialFlag/securitykeyswaggercredentialflag/_utils/utils.py @@ -0,0 +1,25 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from abc import ABC +from typing import Generic, TYPE_CHECKING, TypeVar + +if TYPE_CHECKING: + from .serialization import Deserializer, Serializer + + +TClient = TypeVar("TClient") +TConfig = TypeVar("TConfig") + + +class ClientMixinABC(ABC, Generic[TClient, TConfig]): + """DO NOT use this class. It is for internal typing use only.""" + + _client: TClient + _config: TConfig + _serialize: "Serializer" + _deserialize: "Deserializer" diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/SecurityKeySwaggerCredentialFlag/securitykeyswaggercredentialflag/_vendor.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/SecurityKeySwaggerCredentialFlag/securitykeyswaggercredentialflag/_vendor.py deleted file mode 100644 index aa041ecd52b..00000000000 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/SecurityKeySwaggerCredentialFlag/securitykeyswaggercredentialflag/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) AutoRest Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import SecurityKeySwaggerCredentialFlagConfiguration - -if TYPE_CHECKING: - from azure.core import PipelineClient - - from ._serialization import Deserializer, Serializer - - -class SecurityKeySwaggerCredentialFlagMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "PipelineClient" - _config: SecurityKeySwaggerCredentialFlagConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/SecurityKeySwaggerCredentialFlag/securitykeyswaggercredentialflag/aio/_security_key_swagger_credential_flag.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/SecurityKeySwaggerCredentialFlag/securitykeyswaggercredentialflag/aio/_security_key_swagger_credential_flag.py index 1aed3079a24..64be0707df5 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/SecurityKeySwaggerCredentialFlag/securitykeyswaggercredentialflag/aio/_security_key_swagger_credential_flag.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/SecurityKeySwaggerCredentialFlag/securitykeyswaggercredentialflag/aio/_security_key_swagger_credential_flag.py @@ -14,7 +14,7 @@ from azure.core.pipeline import policies from azure.core.rest import AsyncHttpResponse, HttpRequest -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import SecurityKeySwaggerCredentialFlagConfiguration from .operations import SecurityKeySwaggerCredentialFlagOperationsMixin diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/SecurityKeySwaggerCredentialFlag/securitykeyswaggercredentialflag/aio/_vendor.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/SecurityKeySwaggerCredentialFlag/securitykeyswaggercredentialflag/aio/_vendor.py deleted file mode 100644 index db1ac1a406a..00000000000 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/SecurityKeySwaggerCredentialFlag/securitykeyswaggercredentialflag/aio/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) AutoRest Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import SecurityKeySwaggerCredentialFlagConfiguration - -if TYPE_CHECKING: - from azure.core import AsyncPipelineClient - - from .._serialization import Deserializer, Serializer - - -class SecurityKeySwaggerCredentialFlagMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "AsyncPipelineClient" - _config: SecurityKeySwaggerCredentialFlagConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/SecurityKeySwaggerCredentialFlag/securitykeyswaggercredentialflag/aio/operations/_security_key_swagger_credential_flag_operations.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/SecurityKeySwaggerCredentialFlag/securitykeyswaggercredentialflag/aio/operations/_security_key_swagger_credential_flag_operations.py index 906275c3b20..97994fcf64c 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/SecurityKeySwaggerCredentialFlag/securitykeyswaggercredentialflag/aio/operations/_security_key_swagger_credential_flag_operations.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/SecurityKeySwaggerCredentialFlag/securitykeyswaggercredentialflag/aio/operations/_security_key_swagger_credential_flag_operations.py @@ -9,6 +9,7 @@ from collections.abc import MutableMapping from typing import Any, Callable, Dict, Optional, TypeVar +from azure.core import AsyncPipelineClient from azure.core.exceptions import ( ClientAuthenticationError, HttpResponseError, @@ -21,15 +22,16 @@ from azure.core.rest import AsyncHttpResponse, HttpRequest from azure.core.tracing.decorator_async import distributed_trace_async +from ..._utils.utils import ClientMixinABC from ...operations._security_key_swagger_credential_flag_operations import build_head_request -from .._vendor import SecurityKeySwaggerCredentialFlagMixinABC +from .._configuration import SecurityKeySwaggerCredentialFlagConfiguration T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, AsyncHttpResponse], T, Dict[str, Any]], Any]] class SecurityKeySwaggerCredentialFlagOperationsMixin( # pylint: disable=name-too-long - SecurityKeySwaggerCredentialFlagMixinABC + ClientMixinABC[AsyncPipelineClient, SecurityKeySwaggerCredentialFlagConfiguration] ): @distributed_trace_async diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/SecurityKeySwaggerCredentialFlag/securitykeyswaggercredentialflag/operations/_security_key_swagger_credential_flag_operations.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/SecurityKeySwaggerCredentialFlag/securitykeyswaggercredentialflag/operations/_security_key_swagger_credential_flag_operations.py index da225359d1c..2fa413d6cee 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/SecurityKeySwaggerCredentialFlag/securitykeyswaggercredentialflag/operations/_security_key_swagger_credential_flag_operations.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/SecurityKeySwaggerCredentialFlag/securitykeyswaggercredentialflag/operations/_security_key_swagger_credential_flag_operations.py @@ -8,6 +8,7 @@ from collections.abc import MutableMapping from typing import Any, Callable, Dict, Optional, TypeVar +from azure.core import PipelineClient from azure.core.exceptions import ( ClientAuthenticationError, HttpResponseError, @@ -20,8 +21,9 @@ from azure.core.rest import HttpRequest, HttpResponse from azure.core.tracing.decorator import distributed_trace -from .._serialization import Serializer -from .._vendor import SecurityKeySwaggerCredentialFlagMixinABC +from .._configuration import SecurityKeySwaggerCredentialFlagConfiguration +from .._utils.serialization import Serializer +from .._utils.utils import ClientMixinABC T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] @@ -38,7 +40,7 @@ def build_head_request(**kwargs: Any) -> HttpRequest: class SecurityKeySwaggerCredentialFlagOperationsMixin( # pylint: disable=name-too-long - SecurityKeySwaggerCredentialFlagMixinABC + ClientMixinABC[PipelineClient, SecurityKeySwaggerCredentialFlagConfiguration] ): @distributed_trace diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/UrlMultiCollectionFormat/urlmulticollectionformat/_auto_rest_url_mutli_collection_format_test_service.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/UrlMultiCollectionFormat/urlmulticollectionformat/_auto_rest_url_mutli_collection_format_test_service.py index 2903265c391..e9fb1e8e6dc 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/UrlMultiCollectionFormat/urlmulticollectionformat/_auto_rest_url_mutli_collection_format_test_service.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/UrlMultiCollectionFormat/urlmulticollectionformat/_auto_rest_url_mutli_collection_format_test_service.py @@ -16,7 +16,7 @@ from . import models as _models from ._configuration import AutoRestUrlMutliCollectionFormatTestServiceConfiguration -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer from .operations import QueriesOperations diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/UrlMultiCollectionFormat/urlmulticollectionformat/_utils/__init__.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/UrlMultiCollectionFormat/urlmulticollectionformat/_utils/__init__.py new file mode 100644 index 00000000000..0af9b28f660 --- /dev/null +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/UrlMultiCollectionFormat/urlmulticollectionformat/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ParameterizedEndpointVersionTolerant/parameterizedendpointversiontolerant/_serialization.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/UrlMultiCollectionFormat/urlmulticollectionformat/_utils/serialization.py similarity index 100% rename from packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ParameterizedEndpointVersionTolerant/parameterizedendpointversiontolerant/_serialization.py rename to packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/UrlMultiCollectionFormat/urlmulticollectionformat/_utils/serialization.py diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/UrlMultiCollectionFormat/urlmulticollectionformat/aio/_auto_rest_url_mutli_collection_format_test_service.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/UrlMultiCollectionFormat/urlmulticollectionformat/aio/_auto_rest_url_mutli_collection_format_test_service.py index 9ab2eb42cd4..83e04282d7f 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/UrlMultiCollectionFormat/urlmulticollectionformat/aio/_auto_rest_url_mutli_collection_format_test_service.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/UrlMultiCollectionFormat/urlmulticollectionformat/aio/_auto_rest_url_mutli_collection_format_test_service.py @@ -15,7 +15,7 @@ from azure.core.rest import AsyncHttpResponse, HttpRequest from .. import models as _models -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import AutoRestUrlMutliCollectionFormatTestServiceConfiguration from .operations import QueriesOperations diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/UrlMultiCollectionFormat/urlmulticollectionformat/aio/operations/_queries_operations.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/UrlMultiCollectionFormat/urlmulticollectionformat/aio/operations/_queries_operations.py index 6a699f4251f..a21f48379b4 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/UrlMultiCollectionFormat/urlmulticollectionformat/aio/operations/_queries_operations.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/UrlMultiCollectionFormat/urlmulticollectionformat/aio/operations/_queries_operations.py @@ -22,7 +22,7 @@ from azure.core.tracing.decorator_async import distributed_trace_async from ... import models as _models -from ..._serialization import Deserializer, Serializer +from ..._utils.serialization import Deserializer, Serializer from ...operations._queries_operations import ( build_array_string_multi_empty_request, build_array_string_multi_null_request, diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/UrlMultiCollectionFormat/urlmulticollectionformat/models/_models_py3.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/UrlMultiCollectionFormat/urlmulticollectionformat/models/_models_py3.py index 1d1b7707def..109cf147510 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/UrlMultiCollectionFormat/urlmulticollectionformat/models/_models_py3.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/UrlMultiCollectionFormat/urlmulticollectionformat/models/_models_py3.py @@ -8,7 +8,7 @@ from typing import Any, Optional -from .. import _serialization +from .._utils import serialization as _serialization class Error(_serialization.Model): diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/UrlMultiCollectionFormat/urlmulticollectionformat/operations/_queries_operations.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/UrlMultiCollectionFormat/urlmulticollectionformat/operations/_queries_operations.py index 75c76c5e67d..5a900e2ec3e 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/UrlMultiCollectionFormat/urlmulticollectionformat/operations/_queries_operations.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/UrlMultiCollectionFormat/urlmulticollectionformat/operations/_queries_operations.py @@ -24,7 +24,7 @@ from .. import models as _models from .._configuration import AutoRestUrlMutliCollectionFormatTestServiceConfiguration -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Validation/validation/_utils/__init__.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Validation/validation/_utils/__init__.py new file mode 100644 index 00000000000..0af9b28f660 --- /dev/null +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Validation/validation/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Validation/validation/_utils/utils.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Validation/validation/_utils/utils.py new file mode 100644 index 00000000000..e08efe82ff7 --- /dev/null +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Validation/validation/_utils/utils.py @@ -0,0 +1,25 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from abc import ABC +from typing import Generic, TYPE_CHECKING, TypeVar + +if TYPE_CHECKING: + from msrest import Deserializer, Serializer + + +TClient = TypeVar("TClient") +TConfig = TypeVar("TConfig") + + +class ClientMixinABC(ABC, Generic[TClient, TConfig]): + """DO NOT use this class. It is for internal typing use only.""" + + _client: TClient + _config: TConfig + _serialize: "Serializer" + _deserialize: "Deserializer" diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Validation/validation/_vendor.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Validation/validation/_vendor.py deleted file mode 100644 index 256be7d1e1c..00000000000 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Validation/validation/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) AutoRest Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import AutoRestValidationTestConfiguration - -if TYPE_CHECKING: - from msrest import Deserializer, Serializer - - from azure.core import PipelineClient - - -class AutoRestValidationTestMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "PipelineClient" - _config: AutoRestValidationTestConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Validation/validation/aio/_vendor.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Validation/validation/aio/_vendor.py deleted file mode 100644 index 5d41397de95..00000000000 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Validation/validation/aio/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) AutoRest Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import AutoRestValidationTestConfiguration - -if TYPE_CHECKING: - from msrest import Deserializer, Serializer - - from azure.core import AsyncPipelineClient - - -class AutoRestValidationTestMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "AsyncPipelineClient" - _config: AutoRestValidationTestConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Validation/validation/aio/operations/_auto_rest_validation_test_operations.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Validation/validation/aio/operations/_auto_rest_validation_test_operations.py index b561a844bdb..a044ea07e7d 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Validation/validation/aio/operations/_auto_rest_validation_test_operations.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Validation/validation/aio/operations/_auto_rest_validation_test_operations.py @@ -10,6 +10,7 @@ from io import IOBase from typing import Any, Callable, Dict, IO, Literal, Optional, TypeVar, Union, overload +from azure.core import AsyncPipelineClient from azure.core.exceptions import ( ClientAuthenticationError, HttpResponseError, @@ -24,19 +25,20 @@ from azure.core.utils import case_insensitive_dict from ... import models as _models +from ..._utils.utils import ClientMixinABC from ...operations._auto_rest_validation_test_operations import ( build_get_with_constant_in_path_request, build_post_with_constant_in_body_request, build_validation_of_body_request, build_validation_of_method_parameters_request, ) -from .._vendor import AutoRestValidationTestMixinABC +from .._configuration import AutoRestValidationTestConfiguration T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, AsyncHttpResponse], T, Dict[str, Any]], Any]] -class AutoRestValidationTestOperationsMixin(AutoRestValidationTestMixinABC): +class AutoRestValidationTestOperationsMixin(ClientMixinABC[AsyncPipelineClient, AutoRestValidationTestConfiguration]): @distributed_trace_async async def validation_of_method_parameters( diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Validation/validation/operations/_auto_rest_validation_test_operations.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Validation/validation/operations/_auto_rest_validation_test_operations.py index 97019d0b7db..fab6a91f697 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Validation/validation/operations/_auto_rest_validation_test_operations.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Validation/validation/operations/_auto_rest_validation_test_operations.py @@ -11,6 +11,7 @@ from msrest import Serializer +from azure.core import PipelineClient from azure.core.exceptions import ( ClientAuthenticationError, HttpResponseError, @@ -25,7 +26,8 @@ from azure.core.utils import case_insensitive_dict from .. import models as _models -from .._vendor import AutoRestValidationTestMixinABC +from .._configuration import AutoRestValidationTestConfiguration +from .._utils.utils import ClientMixinABC T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] @@ -132,7 +134,7 @@ def build_post_with_constant_in_body_request(**kwargs: Any) -> HttpRequest: return HttpRequest(method="POST", url=_url, headers=_headers, **kwargs) -class AutoRestValidationTestOperationsMixin(AutoRestValidationTestMixinABC): +class AutoRestValidationTestOperationsMixin(ClientMixinABC[PipelineClient, AutoRestValidationTestConfiguration]): @distributed_trace def validation_of_method_parameters(self, resource_group_name: str, id: int, **kwargs: Any) -> _models.Product: diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Xml/xmlservice/_auto_rest_swagger_batxml_service.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Xml/xmlservice/_auto_rest_swagger_batxml_service.py index 8b9e258892d..dde2913a65b 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Xml/xmlservice/_auto_rest_swagger_batxml_service.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Xml/xmlservice/_auto_rest_swagger_batxml_service.py @@ -16,7 +16,7 @@ from . import models as _models from ._configuration import AutoRestSwaggerBATXMLServiceConfiguration -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer from .operations import XmlOperations diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Xml/xmlservice/_utils/__init__.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Xml/xmlservice/_utils/__init__.py new file mode 100644 index 00000000000..0af9b28f660 --- /dev/null +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Xml/xmlservice/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ReportVersionTolerant/reportversiontolerant/_serialization.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Xml/xmlservice/_utils/serialization.py similarity index 100% rename from packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ReportVersionTolerant/reportversiontolerant/_serialization.py rename to packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Xml/xmlservice/_utils/serialization.py diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Xml/xmlservice/aio/_auto_rest_swagger_batxml_service.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Xml/xmlservice/aio/_auto_rest_swagger_batxml_service.py index 71d898a4808..54c717cf2c3 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Xml/xmlservice/aio/_auto_rest_swagger_batxml_service.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Xml/xmlservice/aio/_auto_rest_swagger_batxml_service.py @@ -15,7 +15,7 @@ from azure.core.rest import AsyncHttpResponse, HttpRequest from .. import models as _models -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import AutoRestSwaggerBATXMLServiceConfiguration from .operations import XmlOperations diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Xml/xmlservice/aio/operations/_xml_operations.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Xml/xmlservice/aio/operations/_xml_operations.py index 5695920e69b..2afe03e2b6c 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Xml/xmlservice/aio/operations/_xml_operations.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Xml/xmlservice/aio/operations/_xml_operations.py @@ -24,7 +24,7 @@ from azure.core.utils import case_insensitive_dict from ... import models as _models -from ..._serialization import Deserializer, Serializer +from ..._utils.serialization import Deserializer, Serializer from ...operations._xml_operations import ( build_get_acls_request, build_get_bytes_request, diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Xml/xmlservice/models/_models_py3.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Xml/xmlservice/models/_models_py3.py index 6b8562c0332..fd349d03a40 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Xml/xmlservice/models/_models_py3.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Xml/xmlservice/models/_models_py3.py @@ -10,7 +10,7 @@ import datetime from typing import Any, Dict, List, Optional, TYPE_CHECKING, Union -from .. import _serialization +from .._utils import serialization as _serialization if TYPE_CHECKING: from .. import models as _models diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Xml/xmlservice/operations/_xml_operations.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Xml/xmlservice/operations/_xml_operations.py index a977ade7159..e5840693819 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Xml/xmlservice/operations/_xml_operations.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/Xml/xmlservice/operations/_xml_operations.py @@ -25,7 +25,7 @@ from .. import models as _models from .._configuration import AutoRestSwaggerBATXMLServiceConfiguration -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/XmsErrorResponse/xmserrorresponse/_utils/__init__.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/XmsErrorResponse/xmserrorresponse/_utils/__init__.py new file mode 100644 index 00000000000..0af9b28f660 --- /dev/null +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/XmsErrorResponse/xmserrorresponse/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/RequiredOptionalVersionTolerant/requiredoptionalversiontolerant/_serialization.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/XmsErrorResponse/xmserrorresponse/_utils/serialization.py similarity index 100% rename from packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/RequiredOptionalVersionTolerant/requiredoptionalversiontolerant/_serialization.py rename to packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/XmsErrorResponse/xmserrorresponse/_utils/serialization.py diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/XmsErrorResponse/xmserrorresponse/_xms_error_response_extensions.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/XmsErrorResponse/xmserrorresponse/_xms_error_response_extensions.py index 128e6a99526..9934f84856b 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/XmsErrorResponse/xmserrorresponse/_xms_error_response_extensions.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/XmsErrorResponse/xmserrorresponse/_xms_error_response_extensions.py @@ -16,7 +16,7 @@ from . import models as _models from ._configuration import XMSErrorResponseExtensionsConfiguration -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer from .operations import PetOperations diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/XmsErrorResponse/xmserrorresponse/aio/_xms_error_response_extensions.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/XmsErrorResponse/xmserrorresponse/aio/_xms_error_response_extensions.py index cfe19779ed1..9526e118e33 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/XmsErrorResponse/xmserrorresponse/aio/_xms_error_response_extensions.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/XmsErrorResponse/xmserrorresponse/aio/_xms_error_response_extensions.py @@ -15,7 +15,7 @@ from azure.core.rest import AsyncHttpResponse, HttpRequest from .. import models as _models -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import XMSErrorResponseExtensionsConfiguration from .operations import PetOperations diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/XmsErrorResponse/xmserrorresponse/aio/operations/_pet_operations.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/XmsErrorResponse/xmserrorresponse/aio/operations/_pet_operations.py index 3d2aac3266a..ccfb3b41066 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/XmsErrorResponse/xmserrorresponse/aio/operations/_pet_operations.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/XmsErrorResponse/xmserrorresponse/aio/operations/_pet_operations.py @@ -22,7 +22,7 @@ from azure.core.tracing.decorator_async import distributed_trace_async from ... import models as _models -from ..._serialization import Deserializer, Serializer +from ..._utils.serialization import Deserializer, Serializer from ...operations._pet_operations import ( build_do_something_request, build_get_pet_by_id_request, diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/XmsErrorResponse/xmserrorresponse/models/_models_py3.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/XmsErrorResponse/xmserrorresponse/models/_models_py3.py index 99be60cefcc..b8c8e93beb7 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/XmsErrorResponse/xmserrorresponse/models/_models_py3.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/XmsErrorResponse/xmserrorresponse/models/_models_py3.py @@ -8,7 +8,7 @@ from typing import Any, Optional -from .. import _serialization +from .._utils import serialization as _serialization class Animal(_serialization.Model): diff --git a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/XmsErrorResponse/xmserrorresponse/operations/_pet_operations.py b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/XmsErrorResponse/xmserrorresponse/operations/_pet_operations.py index 2ab28b7ac19..a3056697ac0 100644 --- a/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/XmsErrorResponse/xmserrorresponse/operations/_pet_operations.py +++ b/packages/autorest.python/test/vanilla/legacy/Expected/AcceptanceTests/XmsErrorResponse/xmserrorresponse/operations/_pet_operations.py @@ -24,7 +24,7 @@ from .. import models as _models from .._configuration import XMSErrorResponseExtensionsConfiguration -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/autorest.python/test/vanilla/legacy/tox.ini b/packages/autorest.python/test/vanilla/legacy/tox.ini index 4cbd7d922c8..42c52381b87 100644 --- a/packages/autorest.python/test/vanilla/legacy/tox.ini +++ b/packages/autorest.python/test/vanilla/legacy/tox.ini @@ -8,11 +8,11 @@ deps= -r requirements.txt -r ../../../../../eng/dev_requirements.txt commands= - pytest --cov=Expected + pytest [testenv:ci] commands = - pytest --cov=Expected + pytest [testenv:apiview] commands = diff --git a/packages/autorest.python/test/vanilla/version-tolerant/AcceptanceTests/asynctests/test_array.py b/packages/autorest.python/test/vanilla/version-tolerant/AcceptanceTests/asynctests/test_array.py index cb87a5f27e0..b765a76f1a9 100644 --- a/packages/autorest.python/test/vanilla/version-tolerant/AcceptanceTests/asynctests/test_array.py +++ b/packages/autorest.python/test/vanilla/version-tolerant/AcceptanceTests/asynctests/test_array.py @@ -27,7 +27,7 @@ from async_generator import yield_, async_generator from datetime import timedelta -from bodyarrayversiontolerant._serialization import Serializer +from bodyarrayversiontolerant._utils.serialization import Serializer from azure.core.exceptions import DecodeError from base64 import b64encode from ..serializer import deserialize_base64 diff --git a/packages/autorest.python/test/vanilla/version-tolerant/AcceptanceTests/asynctests/test_complex.py b/packages/autorest.python/test/vanilla/version-tolerant/AcceptanceTests/asynctests/test_complex.py index b890e89bfd0..ccd61e17846 100644 --- a/packages/autorest.python/test/vanilla/version-tolerant/AcceptanceTests/asynctests/test_complex.py +++ b/packages/autorest.python/test/vanilla/version-tolerant/AcceptanceTests/asynctests/test_complex.py @@ -27,7 +27,7 @@ import isodate from async_generator import yield_, async_generator from datetime import datetime, timedelta, tzinfo -from bodycomplexversiontolerant._serialization import Serializer, Deserializer +from bodycomplexversiontolerant._utils.serialization import Serializer, Deserializer from azure.core.exceptions import DeserializationError from base64 import b64decode, b64encode from azure.core.exceptions import HttpResponseError diff --git a/packages/autorest.python/test/vanilla/version-tolerant/AcceptanceTests/test_array.py b/packages/autorest.python/test/vanilla/version-tolerant/AcceptanceTests/test_array.py index a5ec189f60b..329a64db994 100644 --- a/packages/autorest.python/test/vanilla/version-tolerant/AcceptanceTests/test_array.py +++ b/packages/autorest.python/test/vanilla/version-tolerant/AcceptanceTests/test_array.py @@ -26,7 +26,7 @@ import isodate from datetime import timedelta -from bodyarrayversiontolerant._serialization import Serializer +from bodyarrayversiontolerant._utils.serialization import Serializer from azure.core.exceptions import DecodeError from base64 import b64encode, b64decode from .serializer import deserialize_base64 diff --git a/packages/autorest.python/test/vanilla/version-tolerant/AcceptanceTests/test_complex.py b/packages/autorest.python/test/vanilla/version-tolerant/AcceptanceTests/test_complex.py index dbcb64ac707..3a06b2552e7 100644 --- a/packages/autorest.python/test/vanilla/version-tolerant/AcceptanceTests/test_complex.py +++ b/packages/autorest.python/test/vanilla/version-tolerant/AcceptanceTests/test_complex.py @@ -27,7 +27,7 @@ import pytest import isodate from datetime import datetime, timedelta, tzinfo -from bodycomplexversiontolerant._serialization import Serializer, Deserializer +from bodycomplexversiontolerant._utils.serialization import Serializer, Deserializer from azure.core.exceptions import DeserializationError from base64 import b64decode, b64encode from azure.core.exceptions import HttpResponseError diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/AdditionalPropertiesVersionTolerant/additionalpropertiesversiontolerant/_client.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/AdditionalPropertiesVersionTolerant/additionalpropertiesversiontolerant/_client.py index 72e5a8c21bb..12b8f1b9c26 100644 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/AdditionalPropertiesVersionTolerant/additionalpropertiesversiontolerant/_client.py +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/AdditionalPropertiesVersionTolerant/additionalpropertiesversiontolerant/_client.py @@ -15,7 +15,7 @@ from azure.core.rest import HttpRequest, HttpResponse from ._configuration import AdditionalPropertiesClientConfiguration -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer from .operations import PetsOperations diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/AdditionalPropertiesVersionTolerant/additionalpropertiesversiontolerant/_utils/__init__.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/AdditionalPropertiesVersionTolerant/additionalpropertiesversiontolerant/_utils/__init__.py new file mode 100644 index 00000000000..0af9b28f660 --- /dev/null +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/AdditionalPropertiesVersionTolerant/additionalpropertiesversiontolerant/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ReservedWordsVersionTolerant/reservedwordsversiontolerant/_serialization.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/AdditionalPropertiesVersionTolerant/additionalpropertiesversiontolerant/_utils/serialization.py similarity index 100% rename from packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ReservedWordsVersionTolerant/reservedwordsversiontolerant/_serialization.py rename to packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/AdditionalPropertiesVersionTolerant/additionalpropertiesversiontolerant/_utils/serialization.py diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/AdditionalPropertiesVersionTolerant/additionalpropertiesversiontolerant/aio/_client.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/AdditionalPropertiesVersionTolerant/additionalpropertiesversiontolerant/aio/_client.py index bf722ff4c7a..e09f59f1c1b 100644 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/AdditionalPropertiesVersionTolerant/additionalpropertiesversiontolerant/aio/_client.py +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/AdditionalPropertiesVersionTolerant/additionalpropertiesversiontolerant/aio/_client.py @@ -14,7 +14,7 @@ from azure.core.pipeline import policies from azure.core.rest import AsyncHttpResponse, HttpRequest -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import AdditionalPropertiesClientConfiguration from .operations import PetsOperations diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/AdditionalPropertiesVersionTolerant/additionalpropertiesversiontolerant/aio/operations/_operations.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/AdditionalPropertiesVersionTolerant/additionalpropertiesversiontolerant/aio/operations/_operations.py index 008f6ad4d37..ebc2dd1ca94 100644 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/AdditionalPropertiesVersionTolerant/additionalpropertiesversiontolerant/aio/operations/_operations.py +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/AdditionalPropertiesVersionTolerant/additionalpropertiesversiontolerant/aio/operations/_operations.py @@ -23,7 +23,7 @@ from azure.core.tracing.decorator_async import distributed_trace_async from azure.core.utils import case_insensitive_dict -from ..._serialization import Deserializer, Serializer +from ..._utils.serialization import Deserializer, Serializer from ...operations._operations import ( build_pets_create_ap_in_properties_request, build_pets_create_ap_in_properties_with_ap_string_request, diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/AdditionalPropertiesVersionTolerant/additionalpropertiesversiontolerant/operations/_operations.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/AdditionalPropertiesVersionTolerant/additionalpropertiesversiontolerant/operations/_operations.py index c1cc1bbcbe4..38de325ae08 100644 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/AdditionalPropertiesVersionTolerant/additionalpropertiesversiontolerant/operations/_operations.py +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/AdditionalPropertiesVersionTolerant/additionalpropertiesversiontolerant/operations/_operations.py @@ -25,7 +25,7 @@ from azure.core.utils import case_insensitive_dict from .._configuration import AdditionalPropertiesClientConfiguration -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer JSON = MutableMapping[str, Any] T = TypeVar("T") diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/AnythingVersionTolerant/anythingversiontolerant/_client.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/AnythingVersionTolerant/anythingversiontolerant/_client.py index 519f7a6d1d4..f85ae753b2c 100644 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/AnythingVersionTolerant/anythingversiontolerant/_client.py +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/AnythingVersionTolerant/anythingversiontolerant/_client.py @@ -16,7 +16,7 @@ from ._configuration import AnythingClientConfiguration from ._operations import AnythingClientOperationsMixin -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer class AnythingClient(AnythingClientOperationsMixin): # pylint: disable=client-accepts-api-version-keyword diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/AnythingVersionTolerant/anythingversiontolerant/_operations/_operations.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/AnythingVersionTolerant/anythingversiontolerant/_operations/_operations.py index cbc250e3733..19fd01b4b5f 100644 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/AnythingVersionTolerant/anythingversiontolerant/_operations/_operations.py +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/AnythingVersionTolerant/anythingversiontolerant/_operations/_operations.py @@ -8,6 +8,7 @@ from collections.abc import MutableMapping from typing import Any, Callable, Dict, Optional, TypeVar, cast +from azure.core import PipelineClient from azure.core.exceptions import ( ClientAuthenticationError, HttpResponseError, @@ -21,8 +22,9 @@ from azure.core.tracing.decorator import distributed_trace from azure.core.utils import case_insensitive_dict -from .._serialization import Serializer -from .._vendor import AnythingClientMixinABC +from .._configuration import AnythingClientConfiguration +from .._utils.serialization import Serializer +from .._utils.utils import ClientMixinABC T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] @@ -115,7 +117,7 @@ def build_anything_put_array_request(*, json: Any, **kwargs: Any) -> HttpRequest return HttpRequest(method="PUT", url=_url, headers=_headers, json=json, **kwargs) -class AnythingClientOperationsMixin(AnythingClientMixinABC): +class AnythingClientOperationsMixin(ClientMixinABC[PipelineClient, AnythingClientConfiguration]): @distributed_trace def get_object(self, **kwargs: Any) -> Any: diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/AnythingVersionTolerant/anythingversiontolerant/_utils/__init__.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/AnythingVersionTolerant/anythingversiontolerant/_utils/__init__.py new file mode 100644 index 00000000000..0af9b28f660 --- /dev/null +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/AnythingVersionTolerant/anythingversiontolerant/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/SecurityAadSwaggerVersionTolerant/securityaadswaggerversiontolerant/_serialization.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/AnythingVersionTolerant/anythingversiontolerant/_utils/serialization.py similarity index 100% rename from packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/SecurityAadSwaggerVersionTolerant/securityaadswaggerversiontolerant/_serialization.py rename to packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/AnythingVersionTolerant/anythingversiontolerant/_utils/serialization.py diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/AnythingVersionTolerant/anythingversiontolerant/_utils/utils.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/AnythingVersionTolerant/anythingversiontolerant/_utils/utils.py new file mode 100644 index 00000000000..39b612f39a9 --- /dev/null +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/AnythingVersionTolerant/anythingversiontolerant/_utils/utils.py @@ -0,0 +1,25 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from abc import ABC +from typing import Generic, TYPE_CHECKING, TypeVar + +if TYPE_CHECKING: + from .serialization import Deserializer, Serializer + + +TClient = TypeVar("TClient") +TConfig = TypeVar("TConfig") + + +class ClientMixinABC(ABC, Generic[TClient, TConfig]): + """DO NOT use this class. It is for internal typing use only.""" + + _client: TClient + _config: TConfig + _serialize: "Serializer" + _deserialize: "Deserializer" diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/AnythingVersionTolerant/anythingversiontolerant/_vendor.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/AnythingVersionTolerant/anythingversiontolerant/_vendor.py deleted file mode 100644 index db0a5a9a33b..00000000000 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/AnythingVersionTolerant/anythingversiontolerant/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) AutoRest Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import AnythingClientConfiguration - -if TYPE_CHECKING: - from azure.core import PipelineClient - - from ._serialization import Deserializer, Serializer - - -class AnythingClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "PipelineClient" - _config: AnythingClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/AnythingVersionTolerant/anythingversiontolerant/aio/_client.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/AnythingVersionTolerant/anythingversiontolerant/aio/_client.py index 328e25d83cf..8e3a540c4c5 100644 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/AnythingVersionTolerant/anythingversiontolerant/aio/_client.py +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/AnythingVersionTolerant/anythingversiontolerant/aio/_client.py @@ -14,7 +14,7 @@ from azure.core.pipeline import policies from azure.core.rest import AsyncHttpResponse, HttpRequest -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import AnythingClientConfiguration from ._operations import AnythingClientOperationsMixin diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/AnythingVersionTolerant/anythingversiontolerant/aio/_operations/_operations.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/AnythingVersionTolerant/anythingversiontolerant/aio/_operations/_operations.py index a8f7389fad7..d895e2acf61 100644 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/AnythingVersionTolerant/anythingversiontolerant/aio/_operations/_operations.py +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/AnythingVersionTolerant/anythingversiontolerant/aio/_operations/_operations.py @@ -9,6 +9,7 @@ from collections.abc import MutableMapping from typing import Any, Callable, Dict, Optional, TypeVar, cast +from azure.core import AsyncPipelineClient from azure.core.exceptions import ( ClientAuthenticationError, HttpResponseError, @@ -30,13 +31,14 @@ build_anything_put_object_request, build_anything_put_string_request, ) -from .._vendor import AnythingClientMixinABC +from ..._utils.utils import ClientMixinABC +from .._configuration import AnythingClientConfiguration T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, AsyncHttpResponse], T, Dict[str, Any]], Any]] -class AnythingClientOperationsMixin(AnythingClientMixinABC): +class AnythingClientOperationsMixin(ClientMixinABC[AsyncPipelineClient, AnythingClientConfiguration]): @distributed_trace_async async def get_object(self, **kwargs: Any) -> Any: diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/AnythingVersionTolerant/anythingversiontolerant/aio/_vendor.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/AnythingVersionTolerant/anythingversiontolerant/aio/_vendor.py deleted file mode 100644 index c99b54eef8d..00000000000 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/AnythingVersionTolerant/anythingversiontolerant/aio/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) AutoRest Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import AnythingClientConfiguration - -if TYPE_CHECKING: - from azure.core import AsyncPipelineClient - - from .._serialization import Deserializer, Serializer - - -class AnythingClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "AsyncPipelineClient" - _config: AnythingClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyArrayVersionTolerant/bodyarrayversiontolerant/_client.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyArrayVersionTolerant/bodyarrayversiontolerant/_client.py index 96818639733..bfb2156950a 100644 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyArrayVersionTolerant/bodyarrayversiontolerant/_client.py +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyArrayVersionTolerant/bodyarrayversiontolerant/_client.py @@ -15,7 +15,7 @@ from azure.core.rest import HttpRequest, HttpResponse from ._configuration import AutoRestSwaggerBATArrayServiceConfiguration -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer from .operations import ArrayOperations diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyArrayVersionTolerant/bodyarrayversiontolerant/_utils/__init__.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyArrayVersionTolerant/bodyarrayversiontolerant/_utils/__init__.py new file mode 100644 index 00000000000..0af9b28f660 --- /dev/null +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyArrayVersionTolerant/bodyarrayversiontolerant/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/SecurityKeySwaggerVersionTolerant/securitykeyswaggerversiontolerant/_serialization.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyArrayVersionTolerant/bodyarrayversiontolerant/_utils/serialization.py similarity index 100% rename from packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/SecurityKeySwaggerVersionTolerant/securitykeyswaggerversiontolerant/_serialization.py rename to packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyArrayVersionTolerant/bodyarrayversiontolerant/_utils/serialization.py diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyArrayVersionTolerant/bodyarrayversiontolerant/aio/_client.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyArrayVersionTolerant/bodyarrayversiontolerant/aio/_client.py index baf6099c8a1..bb2af681471 100644 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyArrayVersionTolerant/bodyarrayversiontolerant/aio/_client.py +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyArrayVersionTolerant/bodyarrayversiontolerant/aio/_client.py @@ -14,7 +14,7 @@ from azure.core.pipeline import policies from azure.core.rest import AsyncHttpResponse, HttpRequest -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import AutoRestSwaggerBATArrayServiceConfiguration from .operations import ArrayOperations diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyArrayVersionTolerant/bodyarrayversiontolerant/aio/operations/_operations.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyArrayVersionTolerant/bodyarrayversiontolerant/aio/operations/_operations.py index b8fb6b7a8dc..a93f9f5bb4a 100644 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyArrayVersionTolerant/bodyarrayversiontolerant/aio/operations/_operations.py +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyArrayVersionTolerant/bodyarrayversiontolerant/aio/operations/_operations.py @@ -25,7 +25,7 @@ from azure.core.tracing.decorator_async import distributed_trace_async from azure.core.utils import case_insensitive_dict -from ..._serialization import Deserializer, Serializer +from ..._utils.serialization import Deserializer, Serializer from ...operations._operations import ( build_array_get_array_empty_request, build_array_get_array_item_empty_request, diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyArrayVersionTolerant/bodyarrayversiontolerant/operations/_operations.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyArrayVersionTolerant/bodyarrayversiontolerant/operations/_operations.py index ba777c08e7f..2ac6a920c46 100644 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyArrayVersionTolerant/bodyarrayversiontolerant/operations/_operations.py +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyArrayVersionTolerant/bodyarrayversiontolerant/operations/_operations.py @@ -26,7 +26,7 @@ from azure.core.utils import case_insensitive_dict from .._configuration import AutoRestSwaggerBATArrayServiceConfiguration -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer JSON = MutableMapping[str, Any] T = TypeVar("T") diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyBinaryVersionTolerant/bodybinaryversiontolerant/_client.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyBinaryVersionTolerant/bodybinaryversiontolerant/_client.py index ebe6e3c74a5..5635808c034 100644 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyBinaryVersionTolerant/bodybinaryversiontolerant/_client.py +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyBinaryVersionTolerant/bodybinaryversiontolerant/_client.py @@ -15,7 +15,7 @@ from azure.core.rest import HttpRequest, HttpResponse from ._configuration import BinaryWithContentTypeApplicationJsonConfiguration -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer from .operations import DownloadOperations, UploadOperations diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyBinaryVersionTolerant/bodybinaryversiontolerant/_utils/__init__.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyBinaryVersionTolerant/bodybinaryversiontolerant/_utils/__init__.py new file mode 100644 index 00000000000..0af9b28f660 --- /dev/null +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyBinaryVersionTolerant/bodybinaryversiontolerant/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/UrlMultiCollectionFormatVersionTolerant/urlmulticollectionformatversiontolerant/_serialization.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyBinaryVersionTolerant/bodybinaryversiontolerant/_utils/serialization.py similarity index 100% rename from packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/UrlMultiCollectionFormatVersionTolerant/urlmulticollectionformatversiontolerant/_serialization.py rename to packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyBinaryVersionTolerant/bodybinaryversiontolerant/_utils/serialization.py diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyBinaryVersionTolerant/bodybinaryversiontolerant/aio/_client.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyBinaryVersionTolerant/bodybinaryversiontolerant/aio/_client.py index 58ce76bbea5..27b9c90e829 100644 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyBinaryVersionTolerant/bodybinaryversiontolerant/aio/_client.py +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyBinaryVersionTolerant/bodybinaryversiontolerant/aio/_client.py @@ -14,7 +14,7 @@ from azure.core.pipeline import policies from azure.core.rest import AsyncHttpResponse, HttpRequest -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import BinaryWithContentTypeApplicationJsonConfiguration from .operations import DownloadOperations, UploadOperations diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyBinaryVersionTolerant/bodybinaryversiontolerant/aio/operations/_operations.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyBinaryVersionTolerant/bodybinaryversiontolerant/aio/operations/_operations.py index d49a80c5270..2dc76a01d1c 100644 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyBinaryVersionTolerant/bodybinaryversiontolerant/aio/operations/_operations.py +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyBinaryVersionTolerant/bodybinaryversiontolerant/aio/operations/_operations.py @@ -24,7 +24,7 @@ from azure.core.tracing.decorator_async import distributed_trace_async from azure.core.utils import case_insensitive_dict -from ..._serialization import Deserializer, Serializer +from ..._utils.serialization import Deserializer, Serializer from ...operations._operations import ( build_download_error_stream_request, build_upload_binary_request, diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyBinaryVersionTolerant/bodybinaryversiontolerant/operations/_operations.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyBinaryVersionTolerant/bodybinaryversiontolerant/operations/_operations.py index cd07abdf02c..db6dc335021 100644 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyBinaryVersionTolerant/bodybinaryversiontolerant/operations/_operations.py +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyBinaryVersionTolerant/bodybinaryversiontolerant/operations/_operations.py @@ -25,7 +25,7 @@ from azure.core.utils import case_insensitive_dict from .._configuration import BinaryWithContentTypeApplicationJsonConfiguration -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyBooleanVersionTolerant/bodybooleanversiontolerant/_client.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyBooleanVersionTolerant/bodybooleanversiontolerant/_client.py index f0e5934b288..7b8d248e57a 100644 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyBooleanVersionTolerant/bodybooleanversiontolerant/_client.py +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyBooleanVersionTolerant/bodybooleanversiontolerant/_client.py @@ -15,7 +15,7 @@ from azure.core.rest import HttpRequest, HttpResponse from ._configuration import AutoRestBoolTestServiceConfiguration -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer from .operations import BoolOperations diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyBooleanVersionTolerant/bodybooleanversiontolerant/_utils/__init__.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyBooleanVersionTolerant/bodybooleanversiontolerant/_utils/__init__.py new file mode 100644 index 00000000000..0af9b28f660 --- /dev/null +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyBooleanVersionTolerant/bodybooleanversiontolerant/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/UrlVersionTolerant/urlversiontolerant/_serialization.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyBooleanVersionTolerant/bodybooleanversiontolerant/_utils/serialization.py similarity index 100% rename from packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/UrlVersionTolerant/urlversiontolerant/_serialization.py rename to packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyBooleanVersionTolerant/bodybooleanversiontolerant/_utils/serialization.py diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyBooleanVersionTolerant/bodybooleanversiontolerant/aio/_client.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyBooleanVersionTolerant/bodybooleanversiontolerant/aio/_client.py index 54424eec4b6..1ca13321be1 100644 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyBooleanVersionTolerant/bodybooleanversiontolerant/aio/_client.py +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyBooleanVersionTolerant/bodybooleanversiontolerant/aio/_client.py @@ -14,7 +14,7 @@ from azure.core.pipeline import policies from azure.core.rest import AsyncHttpResponse, HttpRequest -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import AutoRestBoolTestServiceConfiguration from .operations import BoolOperations diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyBooleanVersionTolerant/bodybooleanversiontolerant/aio/operations/_operations.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyBooleanVersionTolerant/bodybooleanversiontolerant/aio/operations/_operations.py index 262af500e26..57d4a904253 100644 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyBooleanVersionTolerant/bodybooleanversiontolerant/aio/operations/_operations.py +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyBooleanVersionTolerant/bodybooleanversiontolerant/aio/operations/_operations.py @@ -22,7 +22,7 @@ from azure.core.tracing.decorator_async import distributed_trace_async from azure.core.utils import case_insensitive_dict -from ..._serialization import Deserializer, Serializer +from ..._utils.serialization import Deserializer, Serializer from ...operations._operations import ( build_bool_get_false_request, build_bool_get_invalid_request, diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyBooleanVersionTolerant/bodybooleanversiontolerant/operations/_operations.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyBooleanVersionTolerant/bodybooleanversiontolerant/operations/_operations.py index 2753a18a48b..8fec5f671cc 100644 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyBooleanVersionTolerant/bodybooleanversiontolerant/operations/_operations.py +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyBooleanVersionTolerant/bodybooleanversiontolerant/operations/_operations.py @@ -23,7 +23,7 @@ from azure.core.utils import case_insensitive_dict from .._configuration import AutoRestBoolTestServiceConfiguration -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyByteVersionTolerant/bodybyteversiontolerant/_client.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyByteVersionTolerant/bodybyteversiontolerant/_client.py index 7a36e78f357..da1af3642c4 100644 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyByteVersionTolerant/bodybyteversiontolerant/_client.py +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyByteVersionTolerant/bodybyteversiontolerant/_client.py @@ -15,7 +15,7 @@ from azure.core.rest import HttpRequest, HttpResponse from ._configuration import AutoRestSwaggerBATByteServiceConfiguration -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer from .operations import ByteOperations diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyByteVersionTolerant/bodybyteversiontolerant/_utils/__init__.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyByteVersionTolerant/bodybyteversiontolerant/_utils/__init__.py new file mode 100644 index 00000000000..0af9b28f660 --- /dev/null +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyByteVersionTolerant/bodybyteversiontolerant/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ValidationVersionTolerant/validationversiontolerant/_serialization.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyByteVersionTolerant/bodybyteversiontolerant/_utils/serialization.py similarity index 100% rename from packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ValidationVersionTolerant/validationversiontolerant/_serialization.py rename to packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyByteVersionTolerant/bodybyteversiontolerant/_utils/serialization.py diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyByteVersionTolerant/bodybyteversiontolerant/aio/_client.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyByteVersionTolerant/bodybyteversiontolerant/aio/_client.py index 7fd12d06c3e..65d89a9e868 100644 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyByteVersionTolerant/bodybyteversiontolerant/aio/_client.py +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyByteVersionTolerant/bodybyteversiontolerant/aio/_client.py @@ -14,7 +14,7 @@ from azure.core.pipeline import policies from azure.core.rest import AsyncHttpResponse, HttpRequest -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import AutoRestSwaggerBATByteServiceConfiguration from .operations import ByteOperations diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyByteVersionTolerant/bodybyteversiontolerant/aio/operations/_operations.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyByteVersionTolerant/bodybyteversiontolerant/aio/operations/_operations.py index a58a8c3bbdd..495f9700fab 100644 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyByteVersionTolerant/bodybyteversiontolerant/aio/operations/_operations.py +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyByteVersionTolerant/bodybyteversiontolerant/aio/operations/_operations.py @@ -22,7 +22,7 @@ from azure.core.tracing.decorator_async import distributed_trace_async from azure.core.utils import case_insensitive_dict -from ..._serialization import Deserializer, Serializer +from ..._utils.serialization import Deserializer, Serializer from ...operations._operations import ( build_byte_get_empty_request, build_byte_get_invalid_request, diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyByteVersionTolerant/bodybyteversiontolerant/operations/_operations.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyByteVersionTolerant/bodybyteversiontolerant/operations/_operations.py index faee54c5136..e554754c316 100644 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyByteVersionTolerant/bodybyteversiontolerant/operations/_operations.py +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyByteVersionTolerant/bodybyteversiontolerant/operations/_operations.py @@ -23,7 +23,7 @@ from azure.core.utils import case_insensitive_dict from .._configuration import AutoRestSwaggerBATByteServiceConfiguration -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyComplexVersionTolerant/bodycomplexversiontolerant/_client.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyComplexVersionTolerant/bodycomplexversiontolerant/_client.py index 3a6593d6772..eb71839da91 100644 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyComplexVersionTolerant/bodycomplexversiontolerant/_client.py +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyComplexVersionTolerant/bodycomplexversiontolerant/_client.py @@ -15,7 +15,7 @@ from azure.core.rest import HttpRequest, HttpResponse from ._configuration import AutoRestComplexTestServiceConfiguration -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer from .operations import ( ArrayOperations, BasicOperations, diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyComplexVersionTolerant/bodycomplexversiontolerant/_utils/__init__.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyComplexVersionTolerant/bodycomplexversiontolerant/_utils/__init__.py new file mode 100644 index 00000000000..0af9b28f660 --- /dev/null +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyComplexVersionTolerant/bodycomplexversiontolerant/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/XmlVersionTolerant/xmlserviceversiontolerant/_serialization.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyComplexVersionTolerant/bodycomplexversiontolerant/_utils/serialization.py similarity index 100% rename from packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/XmlVersionTolerant/xmlserviceversiontolerant/_serialization.py rename to packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyComplexVersionTolerant/bodycomplexversiontolerant/_utils/serialization.py diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyComplexVersionTolerant/bodycomplexversiontolerant/aio/_client.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyComplexVersionTolerant/bodycomplexversiontolerant/aio/_client.py index bf384dcec37..f78792e0eef 100644 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyComplexVersionTolerant/bodycomplexversiontolerant/aio/_client.py +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyComplexVersionTolerant/bodycomplexversiontolerant/aio/_client.py @@ -14,7 +14,7 @@ from azure.core.pipeline import policies from azure.core.rest import AsyncHttpResponse, HttpRequest -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import AutoRestComplexTestServiceConfiguration from .operations import ( ArrayOperations, diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyComplexVersionTolerant/bodycomplexversiontolerant/aio/operations/_operations.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyComplexVersionTolerant/bodycomplexversiontolerant/aio/operations/_operations.py index 21e2705fb69..343ef32e96b 100644 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyComplexVersionTolerant/bodycomplexversiontolerant/aio/operations/_operations.py +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyComplexVersionTolerant/bodycomplexversiontolerant/aio/operations/_operations.py @@ -24,7 +24,7 @@ from azure.core.tracing.decorator_async import distributed_trace_async from azure.core.utils import case_insensitive_dict -from ..._serialization import Deserializer, Serializer +from ..._utils.serialization import Deserializer, Serializer from ...operations._operations import ( build_array_get_empty_request, build_array_get_not_provided_request, diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyComplexVersionTolerant/bodycomplexversiontolerant/operations/_operations.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyComplexVersionTolerant/bodycomplexversiontolerant/operations/_operations.py index ad28d485e3d..f26bef74bf0 100644 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyComplexVersionTolerant/bodycomplexversiontolerant/operations/_operations.py +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyComplexVersionTolerant/bodycomplexversiontolerant/operations/_operations.py @@ -25,7 +25,7 @@ from azure.core.utils import case_insensitive_dict from .._configuration import AutoRestComplexTestServiceConfiguration -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer JSON = MutableMapping[str, Any] T = TypeVar("T") diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyDateTimeRfc1123VersionTolerant/bodydatetimerfc1123versiontolerant/_client.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyDateTimeRfc1123VersionTolerant/bodydatetimerfc1123versiontolerant/_client.py index 85ea3316283..d4a5759f2c1 100644 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyDateTimeRfc1123VersionTolerant/bodydatetimerfc1123versiontolerant/_client.py +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyDateTimeRfc1123VersionTolerant/bodydatetimerfc1123versiontolerant/_client.py @@ -15,7 +15,7 @@ from azure.core.rest import HttpRequest, HttpResponse from ._configuration import AutoRestRFC1123DateTimeTestServiceConfiguration -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer from .operations import Datetimerfc1123Operations diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyDateTimeRfc1123VersionTolerant/bodydatetimerfc1123versiontolerant/_utils/__init__.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyDateTimeRfc1123VersionTolerant/bodydatetimerfc1123versiontolerant/_utils/__init__.py new file mode 100644 index 00000000000..0af9b28f660 --- /dev/null +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyDateTimeRfc1123VersionTolerant/bodydatetimerfc1123versiontolerant/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/XmsErrorResponseVersionTolerant/xmserrorresponseversiontolerant/_serialization.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyDateTimeRfc1123VersionTolerant/bodydatetimerfc1123versiontolerant/_utils/serialization.py similarity index 100% rename from packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/XmsErrorResponseVersionTolerant/xmserrorresponseversiontolerant/_serialization.py rename to packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyDateTimeRfc1123VersionTolerant/bodydatetimerfc1123versiontolerant/_utils/serialization.py diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyDateTimeRfc1123VersionTolerant/bodydatetimerfc1123versiontolerant/aio/_client.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyDateTimeRfc1123VersionTolerant/bodydatetimerfc1123versiontolerant/aio/_client.py index 57511423d49..1f1375c2f6b 100644 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyDateTimeRfc1123VersionTolerant/bodydatetimerfc1123versiontolerant/aio/_client.py +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyDateTimeRfc1123VersionTolerant/bodydatetimerfc1123versiontolerant/aio/_client.py @@ -14,7 +14,7 @@ from azure.core.pipeline import policies from azure.core.rest import AsyncHttpResponse, HttpRequest -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import AutoRestRFC1123DateTimeTestServiceConfiguration from .operations import Datetimerfc1123Operations diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyDateTimeRfc1123VersionTolerant/bodydatetimerfc1123versiontolerant/aio/operations/_operations.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyDateTimeRfc1123VersionTolerant/bodydatetimerfc1123versiontolerant/aio/operations/_operations.py index b00ffd45778..cd1cb40380b 100644 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyDateTimeRfc1123VersionTolerant/bodydatetimerfc1123versiontolerant/aio/operations/_operations.py +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyDateTimeRfc1123VersionTolerant/bodydatetimerfc1123versiontolerant/aio/operations/_operations.py @@ -23,7 +23,7 @@ from azure.core.tracing.decorator_async import distributed_trace_async from azure.core.utils import case_insensitive_dict -from ..._serialization import Deserializer, Serializer +from ..._utils.serialization import Deserializer, Serializer from ...operations._operations import ( build_datetimerfc1123_get_invalid_request, build_datetimerfc1123_get_null_request, diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyDateTimeRfc1123VersionTolerant/bodydatetimerfc1123versiontolerant/operations/_operations.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyDateTimeRfc1123VersionTolerant/bodydatetimerfc1123versiontolerant/operations/_operations.py index 24505c98496..87387bdfc21 100644 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyDateTimeRfc1123VersionTolerant/bodydatetimerfc1123versiontolerant/operations/_operations.py +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyDateTimeRfc1123VersionTolerant/bodydatetimerfc1123versiontolerant/operations/_operations.py @@ -24,7 +24,7 @@ from azure.core.utils import case_insensitive_dict from .._configuration import AutoRestRFC1123DateTimeTestServiceConfiguration -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyDateTimeVersionTolerant/bodydatetimeversiontolerant/_client.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyDateTimeVersionTolerant/bodydatetimeversiontolerant/_client.py index 22024dce353..ac89346984b 100644 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyDateTimeVersionTolerant/bodydatetimeversiontolerant/_client.py +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyDateTimeVersionTolerant/bodydatetimeversiontolerant/_client.py @@ -15,7 +15,7 @@ from azure.core.rest import HttpRequest, HttpResponse from ._configuration import AutoRestDateTimeTestServiceConfiguration -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer from .operations import DatetimeOperations diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyDateTimeVersionTolerant/bodydatetimeversiontolerant/_utils/__init__.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyDateTimeVersionTolerant/bodydatetimeversiontolerant/_utils/__init__.py new file mode 100644 index 00000000000..0af9b28f660 --- /dev/null +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyDateTimeVersionTolerant/bodydatetimeversiontolerant/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyDateTimeVersionTolerant/bodydatetimeversiontolerant/_utils/serialization.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyDateTimeVersionTolerant/bodydatetimeversiontolerant/_utils/serialization.py new file mode 100644 index 00000000000..f5187701d7b --- /dev/null +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyDateTimeVersionTolerant/bodydatetimeversiontolerant/_utils/serialization.py @@ -0,0 +1,2032 @@ +# pylint: disable=line-too-long,useless-suppression,too-many-lines +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +# pyright: reportUnnecessaryTypeIgnoreComment=false + +from base64 import b64decode, b64encode +import calendar +import datetime +import decimal +import email +from enum import Enum +import json +import logging +import re +import sys +import codecs +from typing import ( + Dict, + Any, + cast, + Optional, + Union, + AnyStr, + IO, + Mapping, + Callable, + MutableMapping, + List, +) + +try: + from urllib import quote # type: ignore +except ImportError: + from urllib.parse import quote +import xml.etree.ElementTree as ET + +import isodate # type: ignore +from typing_extensions import Self + +from azure.core.exceptions import DeserializationError, SerializationError +from azure.core.serialization import NULL as CoreNull + +_BOM = codecs.BOM_UTF8.decode(encoding="utf-8") + +JSON = MutableMapping[str, Any] + + +class RawDeserializer: + + # Accept "text" because we're open minded people... + JSON_REGEXP = re.compile(r"^(application|text)/([a-z+.]+\+)?json$") + + # Name used in context + CONTEXT_NAME = "deserialized_data" + + @classmethod + def deserialize_from_text(cls, data: Optional[Union[AnyStr, IO]], content_type: Optional[str] = None) -> Any: + """Decode data according to content-type. + + Accept a stream of data as well, but will be load at once in memory for now. + + If no content-type, will return the string version (not bytes, not stream) + + :param data: Input, could be bytes or stream (will be decoded with UTF8) or text + :type data: str or bytes or IO + :param str content_type: The content type. + :return: The deserialized data. + :rtype: object + """ + if hasattr(data, "read"): + # Assume a stream + data = cast(IO, data).read() + + if isinstance(data, bytes): + data_as_str = data.decode(encoding="utf-8-sig") + else: + # Explain to mypy the correct type. + data_as_str = cast(str, data) + + # Remove Byte Order Mark if present in string + data_as_str = data_as_str.lstrip(_BOM) + + if content_type is None: + return data + + if cls.JSON_REGEXP.match(content_type): + try: + return json.loads(data_as_str) + except ValueError as err: + raise DeserializationError("JSON is invalid: {}".format(err), err) from err + elif "xml" in (content_type or []): + try: + + try: + if isinstance(data, unicode): # type: ignore + # If I'm Python 2.7 and unicode XML will scream if I try a "fromstring" on unicode string + data_as_str = data_as_str.encode(encoding="utf-8") # type: ignore + except NameError: + pass + + return ET.fromstring(data_as_str) # nosec + except ET.ParseError as err: + # It might be because the server has an issue, and returned JSON with + # content-type XML.... + # So let's try a JSON load, and if it's still broken + # let's flow the initial exception + def _json_attemp(data): + try: + return True, json.loads(data) + except ValueError: + return False, None # Don't care about this one + + success, json_result = _json_attemp(data) + if success: + return json_result + # If i'm here, it's not JSON, it's not XML, let's scream + # and raise the last context in this block (the XML exception) + # The function hack is because Py2.7 messes up with exception + # context otherwise. + _LOGGER.critical("Wasn't XML not JSON, failing") + raise DeserializationError("XML is invalid") from err + elif content_type.startswith("text/"): + return data_as_str + raise DeserializationError("Cannot deserialize content-type: {}".format(content_type)) + + @classmethod + def deserialize_from_http_generics(cls, body_bytes: Optional[Union[AnyStr, IO]], headers: Mapping) -> Any: + """Deserialize from HTTP response. + + Use bytes and headers to NOT use any requests/aiohttp or whatever + specific implementation. + Headers will tested for "content-type" + + :param bytes body_bytes: The body of the response. + :param dict headers: The headers of the response. + :returns: The deserialized data. + :rtype: object + """ + # Try to use content-type from headers if available + content_type = None + if "content-type" in headers: + content_type = headers["content-type"].split(";")[0].strip().lower() + # Ouch, this server did not declare what it sent... + # Let's guess it's JSON... + # Also, since Autorest was considering that an empty body was a valid JSON, + # need that test as well.... + else: + content_type = "application/json" + + if body_bytes: + return cls.deserialize_from_text(body_bytes, content_type) + return None + + +_LOGGER = logging.getLogger(__name__) + +try: + _long_type = long # type: ignore +except NameError: + _long_type = int + +TZ_UTC = datetime.timezone.utc + +_FLATTEN = re.compile(r"(? None: + self.additional_properties: Optional[Dict[str, Any]] = {} + for k in kwargs: # pylint: disable=consider-using-dict-items + if k not in self._attribute_map: + _LOGGER.warning("%s is not a known attribute of class %s and will be ignored", k, self.__class__) + elif k in self._validation and self._validation[k].get("readonly", False): + _LOGGER.warning("Readonly attribute %s will be ignored in class %s", k, self.__class__) + else: + setattr(self, k, kwargs[k]) + + def __eq__(self, other: Any) -> bool: + """Compare objects by comparing all attributes. + + :param object other: The object to compare + :returns: True if objects are equal + :rtype: bool + """ + if isinstance(other, self.__class__): + return self.__dict__ == other.__dict__ + return False + + def __ne__(self, other: Any) -> bool: + """Compare objects by comparing all attributes. + + :param object other: The object to compare + :returns: True if objects are not equal + :rtype: bool + """ + return not self.__eq__(other) + + def __str__(self) -> str: + return str(self.__dict__) + + @classmethod + def enable_additional_properties_sending(cls) -> None: + cls._attribute_map["additional_properties"] = {"key": "", "type": "{object}"} + + @classmethod + def is_xml_model(cls) -> bool: + try: + cls._xml_map # type: ignore + except AttributeError: + return False + return True + + @classmethod + def _create_xml_node(cls): + """Create XML node. + + :returns: The XML node + :rtype: xml.etree.ElementTree.Element + """ + try: + xml_map = cls._xml_map # type: ignore + except AttributeError: + xml_map = {} + + return _create_xml_node(xml_map.get("name", cls.__name__), xml_map.get("prefix", None), xml_map.get("ns", None)) + + def serialize(self, keep_readonly: bool = False, **kwargs: Any) -> JSON: + """Return the JSON that would be sent to server from this model. + + This is an alias to `as_dict(full_restapi_key_transformer, keep_readonly=False)`. + + If you want XML serialization, you can pass the kwargs is_xml=True. + + :param bool keep_readonly: If you want to serialize the readonly attributes + :returns: A dict JSON compatible object + :rtype: dict + """ + serializer = Serializer(self._infer_class_models()) + return serializer._serialize( # type: ignore # pylint: disable=protected-access + self, keep_readonly=keep_readonly, **kwargs + ) + + def as_dict( + self, + keep_readonly: bool = True, + key_transformer: Callable[[str, Dict[str, Any], Any], Any] = attribute_transformer, + **kwargs: Any + ) -> JSON: + """Return a dict that can be serialized using json.dump. + + Advanced usage might optionally use a callback as parameter: + + .. code::python + + def my_key_transformer(key, attr_desc, value): + return key + + Key is the attribute name used in Python. Attr_desc + is a dict of metadata. Currently contains 'type' with the + msrest type and 'key' with the RestAPI encoded key. + Value is the current value in this object. + + The string returned will be used to serialize the key. + If the return type is a list, this is considered hierarchical + result dict. + + See the three examples in this file: + + - attribute_transformer + - full_restapi_key_transformer + - last_restapi_key_transformer + + If you want XML serialization, you can pass the kwargs is_xml=True. + + :param bool keep_readonly: If you want to serialize the readonly attributes + :param function key_transformer: A key transformer function. + :returns: A dict JSON compatible object + :rtype: dict + """ + serializer = Serializer(self._infer_class_models()) + return serializer._serialize( # type: ignore # pylint: disable=protected-access + self, key_transformer=key_transformer, keep_readonly=keep_readonly, **kwargs + ) + + @classmethod + def _infer_class_models(cls): + try: + str_models = cls.__module__.rsplit(".", 1)[0] + models = sys.modules[str_models] + client_models = {k: v for k, v in models.__dict__.items() if isinstance(v, type)} + if cls.__name__ not in client_models: + raise ValueError("Not Autorest generated code") + except Exception: # pylint: disable=broad-exception-caught + # Assume it's not Autorest generated (tests?). Add ourselves as dependencies. + client_models = {cls.__name__: cls} + return client_models + + @classmethod + def deserialize(cls, data: Any, content_type: Optional[str] = None) -> Self: + """Parse a str using the RestAPI syntax and return a model. + + :param str data: A str using RestAPI structure. JSON by default. + :param str content_type: JSON by default, set application/xml if XML. + :returns: An instance of this model + :raises DeserializationError: if something went wrong + :rtype: Self + """ + deserializer = Deserializer(cls._infer_class_models()) + return deserializer(cls.__name__, data, content_type=content_type) # type: ignore + + @classmethod + def from_dict( + cls, + data: Any, + key_extractors: Optional[Callable[[str, Dict[str, Any], Any], Any]] = None, + content_type: Optional[str] = None, + ) -> Self: + """Parse a dict using given key extractor return a model. + + By default consider key + extractors (rest_key_case_insensitive_extractor, attribute_key_case_insensitive_extractor + and last_rest_key_case_insensitive_extractor) + + :param dict data: A dict using RestAPI structure + :param function key_extractors: A key extractor function. + :param str content_type: JSON by default, set application/xml if XML. + :returns: An instance of this model + :raises DeserializationError: if something went wrong + :rtype: Self + """ + deserializer = Deserializer(cls._infer_class_models()) + deserializer.key_extractors = ( # type: ignore + [ # type: ignore + attribute_key_case_insensitive_extractor, + rest_key_case_insensitive_extractor, + last_rest_key_case_insensitive_extractor, + ] + if key_extractors is None + else key_extractors + ) + return deserializer(cls.__name__, data, content_type=content_type) # type: ignore + + @classmethod + def _flatten_subtype(cls, key, objects): + if "_subtype_map" not in cls.__dict__: + return {} + result = dict(cls._subtype_map[key]) + for valuetype in cls._subtype_map[key].values(): + result.update(objects[valuetype]._flatten_subtype(key, objects)) # pylint: disable=protected-access + return result + + @classmethod + def _classify(cls, response, objects): + """Check the class _subtype_map for any child classes. + We want to ignore any inherited _subtype_maps. + + :param dict response: The initial data + :param dict objects: The class objects + :returns: The class to be used + :rtype: class + """ + for subtype_key in cls.__dict__.get("_subtype_map", {}).keys(): + subtype_value = None + + if not isinstance(response, ET.Element): + rest_api_response_key = cls._get_rest_key_parts(subtype_key)[-1] + subtype_value = response.get(rest_api_response_key, None) or response.get(subtype_key, None) + else: + subtype_value = xml_key_extractor(subtype_key, cls._attribute_map[subtype_key], response) + if subtype_value: + # Try to match base class. Can be class name only + # (bug to fix in Autorest to support x-ms-discriminator-name) + if cls.__name__ == subtype_value: + return cls + flatten_mapping_type = cls._flatten_subtype(subtype_key, objects) + try: + return objects[flatten_mapping_type[subtype_value]] # type: ignore + except KeyError: + _LOGGER.warning( + "Subtype value %s has no mapping, use base class %s.", + subtype_value, + cls.__name__, + ) + break + else: + _LOGGER.warning("Discriminator %s is absent or null, use base class %s.", subtype_key, cls.__name__) + break + return cls + + @classmethod + def _get_rest_key_parts(cls, attr_key): + """Get the RestAPI key of this attr, split it and decode part + :param str attr_key: Attribute key must be in attribute_map. + :returns: A list of RestAPI part + :rtype: list + """ + rest_split_key = _FLATTEN.split(cls._attribute_map[attr_key]["key"]) + return [_decode_attribute_map_key(key_part) for key_part in rest_split_key] + + +def _decode_attribute_map_key(key): + """This decode a key in an _attribute_map to the actual key we want to look at + inside the received data. + + :param str key: A key string from the generated code + :returns: The decoded key + :rtype: str + """ + return key.replace("\\.", ".") + + +class Serializer: # pylint: disable=too-many-public-methods + """Request object model serializer.""" + + basic_types = {str: "str", int: "int", bool: "bool", float: "float"} + + _xml_basic_types_serializers = {"bool": lambda x: str(x).lower()} + days = {0: "Mon", 1: "Tue", 2: "Wed", 3: "Thu", 4: "Fri", 5: "Sat", 6: "Sun"} + months = { + 1: "Jan", + 2: "Feb", + 3: "Mar", + 4: "Apr", + 5: "May", + 6: "Jun", + 7: "Jul", + 8: "Aug", + 9: "Sep", + 10: "Oct", + 11: "Nov", + 12: "Dec", + } + validation = { + "min_length": lambda x, y: len(x) < y, + "max_length": lambda x, y: len(x) > y, + "minimum": lambda x, y: x < y, + "maximum": lambda x, y: x > y, + "minimum_ex": lambda x, y: x <= y, + "maximum_ex": lambda x, y: x >= y, + "min_items": lambda x, y: len(x) < y, + "max_items": lambda x, y: len(x) > y, + "pattern": lambda x, y: not re.match(y, x, re.UNICODE), + "unique": lambda x, y: len(x) != len(set(x)), + "multiple": lambda x, y: x % y != 0, + } + + def __init__(self, classes: Optional[Mapping[str, type]] = None) -> None: + self.serialize_type = { + "iso-8601": Serializer.serialize_iso, + "rfc-1123": Serializer.serialize_rfc, + "unix-time": Serializer.serialize_unix, + "duration": Serializer.serialize_duration, + "date": Serializer.serialize_date, + "time": Serializer.serialize_time, + "decimal": Serializer.serialize_decimal, + "long": Serializer.serialize_long, + "bytearray": Serializer.serialize_bytearray, + "base64": Serializer.serialize_base64, + "object": self.serialize_object, + "[]": self.serialize_iter, + "{}": self.serialize_dict, + } + self.dependencies: Dict[str, type] = dict(classes) if classes else {} + self.key_transformer = full_restapi_key_transformer + self.client_side_validation = True + + def _serialize( # pylint: disable=too-many-nested-blocks, too-many-branches, too-many-statements, too-many-locals + self, target_obj, data_type=None, **kwargs + ): + """Serialize data into a string according to type. + + :param object target_obj: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str, dict + :raises SerializationError: if serialization fails. + :returns: The serialized data. + """ + key_transformer = kwargs.get("key_transformer", self.key_transformer) + keep_readonly = kwargs.get("keep_readonly", False) + if target_obj is None: + return None + + attr_name = None + class_name = target_obj.__class__.__name__ + + if data_type: + return self.serialize_data(target_obj, data_type, **kwargs) + + if not hasattr(target_obj, "_attribute_map"): + data_type = type(target_obj).__name__ + if data_type in self.basic_types.values(): + return self.serialize_data(target_obj, data_type, **kwargs) + + # Force "is_xml" kwargs if we detect a XML model + try: + is_xml_model_serialization = kwargs["is_xml"] + except KeyError: + is_xml_model_serialization = kwargs.setdefault("is_xml", target_obj.is_xml_model()) + + serialized = {} + if is_xml_model_serialization: + serialized = target_obj._create_xml_node() # pylint: disable=protected-access + try: + attributes = target_obj._attribute_map # pylint: disable=protected-access + for attr, attr_desc in attributes.items(): + attr_name = attr + if not keep_readonly and target_obj._validation.get( # pylint: disable=protected-access + attr_name, {} + ).get("readonly", False): + continue + + if attr_name == "additional_properties" and attr_desc["key"] == "": + if target_obj.additional_properties is not None: + serialized.update(target_obj.additional_properties) + continue + try: + + orig_attr = getattr(target_obj, attr) + if is_xml_model_serialization: + pass # Don't provide "transformer" for XML for now. Keep "orig_attr" + else: # JSON + keys, orig_attr = key_transformer(attr, attr_desc.copy(), orig_attr) + keys = keys if isinstance(keys, list) else [keys] + + kwargs["serialization_ctxt"] = attr_desc + new_attr = self.serialize_data(orig_attr, attr_desc["type"], **kwargs) + + if is_xml_model_serialization: + xml_desc = attr_desc.get("xml", {}) + xml_name = xml_desc.get("name", attr_desc["key"]) + xml_prefix = xml_desc.get("prefix", None) + xml_ns = xml_desc.get("ns", None) + if xml_desc.get("attr", False): + if xml_ns: + ET.register_namespace(xml_prefix, xml_ns) + xml_name = "{{{}}}{}".format(xml_ns, xml_name) + serialized.set(xml_name, new_attr) # type: ignore + continue + if xml_desc.get("text", False): + serialized.text = new_attr # type: ignore + continue + if isinstance(new_attr, list): + serialized.extend(new_attr) # type: ignore + elif isinstance(new_attr, ET.Element): + # If the down XML has no XML/Name, + # we MUST replace the tag with the local tag. But keeping the namespaces. + if "name" not in getattr(orig_attr, "_xml_map", {}): + splitted_tag = new_attr.tag.split("}") + if len(splitted_tag) == 2: # Namespace + new_attr.tag = "}".join([splitted_tag[0], xml_name]) + else: + new_attr.tag = xml_name + serialized.append(new_attr) # type: ignore + else: # That's a basic type + # Integrate namespace if necessary + local_node = _create_xml_node(xml_name, xml_prefix, xml_ns) + local_node.text = str(new_attr) + serialized.append(local_node) # type: ignore + else: # JSON + for k in reversed(keys): # type: ignore + new_attr = {k: new_attr} + + _new_attr = new_attr + _serialized = serialized + for k in keys: # type: ignore + if k not in _serialized: + _serialized.update(_new_attr) # type: ignore + _new_attr = _new_attr[k] # type: ignore + _serialized = _serialized[k] + except ValueError as err: + if isinstance(err, SerializationError): + raise + + except (AttributeError, KeyError, TypeError) as err: + msg = "Attribute {} in object {} cannot be serialized.\n{}".format(attr_name, class_name, str(target_obj)) + raise SerializationError(msg) from err + return serialized + + def body(self, data, data_type, **kwargs): + """Serialize data intended for a request body. + + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: dict + :raises SerializationError: if serialization fails. + :raises ValueError: if data is None + :returns: The serialized request body + """ + + # Just in case this is a dict + internal_data_type_str = data_type.strip("[]{}") + internal_data_type = self.dependencies.get(internal_data_type_str, None) + try: + is_xml_model_serialization = kwargs["is_xml"] + except KeyError: + if internal_data_type and issubclass(internal_data_type, Model): + is_xml_model_serialization = kwargs.setdefault("is_xml", internal_data_type.is_xml_model()) + else: + is_xml_model_serialization = False + if internal_data_type and not isinstance(internal_data_type, Enum): + try: + deserializer = Deserializer(self.dependencies) + # Since it's on serialization, it's almost sure that format is not JSON REST + # We're not able to deal with additional properties for now. + deserializer.additional_properties_detection = False + if is_xml_model_serialization: + deserializer.key_extractors = [ # type: ignore + attribute_key_case_insensitive_extractor, + ] + else: + deserializer.key_extractors = [ + rest_key_case_insensitive_extractor, + attribute_key_case_insensitive_extractor, + last_rest_key_case_insensitive_extractor, + ] + data = deserializer._deserialize(data_type, data) # pylint: disable=protected-access + except DeserializationError as err: + raise SerializationError("Unable to build a model: " + str(err)) from err + + return self._serialize(data, data_type, **kwargs) + + def url(self, name, data, data_type, **kwargs): + """Serialize data intended for a URL path. + + :param str name: The name of the URL path parameter. + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str + :returns: The serialized URL path + :raises TypeError: if serialization fails. + :raises ValueError: if data is None + """ + try: + output = self.serialize_data(data, data_type, **kwargs) + if data_type == "bool": + output = json.dumps(output) + + if kwargs.get("skip_quote") is True: + output = str(output) + output = output.replace("{", quote("{")).replace("}", quote("}")) + else: + output = quote(str(output), safe="") + except SerializationError as exc: + raise TypeError("{} must be type {}.".format(name, data_type)) from exc + return output + + def query(self, name, data, data_type, **kwargs): + """Serialize data intended for a URL query. + + :param str name: The name of the query parameter. + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str, list + :raises TypeError: if serialization fails. + :raises ValueError: if data is None + :returns: The serialized query parameter + """ + try: + # Treat the list aside, since we don't want to encode the div separator + if data_type.startswith("["): + internal_data_type = data_type[1:-1] + do_quote = not kwargs.get("skip_quote", False) + return self.serialize_iter(data, internal_data_type, do_quote=do_quote, **kwargs) + + # Not a list, regular serialization + output = self.serialize_data(data, data_type, **kwargs) + if data_type == "bool": + output = json.dumps(output) + if kwargs.get("skip_quote") is True: + output = str(output) + else: + output = quote(str(output), safe="") + except SerializationError as exc: + raise TypeError("{} must be type {}.".format(name, data_type)) from exc + return str(output) + + def header(self, name, data, data_type, **kwargs): + """Serialize data intended for a request header. + + :param str name: The name of the header. + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str + :raises TypeError: if serialization fails. + :raises ValueError: if data is None + :returns: The serialized header + """ + try: + if data_type in ["[str]"]: + data = ["" if d is None else d for d in data] + + output = self.serialize_data(data, data_type, **kwargs) + if data_type == "bool": + output = json.dumps(output) + except SerializationError as exc: + raise TypeError("{} must be type {}.".format(name, data_type)) from exc + return str(output) + + def serialize_data(self, data, data_type, **kwargs): + """Serialize generic data according to supplied data type. + + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :raises AttributeError: if required data is None. + :raises ValueError: if data is None + :raises SerializationError: if serialization fails. + :returns: The serialized data. + :rtype: str, int, float, bool, dict, list + """ + if data is None: + raise ValueError("No value for given attribute") + + try: + if data is CoreNull: + return None + if data_type in self.basic_types.values(): + return self.serialize_basic(data, data_type, **kwargs) + + if data_type in self.serialize_type: + return self.serialize_type[data_type](data, **kwargs) + + # If dependencies is empty, try with current data class + # It has to be a subclass of Enum anyway + enum_type = self.dependencies.get(data_type, data.__class__) + if issubclass(enum_type, Enum): + return Serializer.serialize_enum(data, enum_obj=enum_type) + + iter_type = data_type[0] + data_type[-1] + if iter_type in self.serialize_type: + return self.serialize_type[iter_type](data, data_type[1:-1], **kwargs) + + except (ValueError, TypeError) as err: + msg = "Unable to serialize value: {!r} as type: {!r}." + raise SerializationError(msg.format(data, data_type)) from err + return self._serialize(data, **kwargs) + + @classmethod + def _get_custom_serializers(cls, data_type, **kwargs): # pylint: disable=inconsistent-return-statements + custom_serializer = kwargs.get("basic_types_serializers", {}).get(data_type) + if custom_serializer: + return custom_serializer + if kwargs.get("is_xml", False): + return cls._xml_basic_types_serializers.get(data_type) + + @classmethod + def serialize_basic(cls, data, data_type, **kwargs): + """Serialize basic builting data type. + Serializes objects to str, int, float or bool. + + Possible kwargs: + - basic_types_serializers dict[str, callable] : If set, use the callable as serializer + - is_xml bool : If set, use xml_basic_types_serializers + + :param obj data: Object to be serialized. + :param str data_type: Type of object in the iterable. + :rtype: str, int, float, bool + :return: serialized object + """ + custom_serializer = cls._get_custom_serializers(data_type, **kwargs) + if custom_serializer: + return custom_serializer(data) + if data_type == "str": + return cls.serialize_unicode(data) + return eval(data_type)(data) # nosec # pylint: disable=eval-used + + @classmethod + def serialize_unicode(cls, data): + """Special handling for serializing unicode strings in Py2. + Encode to UTF-8 if unicode, otherwise handle as a str. + + :param str data: Object to be serialized. + :rtype: str + :return: serialized object + """ + try: # If I received an enum, return its value + return data.value + except AttributeError: + pass + + try: + if isinstance(data, unicode): # type: ignore + # Don't change it, JSON and XML ElementTree are totally able + # to serialize correctly u'' strings + return data + except NameError: + return str(data) + return str(data) + + def serialize_iter(self, data, iter_type, div=None, **kwargs): + """Serialize iterable. + + Supported kwargs: + - serialization_ctxt dict : The current entry of _attribute_map, or same format. + serialization_ctxt['type'] should be same as data_type. + - is_xml bool : If set, serialize as XML + + :param list data: Object to be serialized. + :param str iter_type: Type of object in the iterable. + :param str div: If set, this str will be used to combine the elements + in the iterable into a combined string. Default is 'None'. + Defaults to False. + :rtype: list, str + :return: serialized iterable + """ + if isinstance(data, str): + raise SerializationError("Refuse str type as a valid iter type.") + + serialization_ctxt = kwargs.get("serialization_ctxt", {}) + is_xml = kwargs.get("is_xml", False) + + serialized = [] + for d in data: + try: + serialized.append(self.serialize_data(d, iter_type, **kwargs)) + except ValueError as err: + if isinstance(err, SerializationError): + raise + serialized.append(None) + + if kwargs.get("do_quote", False): + serialized = ["" if s is None else quote(str(s), safe="") for s in serialized] + + if div: + serialized = ["" if s is None else str(s) for s in serialized] + serialized = div.join(serialized) + + if "xml" in serialization_ctxt or is_xml: + # XML serialization is more complicated + xml_desc = serialization_ctxt.get("xml", {}) + xml_name = xml_desc.get("name") + if not xml_name: + xml_name = serialization_ctxt["key"] + + # Create a wrap node if necessary (use the fact that Element and list have "append") + is_wrapped = xml_desc.get("wrapped", False) + node_name = xml_desc.get("itemsName", xml_name) + if is_wrapped: + final_result = _create_xml_node(xml_name, xml_desc.get("prefix", None), xml_desc.get("ns", None)) + else: + final_result = [] + # All list elements to "local_node" + for el in serialized: + if isinstance(el, ET.Element): + el_node = el + else: + el_node = _create_xml_node(node_name, xml_desc.get("prefix", None), xml_desc.get("ns", None)) + if el is not None: # Otherwise it writes "None" :-p + el_node.text = str(el) + final_result.append(el_node) + return final_result + return serialized + + def serialize_dict(self, attr, dict_type, **kwargs): + """Serialize a dictionary of objects. + + :param dict attr: Object to be serialized. + :param str dict_type: Type of object in the dictionary. + :rtype: dict + :return: serialized dictionary + """ + serialization_ctxt = kwargs.get("serialization_ctxt", {}) + serialized = {} + for key, value in attr.items(): + try: + serialized[self.serialize_unicode(key)] = self.serialize_data(value, dict_type, **kwargs) + except ValueError as err: + if isinstance(err, SerializationError): + raise + serialized[self.serialize_unicode(key)] = None + + if "xml" in serialization_ctxt: + # XML serialization is more complicated + xml_desc = serialization_ctxt["xml"] + xml_name = xml_desc["name"] + + final_result = _create_xml_node(xml_name, xml_desc.get("prefix", None), xml_desc.get("ns", None)) + for key, value in serialized.items(): + ET.SubElement(final_result, key).text = value + return final_result + + return serialized + + def serialize_object(self, attr, **kwargs): # pylint: disable=too-many-return-statements + """Serialize a generic object. + This will be handled as a dictionary. If object passed in is not + a basic type (str, int, float, dict, list) it will simply be + cast to str. + + :param dict attr: Object to be serialized. + :rtype: dict or str + :return: serialized object + """ + if attr is None: + return None + if isinstance(attr, ET.Element): + return attr + obj_type = type(attr) + if obj_type in self.basic_types: + return self.serialize_basic(attr, self.basic_types[obj_type], **kwargs) + if obj_type is _long_type: + return self.serialize_long(attr) + if obj_type is str: + return self.serialize_unicode(attr) + if obj_type is datetime.datetime: + return self.serialize_iso(attr) + if obj_type is datetime.date: + return self.serialize_date(attr) + if obj_type is datetime.time: + return self.serialize_time(attr) + if obj_type is datetime.timedelta: + return self.serialize_duration(attr) + if obj_type is decimal.Decimal: + return self.serialize_decimal(attr) + + # If it's a model or I know this dependency, serialize as a Model + if obj_type in self.dependencies.values() or isinstance(attr, Model): + return self._serialize(attr) + + if obj_type == dict: + serialized = {} + for key, value in attr.items(): + try: + serialized[self.serialize_unicode(key)] = self.serialize_object(value, **kwargs) + except ValueError: + serialized[self.serialize_unicode(key)] = None + return serialized + + if obj_type == list: + serialized = [] + for obj in attr: + try: + serialized.append(self.serialize_object(obj, **kwargs)) + except ValueError: + pass + return serialized + return str(attr) + + @staticmethod + def serialize_enum(attr, enum_obj=None): + try: + result = attr.value + except AttributeError: + result = attr + try: + enum_obj(result) # type: ignore + return result + except ValueError as exc: + for enum_value in enum_obj: # type: ignore + if enum_value.value.lower() == str(attr).lower(): + return enum_value.value + error = "{!r} is not valid value for enum {!r}" + raise SerializationError(error.format(attr, enum_obj)) from exc + + @staticmethod + def serialize_bytearray(attr, **kwargs): # pylint: disable=unused-argument + """Serialize bytearray into base-64 string. + + :param str attr: Object to be serialized. + :rtype: str + :return: serialized base64 + """ + return b64encode(attr).decode() + + @staticmethod + def serialize_base64(attr, **kwargs): # pylint: disable=unused-argument + """Serialize str into base-64 string. + + :param str attr: Object to be serialized. + :rtype: str + :return: serialized base64 + """ + encoded = b64encode(attr).decode("ascii") + return encoded.strip("=").replace("+", "-").replace("/", "_") + + @staticmethod + def serialize_decimal(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Decimal object to float. + + :param decimal attr: Object to be serialized. + :rtype: float + :return: serialized decimal + """ + return float(attr) + + @staticmethod + def serialize_long(attr, **kwargs): # pylint: disable=unused-argument + """Serialize long (Py2) or int (Py3). + + :param int attr: Object to be serialized. + :rtype: int/long + :return: serialized long + """ + return _long_type(attr) + + @staticmethod + def serialize_date(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Date object into ISO-8601 formatted string. + + :param Date attr: Object to be serialized. + :rtype: str + :return: serialized date + """ + if isinstance(attr, str): + attr = isodate.parse_date(attr) + t = "{:04}-{:02}-{:02}".format(attr.year, attr.month, attr.day) + return t + + @staticmethod + def serialize_time(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Time object into ISO-8601 formatted string. + + :param datetime.time attr: Object to be serialized. + :rtype: str + :return: serialized time + """ + if isinstance(attr, str): + attr = isodate.parse_time(attr) + t = "{:02}:{:02}:{:02}".format(attr.hour, attr.minute, attr.second) + if attr.microsecond: + t += ".{:02}".format(attr.microsecond) + return t + + @staticmethod + def serialize_duration(attr, **kwargs): # pylint: disable=unused-argument + """Serialize TimeDelta object into ISO-8601 formatted string. + + :param TimeDelta attr: Object to be serialized. + :rtype: str + :return: serialized duration + """ + if isinstance(attr, str): + attr = isodate.parse_duration(attr) + return isodate.duration_isoformat(attr) + + @staticmethod + def serialize_rfc(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Datetime object into RFC-1123 formatted string. + + :param Datetime attr: Object to be serialized. + :rtype: str + :raises TypeError: if format invalid. + :return: serialized rfc + """ + try: + if not attr.tzinfo: + _LOGGER.warning("Datetime with no tzinfo will be considered UTC.") + utc = attr.utctimetuple() + except AttributeError as exc: + raise TypeError("RFC1123 object must be valid Datetime object.") from exc + + return "{}, {:02} {} {:04} {:02}:{:02}:{:02} GMT".format( + Serializer.days[utc.tm_wday], + utc.tm_mday, + Serializer.months[utc.tm_mon], + utc.tm_year, + utc.tm_hour, + utc.tm_min, + utc.tm_sec, + ) + + @staticmethod + def serialize_iso(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Datetime object into ISO-8601 formatted string. + + :param Datetime attr: Object to be serialized. + :rtype: str + :raises SerializationError: if format invalid. + :return: serialized iso + """ + if isinstance(attr, str): + attr = isodate.parse_datetime(attr) + try: + if not attr.tzinfo: + _LOGGER.warning("Datetime with no tzinfo will be considered UTC.") + utc = attr.utctimetuple() + if utc.tm_year > 9999 or utc.tm_year < 1: + raise OverflowError("Hit max or min date") + + microseconds = str(attr.microsecond).rjust(6, "0").rstrip("0").ljust(3, "0") + if microseconds: + microseconds = "." + microseconds + date = "{:04}-{:02}-{:02}T{:02}:{:02}:{:02}".format( + utc.tm_year, utc.tm_mon, utc.tm_mday, utc.tm_hour, utc.tm_min, utc.tm_sec + ) + return date + microseconds + "Z" + except (ValueError, OverflowError) as err: + msg = "Unable to serialize datetime object." + raise SerializationError(msg) from err + except AttributeError as err: + msg = "ISO-8601 object must be valid Datetime object." + raise TypeError(msg) from err + + @staticmethod + def serialize_unix(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Datetime object into IntTime format. + This is represented as seconds. + + :param Datetime attr: Object to be serialized. + :rtype: int + :raises SerializationError: if format invalid + :return: serialied unix + """ + if isinstance(attr, int): + return attr + try: + if not attr.tzinfo: + _LOGGER.warning("Datetime with no tzinfo will be considered UTC.") + return int(calendar.timegm(attr.utctimetuple())) + except AttributeError as exc: + raise TypeError("Unix time object must be valid Datetime object.") from exc + + +def rest_key_extractor(attr, attr_desc, data): # pylint: disable=unused-argument + key = attr_desc["key"] + working_data = data + + while "." in key: + # Need the cast, as for some reasons "split" is typed as list[str | Any] + dict_keys = cast(List[str], _FLATTEN.split(key)) + if len(dict_keys) == 1: + key = _decode_attribute_map_key(dict_keys[0]) + break + working_key = _decode_attribute_map_key(dict_keys[0]) + working_data = working_data.get(working_key, data) + if working_data is None: + # If at any point while following flatten JSON path see None, it means + # that all properties under are None as well + return None + key = ".".join(dict_keys[1:]) + + return working_data.get(key) + + +def rest_key_case_insensitive_extractor( # pylint: disable=unused-argument, inconsistent-return-statements + attr, attr_desc, data +): + key = attr_desc["key"] + working_data = data + + while "." in key: + dict_keys = _FLATTEN.split(key) + if len(dict_keys) == 1: + key = _decode_attribute_map_key(dict_keys[0]) + break + working_key = _decode_attribute_map_key(dict_keys[0]) + working_data = attribute_key_case_insensitive_extractor(working_key, None, working_data) + if working_data is None: + # If at any point while following flatten JSON path see None, it means + # that all properties under are None as well + return None + key = ".".join(dict_keys[1:]) + + if working_data: + return attribute_key_case_insensitive_extractor(key, None, working_data) + + +def last_rest_key_extractor(attr, attr_desc, data): # pylint: disable=unused-argument + """Extract the attribute in "data" based on the last part of the JSON path key. + + :param str attr: The attribute to extract + :param dict attr_desc: The attribute description + :param dict data: The data to extract from + :rtype: object + :returns: The extracted attribute + """ + key = attr_desc["key"] + dict_keys = _FLATTEN.split(key) + return attribute_key_extractor(dict_keys[-1], None, data) + + +def last_rest_key_case_insensitive_extractor(attr, attr_desc, data): # pylint: disable=unused-argument + """Extract the attribute in "data" based on the last part of the JSON path key. + + This is the case insensitive version of "last_rest_key_extractor" + :param str attr: The attribute to extract + :param dict attr_desc: The attribute description + :param dict data: The data to extract from + :rtype: object + :returns: The extracted attribute + """ + key = attr_desc["key"] + dict_keys = _FLATTEN.split(key) + return attribute_key_case_insensitive_extractor(dict_keys[-1], None, data) + + +def attribute_key_extractor(attr, _, data): + return data.get(attr) + + +def attribute_key_case_insensitive_extractor(attr, _, data): + found_key = None + lower_attr = attr.lower() + for key in data: + if lower_attr == key.lower(): + found_key = key + break + + return data.get(found_key) + + +def _extract_name_from_internal_type(internal_type): + """Given an internal type XML description, extract correct XML name with namespace. + + :param dict internal_type: An model type + :rtype: tuple + :returns: A tuple XML name + namespace dict + """ + internal_type_xml_map = getattr(internal_type, "_xml_map", {}) + xml_name = internal_type_xml_map.get("name", internal_type.__name__) + xml_ns = internal_type_xml_map.get("ns", None) + if xml_ns: + xml_name = "{{{}}}{}".format(xml_ns, xml_name) + return xml_name + + +def xml_key_extractor(attr, attr_desc, data): # pylint: disable=unused-argument,too-many-return-statements + if isinstance(data, dict): + return None + + # Test if this model is XML ready first + if not isinstance(data, ET.Element): + return None + + xml_desc = attr_desc.get("xml", {}) + xml_name = xml_desc.get("name", attr_desc["key"]) + + # Look for a children + is_iter_type = attr_desc["type"].startswith("[") + is_wrapped = xml_desc.get("wrapped", False) + internal_type = attr_desc.get("internalType", None) + internal_type_xml_map = getattr(internal_type, "_xml_map", {}) + + # Integrate namespace if necessary + xml_ns = xml_desc.get("ns", internal_type_xml_map.get("ns", None)) + if xml_ns: + xml_name = "{{{}}}{}".format(xml_ns, xml_name) + + # If it's an attribute, that's simple + if xml_desc.get("attr", False): + return data.get(xml_name) + + # If it's x-ms-text, that's simple too + if xml_desc.get("text", False): + return data.text + + # Scenario where I take the local name: + # - Wrapped node + # - Internal type is an enum (considered basic types) + # - Internal type has no XML/Name node + if is_wrapped or (internal_type and (issubclass(internal_type, Enum) or "name" not in internal_type_xml_map)): + children = data.findall(xml_name) + # If internal type has a local name and it's not a list, I use that name + elif not is_iter_type and internal_type and "name" in internal_type_xml_map: + xml_name = _extract_name_from_internal_type(internal_type) + children = data.findall(xml_name) + # That's an array + else: + if internal_type: # Complex type, ignore itemsName and use the complex type name + items_name = _extract_name_from_internal_type(internal_type) + else: + items_name = xml_desc.get("itemsName", xml_name) + children = data.findall(items_name) + + if len(children) == 0: + if is_iter_type: + if is_wrapped: + return None # is_wrapped no node, we want None + return [] # not wrapped, assume empty list + return None # Assume it's not there, maybe an optional node. + + # If is_iter_type and not wrapped, return all found children + if is_iter_type: + if not is_wrapped: + return children + # Iter and wrapped, should have found one node only (the wrap one) + if len(children) != 1: + raise DeserializationError( + "Tried to deserialize an array not wrapped, and found several nodes '{}'. Maybe you should declare this array as wrapped?".format( + xml_name + ) + ) + return list(children[0]) # Might be empty list and that's ok. + + # Here it's not a itertype, we should have found one element only or empty + if len(children) > 1: + raise DeserializationError("Find several XML '{}' where it was not expected".format(xml_name)) + return children[0] + + +class Deserializer: + """Response object model deserializer. + + :param dict classes: Class type dictionary for deserializing complex types. + :ivar list key_extractors: Ordered list of extractors to be used by this deserializer. + """ + + basic_types = {str: "str", int: "int", bool: "bool", float: "float"} + + valid_date = re.compile(r"\d{4}[-]\d{2}[-]\d{2}T\d{2}:\d{2}:\d{2}\.?\d*Z?[-+]?[\d{2}]?:?[\d{2}]?") + + def __init__(self, classes: Optional[Mapping[str, type]] = None) -> None: + self.deserialize_type = { + "iso-8601": Deserializer.deserialize_iso, + "rfc-1123": Deserializer.deserialize_rfc, + "unix-time": Deserializer.deserialize_unix, + "duration": Deserializer.deserialize_duration, + "date": Deserializer.deserialize_date, + "time": Deserializer.deserialize_time, + "decimal": Deserializer.deserialize_decimal, + "long": Deserializer.deserialize_long, + "bytearray": Deserializer.deserialize_bytearray, + "base64": Deserializer.deserialize_base64, + "object": self.deserialize_object, + "[]": self.deserialize_iter, + "{}": self.deserialize_dict, + } + self.deserialize_expected_types = { + "duration": (isodate.Duration, datetime.timedelta), + "iso-8601": (datetime.datetime), + } + self.dependencies: Dict[str, type] = dict(classes) if classes else {} + self.key_extractors = [rest_key_extractor, xml_key_extractor] + # Additional properties only works if the "rest_key_extractor" is used to + # extract the keys. Making it to work whatever the key extractor is too much + # complicated, with no real scenario for now. + # So adding a flag to disable additional properties detection. This flag should be + # used if your expect the deserialization to NOT come from a JSON REST syntax. + # Otherwise, result are unexpected + self.additional_properties_detection = True + + def __call__(self, target_obj, response_data, content_type=None): + """Call the deserializer to process a REST response. + + :param str target_obj: Target data type to deserialize to. + :param requests.Response response_data: REST response object. + :param str content_type: Swagger "produces" if available. + :raises DeserializationError: if deserialization fails. + :return: Deserialized object. + :rtype: object + """ + data = self._unpack_content(response_data, content_type) + return self._deserialize(target_obj, data) + + def _deserialize(self, target_obj, data): # pylint: disable=inconsistent-return-statements + """Call the deserializer on a model. + + Data needs to be already deserialized as JSON or XML ElementTree + + :param str target_obj: Target data type to deserialize to. + :param object data: Object to deserialize. + :raises DeserializationError: if deserialization fails. + :return: Deserialized object. + :rtype: object + """ + # This is already a model, go recursive just in case + if hasattr(data, "_attribute_map"): + constants = [name for name, config in getattr(data, "_validation", {}).items() if config.get("constant")] + try: + for attr, mapconfig in data._attribute_map.items(): # pylint: disable=protected-access + if attr in constants: + continue + value = getattr(data, attr) + if value is None: + continue + local_type = mapconfig["type"] + internal_data_type = local_type.strip("[]{}") + if internal_data_type not in self.dependencies or isinstance(internal_data_type, Enum): + continue + setattr(data, attr, self._deserialize(local_type, value)) + return data + except AttributeError: + return + + response, class_name = self._classify_target(target_obj, data) + + if isinstance(response, str): + return self.deserialize_data(data, response) + if isinstance(response, type) and issubclass(response, Enum): + return self.deserialize_enum(data, response) + + if data is None or data is CoreNull: + return data + try: + attributes = response._attribute_map # type: ignore # pylint: disable=protected-access + d_attrs = {} + for attr, attr_desc in attributes.items(): + # Check empty string. If it's not empty, someone has a real "additionalProperties"... + if attr == "additional_properties" and attr_desc["key"] == "": + continue + raw_value = None + # Enhance attr_desc with some dynamic data + attr_desc = attr_desc.copy() # Do a copy, do not change the real one + internal_data_type = attr_desc["type"].strip("[]{}") + if internal_data_type in self.dependencies: + attr_desc["internalType"] = self.dependencies[internal_data_type] + + for key_extractor in self.key_extractors: + found_value = key_extractor(attr, attr_desc, data) + if found_value is not None: + if raw_value is not None and raw_value != found_value: + msg = ( + "Ignoring extracted value '%s' from %s for key '%s'" + " (duplicate extraction, follow extractors order)" + ) + _LOGGER.warning(msg, found_value, key_extractor, attr) + continue + raw_value = found_value + + value = self.deserialize_data(raw_value, attr_desc["type"]) + d_attrs[attr] = value + except (AttributeError, TypeError, KeyError) as err: + msg = "Unable to deserialize to object: " + class_name # type: ignore + raise DeserializationError(msg) from err + additional_properties = self._build_additional_properties(attributes, data) + return self._instantiate_model(response, d_attrs, additional_properties) + + def _build_additional_properties(self, attribute_map, data): + if not self.additional_properties_detection: + return None + if "additional_properties" in attribute_map and attribute_map.get("additional_properties", {}).get("key") != "": + # Check empty string. If it's not empty, someone has a real "additionalProperties" + return None + if isinstance(data, ET.Element): + data = {el.tag: el.text for el in data} + + known_keys = { + _decode_attribute_map_key(_FLATTEN.split(desc["key"])[0]) + for desc in attribute_map.values() + if desc["key"] != "" + } + present_keys = set(data.keys()) + missing_keys = present_keys - known_keys + return {key: data[key] for key in missing_keys} + + def _classify_target(self, target, data): + """Check to see whether the deserialization target object can + be classified into a subclass. + Once classification has been determined, initialize object. + + :param str target: The target object type to deserialize to. + :param str/dict data: The response data to deserialize. + :return: The classified target object and its class name. + :rtype: tuple + """ + if target is None: + return None, None + + if isinstance(target, str): + try: + target = self.dependencies[target] + except KeyError: + return target, target + + try: + target = target._classify(data, self.dependencies) # type: ignore # pylint: disable=protected-access + except AttributeError: + pass # Target is not a Model, no classify + return target, target.__class__.__name__ # type: ignore + + def failsafe_deserialize(self, target_obj, data, content_type=None): + """Ignores any errors encountered in deserialization, + and falls back to not deserializing the object. Recommended + for use in error deserialization, as we want to return the + HttpResponseError to users, and not have them deal with + a deserialization error. + + :param str target_obj: The target object type to deserialize to. + :param str/dict data: The response data to deserialize. + :param str content_type: Swagger "produces" if available. + :return: Deserialized object. + :rtype: object + """ + try: + return self(target_obj, data, content_type=content_type) + except: # pylint: disable=bare-except + _LOGGER.debug( + "Ran into a deserialization error. Ignoring since this is failsafe deserialization", exc_info=True + ) + return None + + @staticmethod + def _unpack_content(raw_data, content_type=None): + """Extract the correct structure for deserialization. + + If raw_data is a PipelineResponse, try to extract the result of RawDeserializer. + if we can't, raise. Your Pipeline should have a RawDeserializer. + + If not a pipeline response and raw_data is bytes or string, use content-type + to decode it. If no content-type, try JSON. + + If raw_data is something else, bypass all logic and return it directly. + + :param obj raw_data: Data to be processed. + :param str content_type: How to parse if raw_data is a string/bytes. + :raises JSONDecodeError: If JSON is requested and parsing is impossible. + :raises UnicodeDecodeError: If bytes is not UTF8 + :rtype: object + :return: Unpacked content. + """ + # Assume this is enough to detect a Pipeline Response without importing it + context = getattr(raw_data, "context", {}) + if context: + if RawDeserializer.CONTEXT_NAME in context: + return context[RawDeserializer.CONTEXT_NAME] + raise ValueError("This pipeline didn't have the RawDeserializer policy; can't deserialize") + + # Assume this is enough to recognize universal_http.ClientResponse without importing it + if hasattr(raw_data, "body"): + return RawDeserializer.deserialize_from_http_generics(raw_data.text(), raw_data.headers) + + # Assume this enough to recognize requests.Response without importing it. + if hasattr(raw_data, "_content_consumed"): + return RawDeserializer.deserialize_from_http_generics(raw_data.text, raw_data.headers) + + if isinstance(raw_data, (str, bytes)) or hasattr(raw_data, "read"): + return RawDeserializer.deserialize_from_text(raw_data, content_type) # type: ignore + return raw_data + + def _instantiate_model(self, response, attrs, additional_properties=None): + """Instantiate a response model passing in deserialized args. + + :param Response response: The response model class. + :param dict attrs: The deserialized response attributes. + :param dict additional_properties: Additional properties to be set. + :rtype: Response + :return: The instantiated response model. + """ + if callable(response): + subtype = getattr(response, "_subtype_map", {}) + try: + readonly = [ + k + for k, v in response._validation.items() # pylint: disable=protected-access # type: ignore + if v.get("readonly") + ] + const = [ + k + for k, v in response._validation.items() # pylint: disable=protected-access # type: ignore + if v.get("constant") + ] + kwargs = {k: v for k, v in attrs.items() if k not in subtype and k not in readonly + const} + response_obj = response(**kwargs) + for attr in readonly: + setattr(response_obj, attr, attrs.get(attr)) + if additional_properties: + response_obj.additional_properties = additional_properties # type: ignore + return response_obj + except TypeError as err: + msg = "Unable to deserialize {} into model {}. ".format(kwargs, response) # type: ignore + raise DeserializationError(msg + str(err)) from err + else: + try: + for attr, value in attrs.items(): + setattr(response, attr, value) + return response + except Exception as exp: + msg = "Unable to populate response model. " + msg += "Type: {}, Error: {}".format(type(response), exp) + raise DeserializationError(msg) from exp + + def deserialize_data(self, data, data_type): # pylint: disable=too-many-return-statements + """Process data for deserialization according to data type. + + :param str data: The response string to be deserialized. + :param str data_type: The type to deserialize to. + :raises DeserializationError: if deserialization fails. + :return: Deserialized object. + :rtype: object + """ + if data is None: + return data + + try: + if not data_type: + return data + if data_type in self.basic_types.values(): + return self.deserialize_basic(data, data_type) + if data_type in self.deserialize_type: + if isinstance(data, self.deserialize_expected_types.get(data_type, tuple())): + return data + + is_a_text_parsing_type = lambda x: x not in [ # pylint: disable=unnecessary-lambda-assignment + "object", + "[]", + r"{}", + ] + if isinstance(data, ET.Element) and is_a_text_parsing_type(data_type) and not data.text: + return None + data_val = self.deserialize_type[data_type](data) + return data_val + + iter_type = data_type[0] + data_type[-1] + if iter_type in self.deserialize_type: + return self.deserialize_type[iter_type](data, data_type[1:-1]) + + obj_type = self.dependencies[data_type] + if issubclass(obj_type, Enum): + if isinstance(data, ET.Element): + data = data.text + return self.deserialize_enum(data, obj_type) + + except (ValueError, TypeError, AttributeError) as err: + msg = "Unable to deserialize response data." + msg += " Data: {}, {}".format(data, data_type) + raise DeserializationError(msg) from err + return self._deserialize(obj_type, data) + + def deserialize_iter(self, attr, iter_type): + """Deserialize an iterable. + + :param list attr: Iterable to be deserialized. + :param str iter_type: The type of object in the iterable. + :return: Deserialized iterable. + :rtype: list + """ + if attr is None: + return None + if isinstance(attr, ET.Element): # If I receive an element here, get the children + attr = list(attr) + if not isinstance(attr, (list, set)): + raise DeserializationError("Cannot deserialize as [{}] an object of type {}".format(iter_type, type(attr))) + return [self.deserialize_data(a, iter_type) for a in attr] + + def deserialize_dict(self, attr, dict_type): + """Deserialize a dictionary. + + :param dict/list attr: Dictionary to be deserialized. Also accepts + a list of key, value pairs. + :param str dict_type: The object type of the items in the dictionary. + :return: Deserialized dictionary. + :rtype: dict + """ + if isinstance(attr, list): + return {x["key"]: self.deserialize_data(x["value"], dict_type) for x in attr} + + if isinstance(attr, ET.Element): + # Transform value into {"Key": "value"} + attr = {el.tag: el.text for el in attr} + return {k: self.deserialize_data(v, dict_type) for k, v in attr.items()} + + def deserialize_object(self, attr, **kwargs): # pylint: disable=too-many-return-statements + """Deserialize a generic object. + This will be handled as a dictionary. + + :param dict attr: Dictionary to be deserialized. + :return: Deserialized object. + :rtype: dict + :raises TypeError: if non-builtin datatype encountered. + """ + if attr is None: + return None + if isinstance(attr, ET.Element): + # Do no recurse on XML, just return the tree as-is + return attr + if isinstance(attr, str): + return self.deserialize_basic(attr, "str") + obj_type = type(attr) + if obj_type in self.basic_types: + return self.deserialize_basic(attr, self.basic_types[obj_type]) + if obj_type is _long_type: + return self.deserialize_long(attr) + + if obj_type == dict: + deserialized = {} + for key, value in attr.items(): + try: + deserialized[key] = self.deserialize_object(value, **kwargs) + except ValueError: + deserialized[key] = None + return deserialized + + if obj_type == list: + deserialized = [] + for obj in attr: + try: + deserialized.append(self.deserialize_object(obj, **kwargs)) + except ValueError: + pass + return deserialized + + error = "Cannot deserialize generic object with type: " + raise TypeError(error + str(obj_type)) + + def deserialize_basic(self, attr, data_type): # pylint: disable=too-many-return-statements + """Deserialize basic builtin data type from string. + Will attempt to convert to str, int, float and bool. + This function will also accept '1', '0', 'true' and 'false' as + valid bool values. + + :param str attr: response string to be deserialized. + :param str data_type: deserialization data type. + :return: Deserialized basic type. + :rtype: str, int, float or bool + :raises TypeError: if string format is not valid. + """ + # If we're here, data is supposed to be a basic type. + # If it's still an XML node, take the text + if isinstance(attr, ET.Element): + attr = attr.text + if not attr: + if data_type == "str": + # None or '', node is empty string. + return "" + # None or '', node with a strong type is None. + # Don't try to model "empty bool" or "empty int" + return None + + if data_type == "bool": + if attr in [True, False, 1, 0]: + return bool(attr) + if isinstance(attr, str): + if attr.lower() in ["true", "1"]: + return True + if attr.lower() in ["false", "0"]: + return False + raise TypeError("Invalid boolean value: {}".format(attr)) + + if data_type == "str": + return self.deserialize_unicode(attr) + return eval(data_type)(attr) # nosec # pylint: disable=eval-used + + @staticmethod + def deserialize_unicode(data): + """Preserve unicode objects in Python 2, otherwise return data + as a string. + + :param str data: response string to be deserialized. + :return: Deserialized string. + :rtype: str or unicode + """ + # We might be here because we have an enum modeled as string, + # and we try to deserialize a partial dict with enum inside + if isinstance(data, Enum): + return data + + # Consider this is real string + try: + if isinstance(data, unicode): # type: ignore + return data + except NameError: + return str(data) + return str(data) + + @staticmethod + def deserialize_enum(data, enum_obj): + """Deserialize string into enum object. + + If the string is not a valid enum value it will be returned as-is + and a warning will be logged. + + :param str data: Response string to be deserialized. If this value is + None or invalid it will be returned as-is. + :param Enum enum_obj: Enum object to deserialize to. + :return: Deserialized enum object. + :rtype: Enum + """ + if isinstance(data, enum_obj) or data is None: + return data + if isinstance(data, Enum): + data = data.value + if isinstance(data, int): + # Workaround. We might consider remove it in the future. + try: + return list(enum_obj.__members__.values())[data] + except IndexError as exc: + error = "{!r} is not a valid index for enum {!r}" + raise DeserializationError(error.format(data, enum_obj)) from exc + try: + return enum_obj(str(data)) + except ValueError: + for enum_value in enum_obj: + if enum_value.value.lower() == str(data).lower(): + return enum_value + # We don't fail anymore for unknown value, we deserialize as a string + _LOGGER.warning("Deserializer is not able to find %s as valid enum in %s", data, enum_obj) + return Deserializer.deserialize_unicode(data) + + @staticmethod + def deserialize_bytearray(attr): + """Deserialize string into bytearray. + + :param str attr: response string to be deserialized. + :return: Deserialized bytearray + :rtype: bytearray + :raises TypeError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + return bytearray(b64decode(attr)) # type: ignore + + @staticmethod + def deserialize_base64(attr): + """Deserialize base64 encoded string into string. + + :param str attr: response string to be deserialized. + :return: Deserialized base64 string + :rtype: bytearray + :raises TypeError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + padding = "=" * (3 - (len(attr) + 3) % 4) # type: ignore + attr = attr + padding # type: ignore + encoded = attr.replace("-", "+").replace("_", "/") + return b64decode(encoded) + + @staticmethod + def deserialize_decimal(attr): + """Deserialize string into Decimal object. + + :param str attr: response string to be deserialized. + :return: Deserialized decimal + :raises DeserializationError: if string format invalid. + :rtype: decimal + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + return decimal.Decimal(str(attr)) # type: ignore + except decimal.DecimalException as err: + msg = "Invalid decimal {}".format(attr) + raise DeserializationError(msg) from err + + @staticmethod + def deserialize_long(attr): + """Deserialize string into long (Py2) or int (Py3). + + :param str attr: response string to be deserialized. + :return: Deserialized int + :rtype: long or int + :raises ValueError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + return _long_type(attr) # type: ignore + + @staticmethod + def deserialize_duration(attr): + """Deserialize ISO-8601 formatted string into TimeDelta object. + + :param str attr: response string to be deserialized. + :return: Deserialized duration + :rtype: TimeDelta + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + duration = isodate.parse_duration(attr) + except (ValueError, OverflowError, AttributeError) as err: + msg = "Cannot deserialize duration object." + raise DeserializationError(msg) from err + return duration + + @staticmethod + def deserialize_date(attr): + """Deserialize ISO-8601 formatted string into Date object. + + :param str attr: response string to be deserialized. + :return: Deserialized date + :rtype: Date + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + if re.search(r"[^\W\d_]", attr, re.I + re.U): # type: ignore + raise DeserializationError("Date must have only digits and -. Received: %s" % attr) + # This must NOT use defaultmonth/defaultday. Using None ensure this raises an exception. + return isodate.parse_date(attr, defaultmonth=0, defaultday=0) + + @staticmethod + def deserialize_time(attr): + """Deserialize ISO-8601 formatted string into time object. + + :param str attr: response string to be deserialized. + :return: Deserialized time + :rtype: datetime.time + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + if re.search(r"[^\W\d_]", attr, re.I + re.U): # type: ignore + raise DeserializationError("Date must have only digits and -. Received: %s" % attr) + return isodate.parse_time(attr) + + @staticmethod + def deserialize_rfc(attr): + """Deserialize RFC-1123 formatted string into Datetime object. + + :param str attr: response string to be deserialized. + :return: Deserialized RFC datetime + :rtype: Datetime + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + parsed_date = email.utils.parsedate_tz(attr) # type: ignore + date_obj = datetime.datetime( + *parsed_date[:6], tzinfo=datetime.timezone(datetime.timedelta(minutes=(parsed_date[9] or 0) / 60)) + ) + if not date_obj.tzinfo: + date_obj = date_obj.astimezone(tz=TZ_UTC) + except ValueError as err: + msg = "Cannot deserialize to rfc datetime object." + raise DeserializationError(msg) from err + return date_obj + + @staticmethod + def deserialize_iso(attr): + """Deserialize ISO-8601 formatted string into Datetime object. + + :param str attr: response string to be deserialized. + :return: Deserialized ISO datetime + :rtype: Datetime + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + attr = attr.upper() # type: ignore + match = Deserializer.valid_date.match(attr) + if not match: + raise ValueError("Invalid datetime string: " + attr) + + check_decimal = attr.split(".") + if len(check_decimal) > 1: + decimal_str = "" + for digit in check_decimal[1]: + if digit.isdigit(): + decimal_str += digit + else: + break + if len(decimal_str) > 6: + attr = attr.replace(decimal_str, decimal_str[0:6]) + + date_obj = isodate.parse_datetime(attr) + test_utc = date_obj.utctimetuple() + if test_utc.tm_year > 9999 or test_utc.tm_year < 1: + raise OverflowError("Hit max or min date") + except (ValueError, OverflowError, AttributeError) as err: + msg = "Cannot deserialize datetime object." + raise DeserializationError(msg) from err + return date_obj + + @staticmethod + def deserialize_unix(attr): + """Serialize Datetime object into IntTime format. + This is represented as seconds. + + :param int attr: Object to be serialized. + :return: Deserialized datetime + :rtype: Datetime + :raises DeserializationError: if format invalid + """ + if isinstance(attr, ET.Element): + attr = int(attr.text) # type: ignore + try: + attr = int(attr) + date_obj = datetime.datetime.fromtimestamp(attr, TZ_UTC) + except ValueError as err: + msg = "Cannot deserialize to unix datetime object." + raise DeserializationError(msg) from err + return date_obj diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyDateTimeVersionTolerant/bodydatetimeversiontolerant/aio/_client.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyDateTimeVersionTolerant/bodydatetimeversiontolerant/aio/_client.py index c122ba4b8a2..2077c6ffa89 100644 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyDateTimeVersionTolerant/bodydatetimeversiontolerant/aio/_client.py +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyDateTimeVersionTolerant/bodydatetimeversiontolerant/aio/_client.py @@ -14,7 +14,7 @@ from azure.core.pipeline import policies from azure.core.rest import AsyncHttpResponse, HttpRequest -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import AutoRestDateTimeTestServiceConfiguration from .operations import DatetimeOperations diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyDateTimeVersionTolerant/bodydatetimeversiontolerant/aio/operations/_operations.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyDateTimeVersionTolerant/bodydatetimeversiontolerant/aio/operations/_operations.py index 78f47a1a5cc..e82ed2f2bf5 100644 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyDateTimeVersionTolerant/bodydatetimeversiontolerant/aio/operations/_operations.py +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyDateTimeVersionTolerant/bodydatetimeversiontolerant/aio/operations/_operations.py @@ -24,7 +24,7 @@ from azure.core.tracing.decorator_async import distributed_trace_async from azure.core.utils import case_insensitive_dict -from ..._serialization import Deserializer, Serializer +from ..._utils.serialization import Deserializer, Serializer from ...operations._operations import ( build_datetime_get_invalid_request, build_datetime_get_local_negative_offset_lowercase_max_date_time_request, diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyDateTimeVersionTolerant/bodydatetimeversiontolerant/operations/_operations.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyDateTimeVersionTolerant/bodydatetimeversiontolerant/operations/_operations.py index 178d68ed12f..4cc918a19e3 100644 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyDateTimeVersionTolerant/bodydatetimeversiontolerant/operations/_operations.py +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyDateTimeVersionTolerant/bodydatetimeversiontolerant/operations/_operations.py @@ -25,7 +25,7 @@ from azure.core.utils import case_insensitive_dict from .._configuration import AutoRestDateTimeTestServiceConfiguration -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyDateVersionTolerant/bodydateversiontolerant/_client.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyDateVersionTolerant/bodydateversiontolerant/_client.py index 539bde48012..e9b72b3144c 100644 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyDateVersionTolerant/bodydateversiontolerant/_client.py +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyDateVersionTolerant/bodydateversiontolerant/_client.py @@ -15,7 +15,7 @@ from azure.core.rest import HttpRequest, HttpResponse from ._configuration import AutoRestDateTestServiceConfiguration -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer from .operations import DateOperations diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyDateVersionTolerant/bodydateversiontolerant/_utils/__init__.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyDateVersionTolerant/bodydateversiontolerant/_utils/__init__.py new file mode 100644 index 00000000000..0af9b28f660 --- /dev/null +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyDateVersionTolerant/bodydateversiontolerant/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyDateVersionTolerant/bodydateversiontolerant/_utils/serialization.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyDateVersionTolerant/bodydateversiontolerant/_utils/serialization.py new file mode 100644 index 00000000000..f5187701d7b --- /dev/null +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyDateVersionTolerant/bodydateversiontolerant/_utils/serialization.py @@ -0,0 +1,2032 @@ +# pylint: disable=line-too-long,useless-suppression,too-many-lines +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +# pyright: reportUnnecessaryTypeIgnoreComment=false + +from base64 import b64decode, b64encode +import calendar +import datetime +import decimal +import email +from enum import Enum +import json +import logging +import re +import sys +import codecs +from typing import ( + Dict, + Any, + cast, + Optional, + Union, + AnyStr, + IO, + Mapping, + Callable, + MutableMapping, + List, +) + +try: + from urllib import quote # type: ignore +except ImportError: + from urllib.parse import quote +import xml.etree.ElementTree as ET + +import isodate # type: ignore +from typing_extensions import Self + +from azure.core.exceptions import DeserializationError, SerializationError +from azure.core.serialization import NULL as CoreNull + +_BOM = codecs.BOM_UTF8.decode(encoding="utf-8") + +JSON = MutableMapping[str, Any] + + +class RawDeserializer: + + # Accept "text" because we're open minded people... + JSON_REGEXP = re.compile(r"^(application|text)/([a-z+.]+\+)?json$") + + # Name used in context + CONTEXT_NAME = "deserialized_data" + + @classmethod + def deserialize_from_text(cls, data: Optional[Union[AnyStr, IO]], content_type: Optional[str] = None) -> Any: + """Decode data according to content-type. + + Accept a stream of data as well, but will be load at once in memory for now. + + If no content-type, will return the string version (not bytes, not stream) + + :param data: Input, could be bytes or stream (will be decoded with UTF8) or text + :type data: str or bytes or IO + :param str content_type: The content type. + :return: The deserialized data. + :rtype: object + """ + if hasattr(data, "read"): + # Assume a stream + data = cast(IO, data).read() + + if isinstance(data, bytes): + data_as_str = data.decode(encoding="utf-8-sig") + else: + # Explain to mypy the correct type. + data_as_str = cast(str, data) + + # Remove Byte Order Mark if present in string + data_as_str = data_as_str.lstrip(_BOM) + + if content_type is None: + return data + + if cls.JSON_REGEXP.match(content_type): + try: + return json.loads(data_as_str) + except ValueError as err: + raise DeserializationError("JSON is invalid: {}".format(err), err) from err + elif "xml" in (content_type or []): + try: + + try: + if isinstance(data, unicode): # type: ignore + # If I'm Python 2.7 and unicode XML will scream if I try a "fromstring" on unicode string + data_as_str = data_as_str.encode(encoding="utf-8") # type: ignore + except NameError: + pass + + return ET.fromstring(data_as_str) # nosec + except ET.ParseError as err: + # It might be because the server has an issue, and returned JSON with + # content-type XML.... + # So let's try a JSON load, and if it's still broken + # let's flow the initial exception + def _json_attemp(data): + try: + return True, json.loads(data) + except ValueError: + return False, None # Don't care about this one + + success, json_result = _json_attemp(data) + if success: + return json_result + # If i'm here, it's not JSON, it's not XML, let's scream + # and raise the last context in this block (the XML exception) + # The function hack is because Py2.7 messes up with exception + # context otherwise. + _LOGGER.critical("Wasn't XML not JSON, failing") + raise DeserializationError("XML is invalid") from err + elif content_type.startswith("text/"): + return data_as_str + raise DeserializationError("Cannot deserialize content-type: {}".format(content_type)) + + @classmethod + def deserialize_from_http_generics(cls, body_bytes: Optional[Union[AnyStr, IO]], headers: Mapping) -> Any: + """Deserialize from HTTP response. + + Use bytes and headers to NOT use any requests/aiohttp or whatever + specific implementation. + Headers will tested for "content-type" + + :param bytes body_bytes: The body of the response. + :param dict headers: The headers of the response. + :returns: The deserialized data. + :rtype: object + """ + # Try to use content-type from headers if available + content_type = None + if "content-type" in headers: + content_type = headers["content-type"].split(";")[0].strip().lower() + # Ouch, this server did not declare what it sent... + # Let's guess it's JSON... + # Also, since Autorest was considering that an empty body was a valid JSON, + # need that test as well.... + else: + content_type = "application/json" + + if body_bytes: + return cls.deserialize_from_text(body_bytes, content_type) + return None + + +_LOGGER = logging.getLogger(__name__) + +try: + _long_type = long # type: ignore +except NameError: + _long_type = int + +TZ_UTC = datetime.timezone.utc + +_FLATTEN = re.compile(r"(? None: + self.additional_properties: Optional[Dict[str, Any]] = {} + for k in kwargs: # pylint: disable=consider-using-dict-items + if k not in self._attribute_map: + _LOGGER.warning("%s is not a known attribute of class %s and will be ignored", k, self.__class__) + elif k in self._validation and self._validation[k].get("readonly", False): + _LOGGER.warning("Readonly attribute %s will be ignored in class %s", k, self.__class__) + else: + setattr(self, k, kwargs[k]) + + def __eq__(self, other: Any) -> bool: + """Compare objects by comparing all attributes. + + :param object other: The object to compare + :returns: True if objects are equal + :rtype: bool + """ + if isinstance(other, self.__class__): + return self.__dict__ == other.__dict__ + return False + + def __ne__(self, other: Any) -> bool: + """Compare objects by comparing all attributes. + + :param object other: The object to compare + :returns: True if objects are not equal + :rtype: bool + """ + return not self.__eq__(other) + + def __str__(self) -> str: + return str(self.__dict__) + + @classmethod + def enable_additional_properties_sending(cls) -> None: + cls._attribute_map["additional_properties"] = {"key": "", "type": "{object}"} + + @classmethod + def is_xml_model(cls) -> bool: + try: + cls._xml_map # type: ignore + except AttributeError: + return False + return True + + @classmethod + def _create_xml_node(cls): + """Create XML node. + + :returns: The XML node + :rtype: xml.etree.ElementTree.Element + """ + try: + xml_map = cls._xml_map # type: ignore + except AttributeError: + xml_map = {} + + return _create_xml_node(xml_map.get("name", cls.__name__), xml_map.get("prefix", None), xml_map.get("ns", None)) + + def serialize(self, keep_readonly: bool = False, **kwargs: Any) -> JSON: + """Return the JSON that would be sent to server from this model. + + This is an alias to `as_dict(full_restapi_key_transformer, keep_readonly=False)`. + + If you want XML serialization, you can pass the kwargs is_xml=True. + + :param bool keep_readonly: If you want to serialize the readonly attributes + :returns: A dict JSON compatible object + :rtype: dict + """ + serializer = Serializer(self._infer_class_models()) + return serializer._serialize( # type: ignore # pylint: disable=protected-access + self, keep_readonly=keep_readonly, **kwargs + ) + + def as_dict( + self, + keep_readonly: bool = True, + key_transformer: Callable[[str, Dict[str, Any], Any], Any] = attribute_transformer, + **kwargs: Any + ) -> JSON: + """Return a dict that can be serialized using json.dump. + + Advanced usage might optionally use a callback as parameter: + + .. code::python + + def my_key_transformer(key, attr_desc, value): + return key + + Key is the attribute name used in Python. Attr_desc + is a dict of metadata. Currently contains 'type' with the + msrest type and 'key' with the RestAPI encoded key. + Value is the current value in this object. + + The string returned will be used to serialize the key. + If the return type is a list, this is considered hierarchical + result dict. + + See the three examples in this file: + + - attribute_transformer + - full_restapi_key_transformer + - last_restapi_key_transformer + + If you want XML serialization, you can pass the kwargs is_xml=True. + + :param bool keep_readonly: If you want to serialize the readonly attributes + :param function key_transformer: A key transformer function. + :returns: A dict JSON compatible object + :rtype: dict + """ + serializer = Serializer(self._infer_class_models()) + return serializer._serialize( # type: ignore # pylint: disable=protected-access + self, key_transformer=key_transformer, keep_readonly=keep_readonly, **kwargs + ) + + @classmethod + def _infer_class_models(cls): + try: + str_models = cls.__module__.rsplit(".", 1)[0] + models = sys.modules[str_models] + client_models = {k: v for k, v in models.__dict__.items() if isinstance(v, type)} + if cls.__name__ not in client_models: + raise ValueError("Not Autorest generated code") + except Exception: # pylint: disable=broad-exception-caught + # Assume it's not Autorest generated (tests?). Add ourselves as dependencies. + client_models = {cls.__name__: cls} + return client_models + + @classmethod + def deserialize(cls, data: Any, content_type: Optional[str] = None) -> Self: + """Parse a str using the RestAPI syntax and return a model. + + :param str data: A str using RestAPI structure. JSON by default. + :param str content_type: JSON by default, set application/xml if XML. + :returns: An instance of this model + :raises DeserializationError: if something went wrong + :rtype: Self + """ + deserializer = Deserializer(cls._infer_class_models()) + return deserializer(cls.__name__, data, content_type=content_type) # type: ignore + + @classmethod + def from_dict( + cls, + data: Any, + key_extractors: Optional[Callable[[str, Dict[str, Any], Any], Any]] = None, + content_type: Optional[str] = None, + ) -> Self: + """Parse a dict using given key extractor return a model. + + By default consider key + extractors (rest_key_case_insensitive_extractor, attribute_key_case_insensitive_extractor + and last_rest_key_case_insensitive_extractor) + + :param dict data: A dict using RestAPI structure + :param function key_extractors: A key extractor function. + :param str content_type: JSON by default, set application/xml if XML. + :returns: An instance of this model + :raises DeserializationError: if something went wrong + :rtype: Self + """ + deserializer = Deserializer(cls._infer_class_models()) + deserializer.key_extractors = ( # type: ignore + [ # type: ignore + attribute_key_case_insensitive_extractor, + rest_key_case_insensitive_extractor, + last_rest_key_case_insensitive_extractor, + ] + if key_extractors is None + else key_extractors + ) + return deserializer(cls.__name__, data, content_type=content_type) # type: ignore + + @classmethod + def _flatten_subtype(cls, key, objects): + if "_subtype_map" not in cls.__dict__: + return {} + result = dict(cls._subtype_map[key]) + for valuetype in cls._subtype_map[key].values(): + result.update(objects[valuetype]._flatten_subtype(key, objects)) # pylint: disable=protected-access + return result + + @classmethod + def _classify(cls, response, objects): + """Check the class _subtype_map for any child classes. + We want to ignore any inherited _subtype_maps. + + :param dict response: The initial data + :param dict objects: The class objects + :returns: The class to be used + :rtype: class + """ + for subtype_key in cls.__dict__.get("_subtype_map", {}).keys(): + subtype_value = None + + if not isinstance(response, ET.Element): + rest_api_response_key = cls._get_rest_key_parts(subtype_key)[-1] + subtype_value = response.get(rest_api_response_key, None) or response.get(subtype_key, None) + else: + subtype_value = xml_key_extractor(subtype_key, cls._attribute_map[subtype_key], response) + if subtype_value: + # Try to match base class. Can be class name only + # (bug to fix in Autorest to support x-ms-discriminator-name) + if cls.__name__ == subtype_value: + return cls + flatten_mapping_type = cls._flatten_subtype(subtype_key, objects) + try: + return objects[flatten_mapping_type[subtype_value]] # type: ignore + except KeyError: + _LOGGER.warning( + "Subtype value %s has no mapping, use base class %s.", + subtype_value, + cls.__name__, + ) + break + else: + _LOGGER.warning("Discriminator %s is absent or null, use base class %s.", subtype_key, cls.__name__) + break + return cls + + @classmethod + def _get_rest_key_parts(cls, attr_key): + """Get the RestAPI key of this attr, split it and decode part + :param str attr_key: Attribute key must be in attribute_map. + :returns: A list of RestAPI part + :rtype: list + """ + rest_split_key = _FLATTEN.split(cls._attribute_map[attr_key]["key"]) + return [_decode_attribute_map_key(key_part) for key_part in rest_split_key] + + +def _decode_attribute_map_key(key): + """This decode a key in an _attribute_map to the actual key we want to look at + inside the received data. + + :param str key: A key string from the generated code + :returns: The decoded key + :rtype: str + """ + return key.replace("\\.", ".") + + +class Serializer: # pylint: disable=too-many-public-methods + """Request object model serializer.""" + + basic_types = {str: "str", int: "int", bool: "bool", float: "float"} + + _xml_basic_types_serializers = {"bool": lambda x: str(x).lower()} + days = {0: "Mon", 1: "Tue", 2: "Wed", 3: "Thu", 4: "Fri", 5: "Sat", 6: "Sun"} + months = { + 1: "Jan", + 2: "Feb", + 3: "Mar", + 4: "Apr", + 5: "May", + 6: "Jun", + 7: "Jul", + 8: "Aug", + 9: "Sep", + 10: "Oct", + 11: "Nov", + 12: "Dec", + } + validation = { + "min_length": lambda x, y: len(x) < y, + "max_length": lambda x, y: len(x) > y, + "minimum": lambda x, y: x < y, + "maximum": lambda x, y: x > y, + "minimum_ex": lambda x, y: x <= y, + "maximum_ex": lambda x, y: x >= y, + "min_items": lambda x, y: len(x) < y, + "max_items": lambda x, y: len(x) > y, + "pattern": lambda x, y: not re.match(y, x, re.UNICODE), + "unique": lambda x, y: len(x) != len(set(x)), + "multiple": lambda x, y: x % y != 0, + } + + def __init__(self, classes: Optional[Mapping[str, type]] = None) -> None: + self.serialize_type = { + "iso-8601": Serializer.serialize_iso, + "rfc-1123": Serializer.serialize_rfc, + "unix-time": Serializer.serialize_unix, + "duration": Serializer.serialize_duration, + "date": Serializer.serialize_date, + "time": Serializer.serialize_time, + "decimal": Serializer.serialize_decimal, + "long": Serializer.serialize_long, + "bytearray": Serializer.serialize_bytearray, + "base64": Serializer.serialize_base64, + "object": self.serialize_object, + "[]": self.serialize_iter, + "{}": self.serialize_dict, + } + self.dependencies: Dict[str, type] = dict(classes) if classes else {} + self.key_transformer = full_restapi_key_transformer + self.client_side_validation = True + + def _serialize( # pylint: disable=too-many-nested-blocks, too-many-branches, too-many-statements, too-many-locals + self, target_obj, data_type=None, **kwargs + ): + """Serialize data into a string according to type. + + :param object target_obj: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str, dict + :raises SerializationError: if serialization fails. + :returns: The serialized data. + """ + key_transformer = kwargs.get("key_transformer", self.key_transformer) + keep_readonly = kwargs.get("keep_readonly", False) + if target_obj is None: + return None + + attr_name = None + class_name = target_obj.__class__.__name__ + + if data_type: + return self.serialize_data(target_obj, data_type, **kwargs) + + if not hasattr(target_obj, "_attribute_map"): + data_type = type(target_obj).__name__ + if data_type in self.basic_types.values(): + return self.serialize_data(target_obj, data_type, **kwargs) + + # Force "is_xml" kwargs if we detect a XML model + try: + is_xml_model_serialization = kwargs["is_xml"] + except KeyError: + is_xml_model_serialization = kwargs.setdefault("is_xml", target_obj.is_xml_model()) + + serialized = {} + if is_xml_model_serialization: + serialized = target_obj._create_xml_node() # pylint: disable=protected-access + try: + attributes = target_obj._attribute_map # pylint: disable=protected-access + for attr, attr_desc in attributes.items(): + attr_name = attr + if not keep_readonly and target_obj._validation.get( # pylint: disable=protected-access + attr_name, {} + ).get("readonly", False): + continue + + if attr_name == "additional_properties" and attr_desc["key"] == "": + if target_obj.additional_properties is not None: + serialized.update(target_obj.additional_properties) + continue + try: + + orig_attr = getattr(target_obj, attr) + if is_xml_model_serialization: + pass # Don't provide "transformer" for XML for now. Keep "orig_attr" + else: # JSON + keys, orig_attr = key_transformer(attr, attr_desc.copy(), orig_attr) + keys = keys if isinstance(keys, list) else [keys] + + kwargs["serialization_ctxt"] = attr_desc + new_attr = self.serialize_data(orig_attr, attr_desc["type"], **kwargs) + + if is_xml_model_serialization: + xml_desc = attr_desc.get("xml", {}) + xml_name = xml_desc.get("name", attr_desc["key"]) + xml_prefix = xml_desc.get("prefix", None) + xml_ns = xml_desc.get("ns", None) + if xml_desc.get("attr", False): + if xml_ns: + ET.register_namespace(xml_prefix, xml_ns) + xml_name = "{{{}}}{}".format(xml_ns, xml_name) + serialized.set(xml_name, new_attr) # type: ignore + continue + if xml_desc.get("text", False): + serialized.text = new_attr # type: ignore + continue + if isinstance(new_attr, list): + serialized.extend(new_attr) # type: ignore + elif isinstance(new_attr, ET.Element): + # If the down XML has no XML/Name, + # we MUST replace the tag with the local tag. But keeping the namespaces. + if "name" not in getattr(orig_attr, "_xml_map", {}): + splitted_tag = new_attr.tag.split("}") + if len(splitted_tag) == 2: # Namespace + new_attr.tag = "}".join([splitted_tag[0], xml_name]) + else: + new_attr.tag = xml_name + serialized.append(new_attr) # type: ignore + else: # That's a basic type + # Integrate namespace if necessary + local_node = _create_xml_node(xml_name, xml_prefix, xml_ns) + local_node.text = str(new_attr) + serialized.append(local_node) # type: ignore + else: # JSON + for k in reversed(keys): # type: ignore + new_attr = {k: new_attr} + + _new_attr = new_attr + _serialized = serialized + for k in keys: # type: ignore + if k not in _serialized: + _serialized.update(_new_attr) # type: ignore + _new_attr = _new_attr[k] # type: ignore + _serialized = _serialized[k] + except ValueError as err: + if isinstance(err, SerializationError): + raise + + except (AttributeError, KeyError, TypeError) as err: + msg = "Attribute {} in object {} cannot be serialized.\n{}".format(attr_name, class_name, str(target_obj)) + raise SerializationError(msg) from err + return serialized + + def body(self, data, data_type, **kwargs): + """Serialize data intended for a request body. + + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: dict + :raises SerializationError: if serialization fails. + :raises ValueError: if data is None + :returns: The serialized request body + """ + + # Just in case this is a dict + internal_data_type_str = data_type.strip("[]{}") + internal_data_type = self.dependencies.get(internal_data_type_str, None) + try: + is_xml_model_serialization = kwargs["is_xml"] + except KeyError: + if internal_data_type and issubclass(internal_data_type, Model): + is_xml_model_serialization = kwargs.setdefault("is_xml", internal_data_type.is_xml_model()) + else: + is_xml_model_serialization = False + if internal_data_type and not isinstance(internal_data_type, Enum): + try: + deserializer = Deserializer(self.dependencies) + # Since it's on serialization, it's almost sure that format is not JSON REST + # We're not able to deal with additional properties for now. + deserializer.additional_properties_detection = False + if is_xml_model_serialization: + deserializer.key_extractors = [ # type: ignore + attribute_key_case_insensitive_extractor, + ] + else: + deserializer.key_extractors = [ + rest_key_case_insensitive_extractor, + attribute_key_case_insensitive_extractor, + last_rest_key_case_insensitive_extractor, + ] + data = deserializer._deserialize(data_type, data) # pylint: disable=protected-access + except DeserializationError as err: + raise SerializationError("Unable to build a model: " + str(err)) from err + + return self._serialize(data, data_type, **kwargs) + + def url(self, name, data, data_type, **kwargs): + """Serialize data intended for a URL path. + + :param str name: The name of the URL path parameter. + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str + :returns: The serialized URL path + :raises TypeError: if serialization fails. + :raises ValueError: if data is None + """ + try: + output = self.serialize_data(data, data_type, **kwargs) + if data_type == "bool": + output = json.dumps(output) + + if kwargs.get("skip_quote") is True: + output = str(output) + output = output.replace("{", quote("{")).replace("}", quote("}")) + else: + output = quote(str(output), safe="") + except SerializationError as exc: + raise TypeError("{} must be type {}.".format(name, data_type)) from exc + return output + + def query(self, name, data, data_type, **kwargs): + """Serialize data intended for a URL query. + + :param str name: The name of the query parameter. + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str, list + :raises TypeError: if serialization fails. + :raises ValueError: if data is None + :returns: The serialized query parameter + """ + try: + # Treat the list aside, since we don't want to encode the div separator + if data_type.startswith("["): + internal_data_type = data_type[1:-1] + do_quote = not kwargs.get("skip_quote", False) + return self.serialize_iter(data, internal_data_type, do_quote=do_quote, **kwargs) + + # Not a list, regular serialization + output = self.serialize_data(data, data_type, **kwargs) + if data_type == "bool": + output = json.dumps(output) + if kwargs.get("skip_quote") is True: + output = str(output) + else: + output = quote(str(output), safe="") + except SerializationError as exc: + raise TypeError("{} must be type {}.".format(name, data_type)) from exc + return str(output) + + def header(self, name, data, data_type, **kwargs): + """Serialize data intended for a request header. + + :param str name: The name of the header. + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str + :raises TypeError: if serialization fails. + :raises ValueError: if data is None + :returns: The serialized header + """ + try: + if data_type in ["[str]"]: + data = ["" if d is None else d for d in data] + + output = self.serialize_data(data, data_type, **kwargs) + if data_type == "bool": + output = json.dumps(output) + except SerializationError as exc: + raise TypeError("{} must be type {}.".format(name, data_type)) from exc + return str(output) + + def serialize_data(self, data, data_type, **kwargs): + """Serialize generic data according to supplied data type. + + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :raises AttributeError: if required data is None. + :raises ValueError: if data is None + :raises SerializationError: if serialization fails. + :returns: The serialized data. + :rtype: str, int, float, bool, dict, list + """ + if data is None: + raise ValueError("No value for given attribute") + + try: + if data is CoreNull: + return None + if data_type in self.basic_types.values(): + return self.serialize_basic(data, data_type, **kwargs) + + if data_type in self.serialize_type: + return self.serialize_type[data_type](data, **kwargs) + + # If dependencies is empty, try with current data class + # It has to be a subclass of Enum anyway + enum_type = self.dependencies.get(data_type, data.__class__) + if issubclass(enum_type, Enum): + return Serializer.serialize_enum(data, enum_obj=enum_type) + + iter_type = data_type[0] + data_type[-1] + if iter_type in self.serialize_type: + return self.serialize_type[iter_type](data, data_type[1:-1], **kwargs) + + except (ValueError, TypeError) as err: + msg = "Unable to serialize value: {!r} as type: {!r}." + raise SerializationError(msg.format(data, data_type)) from err + return self._serialize(data, **kwargs) + + @classmethod + def _get_custom_serializers(cls, data_type, **kwargs): # pylint: disable=inconsistent-return-statements + custom_serializer = kwargs.get("basic_types_serializers", {}).get(data_type) + if custom_serializer: + return custom_serializer + if kwargs.get("is_xml", False): + return cls._xml_basic_types_serializers.get(data_type) + + @classmethod + def serialize_basic(cls, data, data_type, **kwargs): + """Serialize basic builting data type. + Serializes objects to str, int, float or bool. + + Possible kwargs: + - basic_types_serializers dict[str, callable] : If set, use the callable as serializer + - is_xml bool : If set, use xml_basic_types_serializers + + :param obj data: Object to be serialized. + :param str data_type: Type of object in the iterable. + :rtype: str, int, float, bool + :return: serialized object + """ + custom_serializer = cls._get_custom_serializers(data_type, **kwargs) + if custom_serializer: + return custom_serializer(data) + if data_type == "str": + return cls.serialize_unicode(data) + return eval(data_type)(data) # nosec # pylint: disable=eval-used + + @classmethod + def serialize_unicode(cls, data): + """Special handling for serializing unicode strings in Py2. + Encode to UTF-8 if unicode, otherwise handle as a str. + + :param str data: Object to be serialized. + :rtype: str + :return: serialized object + """ + try: # If I received an enum, return its value + return data.value + except AttributeError: + pass + + try: + if isinstance(data, unicode): # type: ignore + # Don't change it, JSON and XML ElementTree are totally able + # to serialize correctly u'' strings + return data + except NameError: + return str(data) + return str(data) + + def serialize_iter(self, data, iter_type, div=None, **kwargs): + """Serialize iterable. + + Supported kwargs: + - serialization_ctxt dict : The current entry of _attribute_map, or same format. + serialization_ctxt['type'] should be same as data_type. + - is_xml bool : If set, serialize as XML + + :param list data: Object to be serialized. + :param str iter_type: Type of object in the iterable. + :param str div: If set, this str will be used to combine the elements + in the iterable into a combined string. Default is 'None'. + Defaults to False. + :rtype: list, str + :return: serialized iterable + """ + if isinstance(data, str): + raise SerializationError("Refuse str type as a valid iter type.") + + serialization_ctxt = kwargs.get("serialization_ctxt", {}) + is_xml = kwargs.get("is_xml", False) + + serialized = [] + for d in data: + try: + serialized.append(self.serialize_data(d, iter_type, **kwargs)) + except ValueError as err: + if isinstance(err, SerializationError): + raise + serialized.append(None) + + if kwargs.get("do_quote", False): + serialized = ["" if s is None else quote(str(s), safe="") for s in serialized] + + if div: + serialized = ["" if s is None else str(s) for s in serialized] + serialized = div.join(serialized) + + if "xml" in serialization_ctxt or is_xml: + # XML serialization is more complicated + xml_desc = serialization_ctxt.get("xml", {}) + xml_name = xml_desc.get("name") + if not xml_name: + xml_name = serialization_ctxt["key"] + + # Create a wrap node if necessary (use the fact that Element and list have "append") + is_wrapped = xml_desc.get("wrapped", False) + node_name = xml_desc.get("itemsName", xml_name) + if is_wrapped: + final_result = _create_xml_node(xml_name, xml_desc.get("prefix", None), xml_desc.get("ns", None)) + else: + final_result = [] + # All list elements to "local_node" + for el in serialized: + if isinstance(el, ET.Element): + el_node = el + else: + el_node = _create_xml_node(node_name, xml_desc.get("prefix", None), xml_desc.get("ns", None)) + if el is not None: # Otherwise it writes "None" :-p + el_node.text = str(el) + final_result.append(el_node) + return final_result + return serialized + + def serialize_dict(self, attr, dict_type, **kwargs): + """Serialize a dictionary of objects. + + :param dict attr: Object to be serialized. + :param str dict_type: Type of object in the dictionary. + :rtype: dict + :return: serialized dictionary + """ + serialization_ctxt = kwargs.get("serialization_ctxt", {}) + serialized = {} + for key, value in attr.items(): + try: + serialized[self.serialize_unicode(key)] = self.serialize_data(value, dict_type, **kwargs) + except ValueError as err: + if isinstance(err, SerializationError): + raise + serialized[self.serialize_unicode(key)] = None + + if "xml" in serialization_ctxt: + # XML serialization is more complicated + xml_desc = serialization_ctxt["xml"] + xml_name = xml_desc["name"] + + final_result = _create_xml_node(xml_name, xml_desc.get("prefix", None), xml_desc.get("ns", None)) + for key, value in serialized.items(): + ET.SubElement(final_result, key).text = value + return final_result + + return serialized + + def serialize_object(self, attr, **kwargs): # pylint: disable=too-many-return-statements + """Serialize a generic object. + This will be handled as a dictionary. If object passed in is not + a basic type (str, int, float, dict, list) it will simply be + cast to str. + + :param dict attr: Object to be serialized. + :rtype: dict or str + :return: serialized object + """ + if attr is None: + return None + if isinstance(attr, ET.Element): + return attr + obj_type = type(attr) + if obj_type in self.basic_types: + return self.serialize_basic(attr, self.basic_types[obj_type], **kwargs) + if obj_type is _long_type: + return self.serialize_long(attr) + if obj_type is str: + return self.serialize_unicode(attr) + if obj_type is datetime.datetime: + return self.serialize_iso(attr) + if obj_type is datetime.date: + return self.serialize_date(attr) + if obj_type is datetime.time: + return self.serialize_time(attr) + if obj_type is datetime.timedelta: + return self.serialize_duration(attr) + if obj_type is decimal.Decimal: + return self.serialize_decimal(attr) + + # If it's a model or I know this dependency, serialize as a Model + if obj_type in self.dependencies.values() or isinstance(attr, Model): + return self._serialize(attr) + + if obj_type == dict: + serialized = {} + for key, value in attr.items(): + try: + serialized[self.serialize_unicode(key)] = self.serialize_object(value, **kwargs) + except ValueError: + serialized[self.serialize_unicode(key)] = None + return serialized + + if obj_type == list: + serialized = [] + for obj in attr: + try: + serialized.append(self.serialize_object(obj, **kwargs)) + except ValueError: + pass + return serialized + return str(attr) + + @staticmethod + def serialize_enum(attr, enum_obj=None): + try: + result = attr.value + except AttributeError: + result = attr + try: + enum_obj(result) # type: ignore + return result + except ValueError as exc: + for enum_value in enum_obj: # type: ignore + if enum_value.value.lower() == str(attr).lower(): + return enum_value.value + error = "{!r} is not valid value for enum {!r}" + raise SerializationError(error.format(attr, enum_obj)) from exc + + @staticmethod + def serialize_bytearray(attr, **kwargs): # pylint: disable=unused-argument + """Serialize bytearray into base-64 string. + + :param str attr: Object to be serialized. + :rtype: str + :return: serialized base64 + """ + return b64encode(attr).decode() + + @staticmethod + def serialize_base64(attr, **kwargs): # pylint: disable=unused-argument + """Serialize str into base-64 string. + + :param str attr: Object to be serialized. + :rtype: str + :return: serialized base64 + """ + encoded = b64encode(attr).decode("ascii") + return encoded.strip("=").replace("+", "-").replace("/", "_") + + @staticmethod + def serialize_decimal(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Decimal object to float. + + :param decimal attr: Object to be serialized. + :rtype: float + :return: serialized decimal + """ + return float(attr) + + @staticmethod + def serialize_long(attr, **kwargs): # pylint: disable=unused-argument + """Serialize long (Py2) or int (Py3). + + :param int attr: Object to be serialized. + :rtype: int/long + :return: serialized long + """ + return _long_type(attr) + + @staticmethod + def serialize_date(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Date object into ISO-8601 formatted string. + + :param Date attr: Object to be serialized. + :rtype: str + :return: serialized date + """ + if isinstance(attr, str): + attr = isodate.parse_date(attr) + t = "{:04}-{:02}-{:02}".format(attr.year, attr.month, attr.day) + return t + + @staticmethod + def serialize_time(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Time object into ISO-8601 formatted string. + + :param datetime.time attr: Object to be serialized. + :rtype: str + :return: serialized time + """ + if isinstance(attr, str): + attr = isodate.parse_time(attr) + t = "{:02}:{:02}:{:02}".format(attr.hour, attr.minute, attr.second) + if attr.microsecond: + t += ".{:02}".format(attr.microsecond) + return t + + @staticmethod + def serialize_duration(attr, **kwargs): # pylint: disable=unused-argument + """Serialize TimeDelta object into ISO-8601 formatted string. + + :param TimeDelta attr: Object to be serialized. + :rtype: str + :return: serialized duration + """ + if isinstance(attr, str): + attr = isodate.parse_duration(attr) + return isodate.duration_isoformat(attr) + + @staticmethod + def serialize_rfc(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Datetime object into RFC-1123 formatted string. + + :param Datetime attr: Object to be serialized. + :rtype: str + :raises TypeError: if format invalid. + :return: serialized rfc + """ + try: + if not attr.tzinfo: + _LOGGER.warning("Datetime with no tzinfo will be considered UTC.") + utc = attr.utctimetuple() + except AttributeError as exc: + raise TypeError("RFC1123 object must be valid Datetime object.") from exc + + return "{}, {:02} {} {:04} {:02}:{:02}:{:02} GMT".format( + Serializer.days[utc.tm_wday], + utc.tm_mday, + Serializer.months[utc.tm_mon], + utc.tm_year, + utc.tm_hour, + utc.tm_min, + utc.tm_sec, + ) + + @staticmethod + def serialize_iso(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Datetime object into ISO-8601 formatted string. + + :param Datetime attr: Object to be serialized. + :rtype: str + :raises SerializationError: if format invalid. + :return: serialized iso + """ + if isinstance(attr, str): + attr = isodate.parse_datetime(attr) + try: + if not attr.tzinfo: + _LOGGER.warning("Datetime with no tzinfo will be considered UTC.") + utc = attr.utctimetuple() + if utc.tm_year > 9999 or utc.tm_year < 1: + raise OverflowError("Hit max or min date") + + microseconds = str(attr.microsecond).rjust(6, "0").rstrip("0").ljust(3, "0") + if microseconds: + microseconds = "." + microseconds + date = "{:04}-{:02}-{:02}T{:02}:{:02}:{:02}".format( + utc.tm_year, utc.tm_mon, utc.tm_mday, utc.tm_hour, utc.tm_min, utc.tm_sec + ) + return date + microseconds + "Z" + except (ValueError, OverflowError) as err: + msg = "Unable to serialize datetime object." + raise SerializationError(msg) from err + except AttributeError as err: + msg = "ISO-8601 object must be valid Datetime object." + raise TypeError(msg) from err + + @staticmethod + def serialize_unix(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Datetime object into IntTime format. + This is represented as seconds. + + :param Datetime attr: Object to be serialized. + :rtype: int + :raises SerializationError: if format invalid + :return: serialied unix + """ + if isinstance(attr, int): + return attr + try: + if not attr.tzinfo: + _LOGGER.warning("Datetime with no tzinfo will be considered UTC.") + return int(calendar.timegm(attr.utctimetuple())) + except AttributeError as exc: + raise TypeError("Unix time object must be valid Datetime object.") from exc + + +def rest_key_extractor(attr, attr_desc, data): # pylint: disable=unused-argument + key = attr_desc["key"] + working_data = data + + while "." in key: + # Need the cast, as for some reasons "split" is typed as list[str | Any] + dict_keys = cast(List[str], _FLATTEN.split(key)) + if len(dict_keys) == 1: + key = _decode_attribute_map_key(dict_keys[0]) + break + working_key = _decode_attribute_map_key(dict_keys[0]) + working_data = working_data.get(working_key, data) + if working_data is None: + # If at any point while following flatten JSON path see None, it means + # that all properties under are None as well + return None + key = ".".join(dict_keys[1:]) + + return working_data.get(key) + + +def rest_key_case_insensitive_extractor( # pylint: disable=unused-argument, inconsistent-return-statements + attr, attr_desc, data +): + key = attr_desc["key"] + working_data = data + + while "." in key: + dict_keys = _FLATTEN.split(key) + if len(dict_keys) == 1: + key = _decode_attribute_map_key(dict_keys[0]) + break + working_key = _decode_attribute_map_key(dict_keys[0]) + working_data = attribute_key_case_insensitive_extractor(working_key, None, working_data) + if working_data is None: + # If at any point while following flatten JSON path see None, it means + # that all properties under are None as well + return None + key = ".".join(dict_keys[1:]) + + if working_data: + return attribute_key_case_insensitive_extractor(key, None, working_data) + + +def last_rest_key_extractor(attr, attr_desc, data): # pylint: disable=unused-argument + """Extract the attribute in "data" based on the last part of the JSON path key. + + :param str attr: The attribute to extract + :param dict attr_desc: The attribute description + :param dict data: The data to extract from + :rtype: object + :returns: The extracted attribute + """ + key = attr_desc["key"] + dict_keys = _FLATTEN.split(key) + return attribute_key_extractor(dict_keys[-1], None, data) + + +def last_rest_key_case_insensitive_extractor(attr, attr_desc, data): # pylint: disable=unused-argument + """Extract the attribute in "data" based on the last part of the JSON path key. + + This is the case insensitive version of "last_rest_key_extractor" + :param str attr: The attribute to extract + :param dict attr_desc: The attribute description + :param dict data: The data to extract from + :rtype: object + :returns: The extracted attribute + """ + key = attr_desc["key"] + dict_keys = _FLATTEN.split(key) + return attribute_key_case_insensitive_extractor(dict_keys[-1], None, data) + + +def attribute_key_extractor(attr, _, data): + return data.get(attr) + + +def attribute_key_case_insensitive_extractor(attr, _, data): + found_key = None + lower_attr = attr.lower() + for key in data: + if lower_attr == key.lower(): + found_key = key + break + + return data.get(found_key) + + +def _extract_name_from_internal_type(internal_type): + """Given an internal type XML description, extract correct XML name with namespace. + + :param dict internal_type: An model type + :rtype: tuple + :returns: A tuple XML name + namespace dict + """ + internal_type_xml_map = getattr(internal_type, "_xml_map", {}) + xml_name = internal_type_xml_map.get("name", internal_type.__name__) + xml_ns = internal_type_xml_map.get("ns", None) + if xml_ns: + xml_name = "{{{}}}{}".format(xml_ns, xml_name) + return xml_name + + +def xml_key_extractor(attr, attr_desc, data): # pylint: disable=unused-argument,too-many-return-statements + if isinstance(data, dict): + return None + + # Test if this model is XML ready first + if not isinstance(data, ET.Element): + return None + + xml_desc = attr_desc.get("xml", {}) + xml_name = xml_desc.get("name", attr_desc["key"]) + + # Look for a children + is_iter_type = attr_desc["type"].startswith("[") + is_wrapped = xml_desc.get("wrapped", False) + internal_type = attr_desc.get("internalType", None) + internal_type_xml_map = getattr(internal_type, "_xml_map", {}) + + # Integrate namespace if necessary + xml_ns = xml_desc.get("ns", internal_type_xml_map.get("ns", None)) + if xml_ns: + xml_name = "{{{}}}{}".format(xml_ns, xml_name) + + # If it's an attribute, that's simple + if xml_desc.get("attr", False): + return data.get(xml_name) + + # If it's x-ms-text, that's simple too + if xml_desc.get("text", False): + return data.text + + # Scenario where I take the local name: + # - Wrapped node + # - Internal type is an enum (considered basic types) + # - Internal type has no XML/Name node + if is_wrapped or (internal_type and (issubclass(internal_type, Enum) or "name" not in internal_type_xml_map)): + children = data.findall(xml_name) + # If internal type has a local name and it's not a list, I use that name + elif not is_iter_type and internal_type and "name" in internal_type_xml_map: + xml_name = _extract_name_from_internal_type(internal_type) + children = data.findall(xml_name) + # That's an array + else: + if internal_type: # Complex type, ignore itemsName and use the complex type name + items_name = _extract_name_from_internal_type(internal_type) + else: + items_name = xml_desc.get("itemsName", xml_name) + children = data.findall(items_name) + + if len(children) == 0: + if is_iter_type: + if is_wrapped: + return None # is_wrapped no node, we want None + return [] # not wrapped, assume empty list + return None # Assume it's not there, maybe an optional node. + + # If is_iter_type and not wrapped, return all found children + if is_iter_type: + if not is_wrapped: + return children + # Iter and wrapped, should have found one node only (the wrap one) + if len(children) != 1: + raise DeserializationError( + "Tried to deserialize an array not wrapped, and found several nodes '{}'. Maybe you should declare this array as wrapped?".format( + xml_name + ) + ) + return list(children[0]) # Might be empty list and that's ok. + + # Here it's not a itertype, we should have found one element only or empty + if len(children) > 1: + raise DeserializationError("Find several XML '{}' where it was not expected".format(xml_name)) + return children[0] + + +class Deserializer: + """Response object model deserializer. + + :param dict classes: Class type dictionary for deserializing complex types. + :ivar list key_extractors: Ordered list of extractors to be used by this deserializer. + """ + + basic_types = {str: "str", int: "int", bool: "bool", float: "float"} + + valid_date = re.compile(r"\d{4}[-]\d{2}[-]\d{2}T\d{2}:\d{2}:\d{2}\.?\d*Z?[-+]?[\d{2}]?:?[\d{2}]?") + + def __init__(self, classes: Optional[Mapping[str, type]] = None) -> None: + self.deserialize_type = { + "iso-8601": Deserializer.deserialize_iso, + "rfc-1123": Deserializer.deserialize_rfc, + "unix-time": Deserializer.deserialize_unix, + "duration": Deserializer.deserialize_duration, + "date": Deserializer.deserialize_date, + "time": Deserializer.deserialize_time, + "decimal": Deserializer.deserialize_decimal, + "long": Deserializer.deserialize_long, + "bytearray": Deserializer.deserialize_bytearray, + "base64": Deserializer.deserialize_base64, + "object": self.deserialize_object, + "[]": self.deserialize_iter, + "{}": self.deserialize_dict, + } + self.deserialize_expected_types = { + "duration": (isodate.Duration, datetime.timedelta), + "iso-8601": (datetime.datetime), + } + self.dependencies: Dict[str, type] = dict(classes) if classes else {} + self.key_extractors = [rest_key_extractor, xml_key_extractor] + # Additional properties only works if the "rest_key_extractor" is used to + # extract the keys. Making it to work whatever the key extractor is too much + # complicated, with no real scenario for now. + # So adding a flag to disable additional properties detection. This flag should be + # used if your expect the deserialization to NOT come from a JSON REST syntax. + # Otherwise, result are unexpected + self.additional_properties_detection = True + + def __call__(self, target_obj, response_data, content_type=None): + """Call the deserializer to process a REST response. + + :param str target_obj: Target data type to deserialize to. + :param requests.Response response_data: REST response object. + :param str content_type: Swagger "produces" if available. + :raises DeserializationError: if deserialization fails. + :return: Deserialized object. + :rtype: object + """ + data = self._unpack_content(response_data, content_type) + return self._deserialize(target_obj, data) + + def _deserialize(self, target_obj, data): # pylint: disable=inconsistent-return-statements + """Call the deserializer on a model. + + Data needs to be already deserialized as JSON or XML ElementTree + + :param str target_obj: Target data type to deserialize to. + :param object data: Object to deserialize. + :raises DeserializationError: if deserialization fails. + :return: Deserialized object. + :rtype: object + """ + # This is already a model, go recursive just in case + if hasattr(data, "_attribute_map"): + constants = [name for name, config in getattr(data, "_validation", {}).items() if config.get("constant")] + try: + for attr, mapconfig in data._attribute_map.items(): # pylint: disable=protected-access + if attr in constants: + continue + value = getattr(data, attr) + if value is None: + continue + local_type = mapconfig["type"] + internal_data_type = local_type.strip("[]{}") + if internal_data_type not in self.dependencies or isinstance(internal_data_type, Enum): + continue + setattr(data, attr, self._deserialize(local_type, value)) + return data + except AttributeError: + return + + response, class_name = self._classify_target(target_obj, data) + + if isinstance(response, str): + return self.deserialize_data(data, response) + if isinstance(response, type) and issubclass(response, Enum): + return self.deserialize_enum(data, response) + + if data is None or data is CoreNull: + return data + try: + attributes = response._attribute_map # type: ignore # pylint: disable=protected-access + d_attrs = {} + for attr, attr_desc in attributes.items(): + # Check empty string. If it's not empty, someone has a real "additionalProperties"... + if attr == "additional_properties" and attr_desc["key"] == "": + continue + raw_value = None + # Enhance attr_desc with some dynamic data + attr_desc = attr_desc.copy() # Do a copy, do not change the real one + internal_data_type = attr_desc["type"].strip("[]{}") + if internal_data_type in self.dependencies: + attr_desc["internalType"] = self.dependencies[internal_data_type] + + for key_extractor in self.key_extractors: + found_value = key_extractor(attr, attr_desc, data) + if found_value is not None: + if raw_value is not None and raw_value != found_value: + msg = ( + "Ignoring extracted value '%s' from %s for key '%s'" + " (duplicate extraction, follow extractors order)" + ) + _LOGGER.warning(msg, found_value, key_extractor, attr) + continue + raw_value = found_value + + value = self.deserialize_data(raw_value, attr_desc["type"]) + d_attrs[attr] = value + except (AttributeError, TypeError, KeyError) as err: + msg = "Unable to deserialize to object: " + class_name # type: ignore + raise DeserializationError(msg) from err + additional_properties = self._build_additional_properties(attributes, data) + return self._instantiate_model(response, d_attrs, additional_properties) + + def _build_additional_properties(self, attribute_map, data): + if not self.additional_properties_detection: + return None + if "additional_properties" in attribute_map and attribute_map.get("additional_properties", {}).get("key") != "": + # Check empty string. If it's not empty, someone has a real "additionalProperties" + return None + if isinstance(data, ET.Element): + data = {el.tag: el.text for el in data} + + known_keys = { + _decode_attribute_map_key(_FLATTEN.split(desc["key"])[0]) + for desc in attribute_map.values() + if desc["key"] != "" + } + present_keys = set(data.keys()) + missing_keys = present_keys - known_keys + return {key: data[key] for key in missing_keys} + + def _classify_target(self, target, data): + """Check to see whether the deserialization target object can + be classified into a subclass. + Once classification has been determined, initialize object. + + :param str target: The target object type to deserialize to. + :param str/dict data: The response data to deserialize. + :return: The classified target object and its class name. + :rtype: tuple + """ + if target is None: + return None, None + + if isinstance(target, str): + try: + target = self.dependencies[target] + except KeyError: + return target, target + + try: + target = target._classify(data, self.dependencies) # type: ignore # pylint: disable=protected-access + except AttributeError: + pass # Target is not a Model, no classify + return target, target.__class__.__name__ # type: ignore + + def failsafe_deserialize(self, target_obj, data, content_type=None): + """Ignores any errors encountered in deserialization, + and falls back to not deserializing the object. Recommended + for use in error deserialization, as we want to return the + HttpResponseError to users, and not have them deal with + a deserialization error. + + :param str target_obj: The target object type to deserialize to. + :param str/dict data: The response data to deserialize. + :param str content_type: Swagger "produces" if available. + :return: Deserialized object. + :rtype: object + """ + try: + return self(target_obj, data, content_type=content_type) + except: # pylint: disable=bare-except + _LOGGER.debug( + "Ran into a deserialization error. Ignoring since this is failsafe deserialization", exc_info=True + ) + return None + + @staticmethod + def _unpack_content(raw_data, content_type=None): + """Extract the correct structure for deserialization. + + If raw_data is a PipelineResponse, try to extract the result of RawDeserializer. + if we can't, raise. Your Pipeline should have a RawDeserializer. + + If not a pipeline response and raw_data is bytes or string, use content-type + to decode it. If no content-type, try JSON. + + If raw_data is something else, bypass all logic and return it directly. + + :param obj raw_data: Data to be processed. + :param str content_type: How to parse if raw_data is a string/bytes. + :raises JSONDecodeError: If JSON is requested and parsing is impossible. + :raises UnicodeDecodeError: If bytes is not UTF8 + :rtype: object + :return: Unpacked content. + """ + # Assume this is enough to detect a Pipeline Response without importing it + context = getattr(raw_data, "context", {}) + if context: + if RawDeserializer.CONTEXT_NAME in context: + return context[RawDeserializer.CONTEXT_NAME] + raise ValueError("This pipeline didn't have the RawDeserializer policy; can't deserialize") + + # Assume this is enough to recognize universal_http.ClientResponse without importing it + if hasattr(raw_data, "body"): + return RawDeserializer.deserialize_from_http_generics(raw_data.text(), raw_data.headers) + + # Assume this enough to recognize requests.Response without importing it. + if hasattr(raw_data, "_content_consumed"): + return RawDeserializer.deserialize_from_http_generics(raw_data.text, raw_data.headers) + + if isinstance(raw_data, (str, bytes)) or hasattr(raw_data, "read"): + return RawDeserializer.deserialize_from_text(raw_data, content_type) # type: ignore + return raw_data + + def _instantiate_model(self, response, attrs, additional_properties=None): + """Instantiate a response model passing in deserialized args. + + :param Response response: The response model class. + :param dict attrs: The deserialized response attributes. + :param dict additional_properties: Additional properties to be set. + :rtype: Response + :return: The instantiated response model. + """ + if callable(response): + subtype = getattr(response, "_subtype_map", {}) + try: + readonly = [ + k + for k, v in response._validation.items() # pylint: disable=protected-access # type: ignore + if v.get("readonly") + ] + const = [ + k + for k, v in response._validation.items() # pylint: disable=protected-access # type: ignore + if v.get("constant") + ] + kwargs = {k: v for k, v in attrs.items() if k not in subtype and k not in readonly + const} + response_obj = response(**kwargs) + for attr in readonly: + setattr(response_obj, attr, attrs.get(attr)) + if additional_properties: + response_obj.additional_properties = additional_properties # type: ignore + return response_obj + except TypeError as err: + msg = "Unable to deserialize {} into model {}. ".format(kwargs, response) # type: ignore + raise DeserializationError(msg + str(err)) from err + else: + try: + for attr, value in attrs.items(): + setattr(response, attr, value) + return response + except Exception as exp: + msg = "Unable to populate response model. " + msg += "Type: {}, Error: {}".format(type(response), exp) + raise DeserializationError(msg) from exp + + def deserialize_data(self, data, data_type): # pylint: disable=too-many-return-statements + """Process data for deserialization according to data type. + + :param str data: The response string to be deserialized. + :param str data_type: The type to deserialize to. + :raises DeserializationError: if deserialization fails. + :return: Deserialized object. + :rtype: object + """ + if data is None: + return data + + try: + if not data_type: + return data + if data_type in self.basic_types.values(): + return self.deserialize_basic(data, data_type) + if data_type in self.deserialize_type: + if isinstance(data, self.deserialize_expected_types.get(data_type, tuple())): + return data + + is_a_text_parsing_type = lambda x: x not in [ # pylint: disable=unnecessary-lambda-assignment + "object", + "[]", + r"{}", + ] + if isinstance(data, ET.Element) and is_a_text_parsing_type(data_type) and not data.text: + return None + data_val = self.deserialize_type[data_type](data) + return data_val + + iter_type = data_type[0] + data_type[-1] + if iter_type in self.deserialize_type: + return self.deserialize_type[iter_type](data, data_type[1:-1]) + + obj_type = self.dependencies[data_type] + if issubclass(obj_type, Enum): + if isinstance(data, ET.Element): + data = data.text + return self.deserialize_enum(data, obj_type) + + except (ValueError, TypeError, AttributeError) as err: + msg = "Unable to deserialize response data." + msg += " Data: {}, {}".format(data, data_type) + raise DeserializationError(msg) from err + return self._deserialize(obj_type, data) + + def deserialize_iter(self, attr, iter_type): + """Deserialize an iterable. + + :param list attr: Iterable to be deserialized. + :param str iter_type: The type of object in the iterable. + :return: Deserialized iterable. + :rtype: list + """ + if attr is None: + return None + if isinstance(attr, ET.Element): # If I receive an element here, get the children + attr = list(attr) + if not isinstance(attr, (list, set)): + raise DeserializationError("Cannot deserialize as [{}] an object of type {}".format(iter_type, type(attr))) + return [self.deserialize_data(a, iter_type) for a in attr] + + def deserialize_dict(self, attr, dict_type): + """Deserialize a dictionary. + + :param dict/list attr: Dictionary to be deserialized. Also accepts + a list of key, value pairs. + :param str dict_type: The object type of the items in the dictionary. + :return: Deserialized dictionary. + :rtype: dict + """ + if isinstance(attr, list): + return {x["key"]: self.deserialize_data(x["value"], dict_type) for x in attr} + + if isinstance(attr, ET.Element): + # Transform value into {"Key": "value"} + attr = {el.tag: el.text for el in attr} + return {k: self.deserialize_data(v, dict_type) for k, v in attr.items()} + + def deserialize_object(self, attr, **kwargs): # pylint: disable=too-many-return-statements + """Deserialize a generic object. + This will be handled as a dictionary. + + :param dict attr: Dictionary to be deserialized. + :return: Deserialized object. + :rtype: dict + :raises TypeError: if non-builtin datatype encountered. + """ + if attr is None: + return None + if isinstance(attr, ET.Element): + # Do no recurse on XML, just return the tree as-is + return attr + if isinstance(attr, str): + return self.deserialize_basic(attr, "str") + obj_type = type(attr) + if obj_type in self.basic_types: + return self.deserialize_basic(attr, self.basic_types[obj_type]) + if obj_type is _long_type: + return self.deserialize_long(attr) + + if obj_type == dict: + deserialized = {} + for key, value in attr.items(): + try: + deserialized[key] = self.deserialize_object(value, **kwargs) + except ValueError: + deserialized[key] = None + return deserialized + + if obj_type == list: + deserialized = [] + for obj in attr: + try: + deserialized.append(self.deserialize_object(obj, **kwargs)) + except ValueError: + pass + return deserialized + + error = "Cannot deserialize generic object with type: " + raise TypeError(error + str(obj_type)) + + def deserialize_basic(self, attr, data_type): # pylint: disable=too-many-return-statements + """Deserialize basic builtin data type from string. + Will attempt to convert to str, int, float and bool. + This function will also accept '1', '0', 'true' and 'false' as + valid bool values. + + :param str attr: response string to be deserialized. + :param str data_type: deserialization data type. + :return: Deserialized basic type. + :rtype: str, int, float or bool + :raises TypeError: if string format is not valid. + """ + # If we're here, data is supposed to be a basic type. + # If it's still an XML node, take the text + if isinstance(attr, ET.Element): + attr = attr.text + if not attr: + if data_type == "str": + # None or '', node is empty string. + return "" + # None or '', node with a strong type is None. + # Don't try to model "empty bool" or "empty int" + return None + + if data_type == "bool": + if attr in [True, False, 1, 0]: + return bool(attr) + if isinstance(attr, str): + if attr.lower() in ["true", "1"]: + return True + if attr.lower() in ["false", "0"]: + return False + raise TypeError("Invalid boolean value: {}".format(attr)) + + if data_type == "str": + return self.deserialize_unicode(attr) + return eval(data_type)(attr) # nosec # pylint: disable=eval-used + + @staticmethod + def deserialize_unicode(data): + """Preserve unicode objects in Python 2, otherwise return data + as a string. + + :param str data: response string to be deserialized. + :return: Deserialized string. + :rtype: str or unicode + """ + # We might be here because we have an enum modeled as string, + # and we try to deserialize a partial dict with enum inside + if isinstance(data, Enum): + return data + + # Consider this is real string + try: + if isinstance(data, unicode): # type: ignore + return data + except NameError: + return str(data) + return str(data) + + @staticmethod + def deserialize_enum(data, enum_obj): + """Deserialize string into enum object. + + If the string is not a valid enum value it will be returned as-is + and a warning will be logged. + + :param str data: Response string to be deserialized. If this value is + None or invalid it will be returned as-is. + :param Enum enum_obj: Enum object to deserialize to. + :return: Deserialized enum object. + :rtype: Enum + """ + if isinstance(data, enum_obj) or data is None: + return data + if isinstance(data, Enum): + data = data.value + if isinstance(data, int): + # Workaround. We might consider remove it in the future. + try: + return list(enum_obj.__members__.values())[data] + except IndexError as exc: + error = "{!r} is not a valid index for enum {!r}" + raise DeserializationError(error.format(data, enum_obj)) from exc + try: + return enum_obj(str(data)) + except ValueError: + for enum_value in enum_obj: + if enum_value.value.lower() == str(data).lower(): + return enum_value + # We don't fail anymore for unknown value, we deserialize as a string + _LOGGER.warning("Deserializer is not able to find %s as valid enum in %s", data, enum_obj) + return Deserializer.deserialize_unicode(data) + + @staticmethod + def deserialize_bytearray(attr): + """Deserialize string into bytearray. + + :param str attr: response string to be deserialized. + :return: Deserialized bytearray + :rtype: bytearray + :raises TypeError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + return bytearray(b64decode(attr)) # type: ignore + + @staticmethod + def deserialize_base64(attr): + """Deserialize base64 encoded string into string. + + :param str attr: response string to be deserialized. + :return: Deserialized base64 string + :rtype: bytearray + :raises TypeError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + padding = "=" * (3 - (len(attr) + 3) % 4) # type: ignore + attr = attr + padding # type: ignore + encoded = attr.replace("-", "+").replace("_", "/") + return b64decode(encoded) + + @staticmethod + def deserialize_decimal(attr): + """Deserialize string into Decimal object. + + :param str attr: response string to be deserialized. + :return: Deserialized decimal + :raises DeserializationError: if string format invalid. + :rtype: decimal + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + return decimal.Decimal(str(attr)) # type: ignore + except decimal.DecimalException as err: + msg = "Invalid decimal {}".format(attr) + raise DeserializationError(msg) from err + + @staticmethod + def deserialize_long(attr): + """Deserialize string into long (Py2) or int (Py3). + + :param str attr: response string to be deserialized. + :return: Deserialized int + :rtype: long or int + :raises ValueError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + return _long_type(attr) # type: ignore + + @staticmethod + def deserialize_duration(attr): + """Deserialize ISO-8601 formatted string into TimeDelta object. + + :param str attr: response string to be deserialized. + :return: Deserialized duration + :rtype: TimeDelta + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + duration = isodate.parse_duration(attr) + except (ValueError, OverflowError, AttributeError) as err: + msg = "Cannot deserialize duration object." + raise DeserializationError(msg) from err + return duration + + @staticmethod + def deserialize_date(attr): + """Deserialize ISO-8601 formatted string into Date object. + + :param str attr: response string to be deserialized. + :return: Deserialized date + :rtype: Date + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + if re.search(r"[^\W\d_]", attr, re.I + re.U): # type: ignore + raise DeserializationError("Date must have only digits and -. Received: %s" % attr) + # This must NOT use defaultmonth/defaultday. Using None ensure this raises an exception. + return isodate.parse_date(attr, defaultmonth=0, defaultday=0) + + @staticmethod + def deserialize_time(attr): + """Deserialize ISO-8601 formatted string into time object. + + :param str attr: response string to be deserialized. + :return: Deserialized time + :rtype: datetime.time + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + if re.search(r"[^\W\d_]", attr, re.I + re.U): # type: ignore + raise DeserializationError("Date must have only digits and -. Received: %s" % attr) + return isodate.parse_time(attr) + + @staticmethod + def deserialize_rfc(attr): + """Deserialize RFC-1123 formatted string into Datetime object. + + :param str attr: response string to be deserialized. + :return: Deserialized RFC datetime + :rtype: Datetime + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + parsed_date = email.utils.parsedate_tz(attr) # type: ignore + date_obj = datetime.datetime( + *parsed_date[:6], tzinfo=datetime.timezone(datetime.timedelta(minutes=(parsed_date[9] or 0) / 60)) + ) + if not date_obj.tzinfo: + date_obj = date_obj.astimezone(tz=TZ_UTC) + except ValueError as err: + msg = "Cannot deserialize to rfc datetime object." + raise DeserializationError(msg) from err + return date_obj + + @staticmethod + def deserialize_iso(attr): + """Deserialize ISO-8601 formatted string into Datetime object. + + :param str attr: response string to be deserialized. + :return: Deserialized ISO datetime + :rtype: Datetime + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + attr = attr.upper() # type: ignore + match = Deserializer.valid_date.match(attr) + if not match: + raise ValueError("Invalid datetime string: " + attr) + + check_decimal = attr.split(".") + if len(check_decimal) > 1: + decimal_str = "" + for digit in check_decimal[1]: + if digit.isdigit(): + decimal_str += digit + else: + break + if len(decimal_str) > 6: + attr = attr.replace(decimal_str, decimal_str[0:6]) + + date_obj = isodate.parse_datetime(attr) + test_utc = date_obj.utctimetuple() + if test_utc.tm_year > 9999 or test_utc.tm_year < 1: + raise OverflowError("Hit max or min date") + except (ValueError, OverflowError, AttributeError) as err: + msg = "Cannot deserialize datetime object." + raise DeserializationError(msg) from err + return date_obj + + @staticmethod + def deserialize_unix(attr): + """Serialize Datetime object into IntTime format. + This is represented as seconds. + + :param int attr: Object to be serialized. + :return: Deserialized datetime + :rtype: Datetime + :raises DeserializationError: if format invalid + """ + if isinstance(attr, ET.Element): + attr = int(attr.text) # type: ignore + try: + attr = int(attr) + date_obj = datetime.datetime.fromtimestamp(attr, TZ_UTC) + except ValueError as err: + msg = "Cannot deserialize to unix datetime object." + raise DeserializationError(msg) from err + return date_obj diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyDateVersionTolerant/bodydateversiontolerant/aio/_client.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyDateVersionTolerant/bodydateversiontolerant/aio/_client.py index 3b00df8de78..23187ee0c07 100644 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyDateVersionTolerant/bodydateversiontolerant/aio/_client.py +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyDateVersionTolerant/bodydateversiontolerant/aio/_client.py @@ -14,7 +14,7 @@ from azure.core.pipeline import policies from azure.core.rest import AsyncHttpResponse, HttpRequest -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import AutoRestDateTestServiceConfiguration from .operations import DateOperations diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyDateVersionTolerant/bodydateversiontolerant/aio/operations/_operations.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyDateVersionTolerant/bodydateversiontolerant/aio/operations/_operations.py index cf9ca0b3ea2..4dad4798f38 100644 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyDateVersionTolerant/bodydateversiontolerant/aio/operations/_operations.py +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyDateVersionTolerant/bodydateversiontolerant/aio/operations/_operations.py @@ -23,7 +23,7 @@ from azure.core.tracing.decorator_async import distributed_trace_async from azure.core.utils import case_insensitive_dict -from ..._serialization import Deserializer, Serializer +from ..._utils.serialization import Deserializer, Serializer from ...operations._operations import ( build_date_get_invalid_date_request, build_date_get_max_date_request, diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyDateVersionTolerant/bodydateversiontolerant/operations/_operations.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyDateVersionTolerant/bodydateversiontolerant/operations/_operations.py index 89d28c95417..da401046a69 100644 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyDateVersionTolerant/bodydateversiontolerant/operations/_operations.py +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyDateVersionTolerant/bodydateversiontolerant/operations/_operations.py @@ -24,7 +24,7 @@ from azure.core.utils import case_insensitive_dict from .._configuration import AutoRestDateTestServiceConfiguration -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyDictionaryVersionTolerant/bodydictionaryversiontolerant/_client.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyDictionaryVersionTolerant/bodydictionaryversiontolerant/_client.py index 42f1c9ccd24..52c12807ba5 100644 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyDictionaryVersionTolerant/bodydictionaryversiontolerant/_client.py +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyDictionaryVersionTolerant/bodydictionaryversiontolerant/_client.py @@ -15,7 +15,7 @@ from azure.core.rest import HttpRequest, HttpResponse from ._configuration import AutoRestSwaggerBATDictionaryServiceConfiguration -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer from .operations import DictionaryOperations diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyDictionaryVersionTolerant/bodydictionaryversiontolerant/_utils/__init__.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyDictionaryVersionTolerant/bodydictionaryversiontolerant/_utils/__init__.py new file mode 100644 index 00000000000..0af9b28f660 --- /dev/null +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyDictionaryVersionTolerant/bodydictionaryversiontolerant/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyDictionaryVersionTolerant/bodydictionaryversiontolerant/_utils/serialization.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyDictionaryVersionTolerant/bodydictionaryversiontolerant/_utils/serialization.py new file mode 100644 index 00000000000..f5187701d7b --- /dev/null +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyDictionaryVersionTolerant/bodydictionaryversiontolerant/_utils/serialization.py @@ -0,0 +1,2032 @@ +# pylint: disable=line-too-long,useless-suppression,too-many-lines +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +# pyright: reportUnnecessaryTypeIgnoreComment=false + +from base64 import b64decode, b64encode +import calendar +import datetime +import decimal +import email +from enum import Enum +import json +import logging +import re +import sys +import codecs +from typing import ( + Dict, + Any, + cast, + Optional, + Union, + AnyStr, + IO, + Mapping, + Callable, + MutableMapping, + List, +) + +try: + from urllib import quote # type: ignore +except ImportError: + from urllib.parse import quote +import xml.etree.ElementTree as ET + +import isodate # type: ignore +from typing_extensions import Self + +from azure.core.exceptions import DeserializationError, SerializationError +from azure.core.serialization import NULL as CoreNull + +_BOM = codecs.BOM_UTF8.decode(encoding="utf-8") + +JSON = MutableMapping[str, Any] + + +class RawDeserializer: + + # Accept "text" because we're open minded people... + JSON_REGEXP = re.compile(r"^(application|text)/([a-z+.]+\+)?json$") + + # Name used in context + CONTEXT_NAME = "deserialized_data" + + @classmethod + def deserialize_from_text(cls, data: Optional[Union[AnyStr, IO]], content_type: Optional[str] = None) -> Any: + """Decode data according to content-type. + + Accept a stream of data as well, but will be load at once in memory for now. + + If no content-type, will return the string version (not bytes, not stream) + + :param data: Input, could be bytes or stream (will be decoded with UTF8) or text + :type data: str or bytes or IO + :param str content_type: The content type. + :return: The deserialized data. + :rtype: object + """ + if hasattr(data, "read"): + # Assume a stream + data = cast(IO, data).read() + + if isinstance(data, bytes): + data_as_str = data.decode(encoding="utf-8-sig") + else: + # Explain to mypy the correct type. + data_as_str = cast(str, data) + + # Remove Byte Order Mark if present in string + data_as_str = data_as_str.lstrip(_BOM) + + if content_type is None: + return data + + if cls.JSON_REGEXP.match(content_type): + try: + return json.loads(data_as_str) + except ValueError as err: + raise DeserializationError("JSON is invalid: {}".format(err), err) from err + elif "xml" in (content_type or []): + try: + + try: + if isinstance(data, unicode): # type: ignore + # If I'm Python 2.7 and unicode XML will scream if I try a "fromstring" on unicode string + data_as_str = data_as_str.encode(encoding="utf-8") # type: ignore + except NameError: + pass + + return ET.fromstring(data_as_str) # nosec + except ET.ParseError as err: + # It might be because the server has an issue, and returned JSON with + # content-type XML.... + # So let's try a JSON load, and if it's still broken + # let's flow the initial exception + def _json_attemp(data): + try: + return True, json.loads(data) + except ValueError: + return False, None # Don't care about this one + + success, json_result = _json_attemp(data) + if success: + return json_result + # If i'm here, it's not JSON, it's not XML, let's scream + # and raise the last context in this block (the XML exception) + # The function hack is because Py2.7 messes up with exception + # context otherwise. + _LOGGER.critical("Wasn't XML not JSON, failing") + raise DeserializationError("XML is invalid") from err + elif content_type.startswith("text/"): + return data_as_str + raise DeserializationError("Cannot deserialize content-type: {}".format(content_type)) + + @classmethod + def deserialize_from_http_generics(cls, body_bytes: Optional[Union[AnyStr, IO]], headers: Mapping) -> Any: + """Deserialize from HTTP response. + + Use bytes and headers to NOT use any requests/aiohttp or whatever + specific implementation. + Headers will tested for "content-type" + + :param bytes body_bytes: The body of the response. + :param dict headers: The headers of the response. + :returns: The deserialized data. + :rtype: object + """ + # Try to use content-type from headers if available + content_type = None + if "content-type" in headers: + content_type = headers["content-type"].split(";")[0].strip().lower() + # Ouch, this server did not declare what it sent... + # Let's guess it's JSON... + # Also, since Autorest was considering that an empty body was a valid JSON, + # need that test as well.... + else: + content_type = "application/json" + + if body_bytes: + return cls.deserialize_from_text(body_bytes, content_type) + return None + + +_LOGGER = logging.getLogger(__name__) + +try: + _long_type = long # type: ignore +except NameError: + _long_type = int + +TZ_UTC = datetime.timezone.utc + +_FLATTEN = re.compile(r"(? None: + self.additional_properties: Optional[Dict[str, Any]] = {} + for k in kwargs: # pylint: disable=consider-using-dict-items + if k not in self._attribute_map: + _LOGGER.warning("%s is not a known attribute of class %s and will be ignored", k, self.__class__) + elif k in self._validation and self._validation[k].get("readonly", False): + _LOGGER.warning("Readonly attribute %s will be ignored in class %s", k, self.__class__) + else: + setattr(self, k, kwargs[k]) + + def __eq__(self, other: Any) -> bool: + """Compare objects by comparing all attributes. + + :param object other: The object to compare + :returns: True if objects are equal + :rtype: bool + """ + if isinstance(other, self.__class__): + return self.__dict__ == other.__dict__ + return False + + def __ne__(self, other: Any) -> bool: + """Compare objects by comparing all attributes. + + :param object other: The object to compare + :returns: True if objects are not equal + :rtype: bool + """ + return not self.__eq__(other) + + def __str__(self) -> str: + return str(self.__dict__) + + @classmethod + def enable_additional_properties_sending(cls) -> None: + cls._attribute_map["additional_properties"] = {"key": "", "type": "{object}"} + + @classmethod + def is_xml_model(cls) -> bool: + try: + cls._xml_map # type: ignore + except AttributeError: + return False + return True + + @classmethod + def _create_xml_node(cls): + """Create XML node. + + :returns: The XML node + :rtype: xml.etree.ElementTree.Element + """ + try: + xml_map = cls._xml_map # type: ignore + except AttributeError: + xml_map = {} + + return _create_xml_node(xml_map.get("name", cls.__name__), xml_map.get("prefix", None), xml_map.get("ns", None)) + + def serialize(self, keep_readonly: bool = False, **kwargs: Any) -> JSON: + """Return the JSON that would be sent to server from this model. + + This is an alias to `as_dict(full_restapi_key_transformer, keep_readonly=False)`. + + If you want XML serialization, you can pass the kwargs is_xml=True. + + :param bool keep_readonly: If you want to serialize the readonly attributes + :returns: A dict JSON compatible object + :rtype: dict + """ + serializer = Serializer(self._infer_class_models()) + return serializer._serialize( # type: ignore # pylint: disable=protected-access + self, keep_readonly=keep_readonly, **kwargs + ) + + def as_dict( + self, + keep_readonly: bool = True, + key_transformer: Callable[[str, Dict[str, Any], Any], Any] = attribute_transformer, + **kwargs: Any + ) -> JSON: + """Return a dict that can be serialized using json.dump. + + Advanced usage might optionally use a callback as parameter: + + .. code::python + + def my_key_transformer(key, attr_desc, value): + return key + + Key is the attribute name used in Python. Attr_desc + is a dict of metadata. Currently contains 'type' with the + msrest type and 'key' with the RestAPI encoded key. + Value is the current value in this object. + + The string returned will be used to serialize the key. + If the return type is a list, this is considered hierarchical + result dict. + + See the three examples in this file: + + - attribute_transformer + - full_restapi_key_transformer + - last_restapi_key_transformer + + If you want XML serialization, you can pass the kwargs is_xml=True. + + :param bool keep_readonly: If you want to serialize the readonly attributes + :param function key_transformer: A key transformer function. + :returns: A dict JSON compatible object + :rtype: dict + """ + serializer = Serializer(self._infer_class_models()) + return serializer._serialize( # type: ignore # pylint: disable=protected-access + self, key_transformer=key_transformer, keep_readonly=keep_readonly, **kwargs + ) + + @classmethod + def _infer_class_models(cls): + try: + str_models = cls.__module__.rsplit(".", 1)[0] + models = sys.modules[str_models] + client_models = {k: v for k, v in models.__dict__.items() if isinstance(v, type)} + if cls.__name__ not in client_models: + raise ValueError("Not Autorest generated code") + except Exception: # pylint: disable=broad-exception-caught + # Assume it's not Autorest generated (tests?). Add ourselves as dependencies. + client_models = {cls.__name__: cls} + return client_models + + @classmethod + def deserialize(cls, data: Any, content_type: Optional[str] = None) -> Self: + """Parse a str using the RestAPI syntax and return a model. + + :param str data: A str using RestAPI structure. JSON by default. + :param str content_type: JSON by default, set application/xml if XML. + :returns: An instance of this model + :raises DeserializationError: if something went wrong + :rtype: Self + """ + deserializer = Deserializer(cls._infer_class_models()) + return deserializer(cls.__name__, data, content_type=content_type) # type: ignore + + @classmethod + def from_dict( + cls, + data: Any, + key_extractors: Optional[Callable[[str, Dict[str, Any], Any], Any]] = None, + content_type: Optional[str] = None, + ) -> Self: + """Parse a dict using given key extractor return a model. + + By default consider key + extractors (rest_key_case_insensitive_extractor, attribute_key_case_insensitive_extractor + and last_rest_key_case_insensitive_extractor) + + :param dict data: A dict using RestAPI structure + :param function key_extractors: A key extractor function. + :param str content_type: JSON by default, set application/xml if XML. + :returns: An instance of this model + :raises DeserializationError: if something went wrong + :rtype: Self + """ + deserializer = Deserializer(cls._infer_class_models()) + deserializer.key_extractors = ( # type: ignore + [ # type: ignore + attribute_key_case_insensitive_extractor, + rest_key_case_insensitive_extractor, + last_rest_key_case_insensitive_extractor, + ] + if key_extractors is None + else key_extractors + ) + return deserializer(cls.__name__, data, content_type=content_type) # type: ignore + + @classmethod + def _flatten_subtype(cls, key, objects): + if "_subtype_map" not in cls.__dict__: + return {} + result = dict(cls._subtype_map[key]) + for valuetype in cls._subtype_map[key].values(): + result.update(objects[valuetype]._flatten_subtype(key, objects)) # pylint: disable=protected-access + return result + + @classmethod + def _classify(cls, response, objects): + """Check the class _subtype_map for any child classes. + We want to ignore any inherited _subtype_maps. + + :param dict response: The initial data + :param dict objects: The class objects + :returns: The class to be used + :rtype: class + """ + for subtype_key in cls.__dict__.get("_subtype_map", {}).keys(): + subtype_value = None + + if not isinstance(response, ET.Element): + rest_api_response_key = cls._get_rest_key_parts(subtype_key)[-1] + subtype_value = response.get(rest_api_response_key, None) or response.get(subtype_key, None) + else: + subtype_value = xml_key_extractor(subtype_key, cls._attribute_map[subtype_key], response) + if subtype_value: + # Try to match base class. Can be class name only + # (bug to fix in Autorest to support x-ms-discriminator-name) + if cls.__name__ == subtype_value: + return cls + flatten_mapping_type = cls._flatten_subtype(subtype_key, objects) + try: + return objects[flatten_mapping_type[subtype_value]] # type: ignore + except KeyError: + _LOGGER.warning( + "Subtype value %s has no mapping, use base class %s.", + subtype_value, + cls.__name__, + ) + break + else: + _LOGGER.warning("Discriminator %s is absent or null, use base class %s.", subtype_key, cls.__name__) + break + return cls + + @classmethod + def _get_rest_key_parts(cls, attr_key): + """Get the RestAPI key of this attr, split it and decode part + :param str attr_key: Attribute key must be in attribute_map. + :returns: A list of RestAPI part + :rtype: list + """ + rest_split_key = _FLATTEN.split(cls._attribute_map[attr_key]["key"]) + return [_decode_attribute_map_key(key_part) for key_part in rest_split_key] + + +def _decode_attribute_map_key(key): + """This decode a key in an _attribute_map to the actual key we want to look at + inside the received data. + + :param str key: A key string from the generated code + :returns: The decoded key + :rtype: str + """ + return key.replace("\\.", ".") + + +class Serializer: # pylint: disable=too-many-public-methods + """Request object model serializer.""" + + basic_types = {str: "str", int: "int", bool: "bool", float: "float"} + + _xml_basic_types_serializers = {"bool": lambda x: str(x).lower()} + days = {0: "Mon", 1: "Tue", 2: "Wed", 3: "Thu", 4: "Fri", 5: "Sat", 6: "Sun"} + months = { + 1: "Jan", + 2: "Feb", + 3: "Mar", + 4: "Apr", + 5: "May", + 6: "Jun", + 7: "Jul", + 8: "Aug", + 9: "Sep", + 10: "Oct", + 11: "Nov", + 12: "Dec", + } + validation = { + "min_length": lambda x, y: len(x) < y, + "max_length": lambda x, y: len(x) > y, + "minimum": lambda x, y: x < y, + "maximum": lambda x, y: x > y, + "minimum_ex": lambda x, y: x <= y, + "maximum_ex": lambda x, y: x >= y, + "min_items": lambda x, y: len(x) < y, + "max_items": lambda x, y: len(x) > y, + "pattern": lambda x, y: not re.match(y, x, re.UNICODE), + "unique": lambda x, y: len(x) != len(set(x)), + "multiple": lambda x, y: x % y != 0, + } + + def __init__(self, classes: Optional[Mapping[str, type]] = None) -> None: + self.serialize_type = { + "iso-8601": Serializer.serialize_iso, + "rfc-1123": Serializer.serialize_rfc, + "unix-time": Serializer.serialize_unix, + "duration": Serializer.serialize_duration, + "date": Serializer.serialize_date, + "time": Serializer.serialize_time, + "decimal": Serializer.serialize_decimal, + "long": Serializer.serialize_long, + "bytearray": Serializer.serialize_bytearray, + "base64": Serializer.serialize_base64, + "object": self.serialize_object, + "[]": self.serialize_iter, + "{}": self.serialize_dict, + } + self.dependencies: Dict[str, type] = dict(classes) if classes else {} + self.key_transformer = full_restapi_key_transformer + self.client_side_validation = True + + def _serialize( # pylint: disable=too-many-nested-blocks, too-many-branches, too-many-statements, too-many-locals + self, target_obj, data_type=None, **kwargs + ): + """Serialize data into a string according to type. + + :param object target_obj: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str, dict + :raises SerializationError: if serialization fails. + :returns: The serialized data. + """ + key_transformer = kwargs.get("key_transformer", self.key_transformer) + keep_readonly = kwargs.get("keep_readonly", False) + if target_obj is None: + return None + + attr_name = None + class_name = target_obj.__class__.__name__ + + if data_type: + return self.serialize_data(target_obj, data_type, **kwargs) + + if not hasattr(target_obj, "_attribute_map"): + data_type = type(target_obj).__name__ + if data_type in self.basic_types.values(): + return self.serialize_data(target_obj, data_type, **kwargs) + + # Force "is_xml" kwargs if we detect a XML model + try: + is_xml_model_serialization = kwargs["is_xml"] + except KeyError: + is_xml_model_serialization = kwargs.setdefault("is_xml", target_obj.is_xml_model()) + + serialized = {} + if is_xml_model_serialization: + serialized = target_obj._create_xml_node() # pylint: disable=protected-access + try: + attributes = target_obj._attribute_map # pylint: disable=protected-access + for attr, attr_desc in attributes.items(): + attr_name = attr + if not keep_readonly and target_obj._validation.get( # pylint: disable=protected-access + attr_name, {} + ).get("readonly", False): + continue + + if attr_name == "additional_properties" and attr_desc["key"] == "": + if target_obj.additional_properties is not None: + serialized.update(target_obj.additional_properties) + continue + try: + + orig_attr = getattr(target_obj, attr) + if is_xml_model_serialization: + pass # Don't provide "transformer" for XML for now. Keep "orig_attr" + else: # JSON + keys, orig_attr = key_transformer(attr, attr_desc.copy(), orig_attr) + keys = keys if isinstance(keys, list) else [keys] + + kwargs["serialization_ctxt"] = attr_desc + new_attr = self.serialize_data(orig_attr, attr_desc["type"], **kwargs) + + if is_xml_model_serialization: + xml_desc = attr_desc.get("xml", {}) + xml_name = xml_desc.get("name", attr_desc["key"]) + xml_prefix = xml_desc.get("prefix", None) + xml_ns = xml_desc.get("ns", None) + if xml_desc.get("attr", False): + if xml_ns: + ET.register_namespace(xml_prefix, xml_ns) + xml_name = "{{{}}}{}".format(xml_ns, xml_name) + serialized.set(xml_name, new_attr) # type: ignore + continue + if xml_desc.get("text", False): + serialized.text = new_attr # type: ignore + continue + if isinstance(new_attr, list): + serialized.extend(new_attr) # type: ignore + elif isinstance(new_attr, ET.Element): + # If the down XML has no XML/Name, + # we MUST replace the tag with the local tag. But keeping the namespaces. + if "name" not in getattr(orig_attr, "_xml_map", {}): + splitted_tag = new_attr.tag.split("}") + if len(splitted_tag) == 2: # Namespace + new_attr.tag = "}".join([splitted_tag[0], xml_name]) + else: + new_attr.tag = xml_name + serialized.append(new_attr) # type: ignore + else: # That's a basic type + # Integrate namespace if necessary + local_node = _create_xml_node(xml_name, xml_prefix, xml_ns) + local_node.text = str(new_attr) + serialized.append(local_node) # type: ignore + else: # JSON + for k in reversed(keys): # type: ignore + new_attr = {k: new_attr} + + _new_attr = new_attr + _serialized = serialized + for k in keys: # type: ignore + if k not in _serialized: + _serialized.update(_new_attr) # type: ignore + _new_attr = _new_attr[k] # type: ignore + _serialized = _serialized[k] + except ValueError as err: + if isinstance(err, SerializationError): + raise + + except (AttributeError, KeyError, TypeError) as err: + msg = "Attribute {} in object {} cannot be serialized.\n{}".format(attr_name, class_name, str(target_obj)) + raise SerializationError(msg) from err + return serialized + + def body(self, data, data_type, **kwargs): + """Serialize data intended for a request body. + + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: dict + :raises SerializationError: if serialization fails. + :raises ValueError: if data is None + :returns: The serialized request body + """ + + # Just in case this is a dict + internal_data_type_str = data_type.strip("[]{}") + internal_data_type = self.dependencies.get(internal_data_type_str, None) + try: + is_xml_model_serialization = kwargs["is_xml"] + except KeyError: + if internal_data_type and issubclass(internal_data_type, Model): + is_xml_model_serialization = kwargs.setdefault("is_xml", internal_data_type.is_xml_model()) + else: + is_xml_model_serialization = False + if internal_data_type and not isinstance(internal_data_type, Enum): + try: + deserializer = Deserializer(self.dependencies) + # Since it's on serialization, it's almost sure that format is not JSON REST + # We're not able to deal with additional properties for now. + deserializer.additional_properties_detection = False + if is_xml_model_serialization: + deserializer.key_extractors = [ # type: ignore + attribute_key_case_insensitive_extractor, + ] + else: + deserializer.key_extractors = [ + rest_key_case_insensitive_extractor, + attribute_key_case_insensitive_extractor, + last_rest_key_case_insensitive_extractor, + ] + data = deserializer._deserialize(data_type, data) # pylint: disable=protected-access + except DeserializationError as err: + raise SerializationError("Unable to build a model: " + str(err)) from err + + return self._serialize(data, data_type, **kwargs) + + def url(self, name, data, data_type, **kwargs): + """Serialize data intended for a URL path. + + :param str name: The name of the URL path parameter. + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str + :returns: The serialized URL path + :raises TypeError: if serialization fails. + :raises ValueError: if data is None + """ + try: + output = self.serialize_data(data, data_type, **kwargs) + if data_type == "bool": + output = json.dumps(output) + + if kwargs.get("skip_quote") is True: + output = str(output) + output = output.replace("{", quote("{")).replace("}", quote("}")) + else: + output = quote(str(output), safe="") + except SerializationError as exc: + raise TypeError("{} must be type {}.".format(name, data_type)) from exc + return output + + def query(self, name, data, data_type, **kwargs): + """Serialize data intended for a URL query. + + :param str name: The name of the query parameter. + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str, list + :raises TypeError: if serialization fails. + :raises ValueError: if data is None + :returns: The serialized query parameter + """ + try: + # Treat the list aside, since we don't want to encode the div separator + if data_type.startswith("["): + internal_data_type = data_type[1:-1] + do_quote = not kwargs.get("skip_quote", False) + return self.serialize_iter(data, internal_data_type, do_quote=do_quote, **kwargs) + + # Not a list, regular serialization + output = self.serialize_data(data, data_type, **kwargs) + if data_type == "bool": + output = json.dumps(output) + if kwargs.get("skip_quote") is True: + output = str(output) + else: + output = quote(str(output), safe="") + except SerializationError as exc: + raise TypeError("{} must be type {}.".format(name, data_type)) from exc + return str(output) + + def header(self, name, data, data_type, **kwargs): + """Serialize data intended for a request header. + + :param str name: The name of the header. + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str + :raises TypeError: if serialization fails. + :raises ValueError: if data is None + :returns: The serialized header + """ + try: + if data_type in ["[str]"]: + data = ["" if d is None else d for d in data] + + output = self.serialize_data(data, data_type, **kwargs) + if data_type == "bool": + output = json.dumps(output) + except SerializationError as exc: + raise TypeError("{} must be type {}.".format(name, data_type)) from exc + return str(output) + + def serialize_data(self, data, data_type, **kwargs): + """Serialize generic data according to supplied data type. + + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :raises AttributeError: if required data is None. + :raises ValueError: if data is None + :raises SerializationError: if serialization fails. + :returns: The serialized data. + :rtype: str, int, float, bool, dict, list + """ + if data is None: + raise ValueError("No value for given attribute") + + try: + if data is CoreNull: + return None + if data_type in self.basic_types.values(): + return self.serialize_basic(data, data_type, **kwargs) + + if data_type in self.serialize_type: + return self.serialize_type[data_type](data, **kwargs) + + # If dependencies is empty, try with current data class + # It has to be a subclass of Enum anyway + enum_type = self.dependencies.get(data_type, data.__class__) + if issubclass(enum_type, Enum): + return Serializer.serialize_enum(data, enum_obj=enum_type) + + iter_type = data_type[0] + data_type[-1] + if iter_type in self.serialize_type: + return self.serialize_type[iter_type](data, data_type[1:-1], **kwargs) + + except (ValueError, TypeError) as err: + msg = "Unable to serialize value: {!r} as type: {!r}." + raise SerializationError(msg.format(data, data_type)) from err + return self._serialize(data, **kwargs) + + @classmethod + def _get_custom_serializers(cls, data_type, **kwargs): # pylint: disable=inconsistent-return-statements + custom_serializer = kwargs.get("basic_types_serializers", {}).get(data_type) + if custom_serializer: + return custom_serializer + if kwargs.get("is_xml", False): + return cls._xml_basic_types_serializers.get(data_type) + + @classmethod + def serialize_basic(cls, data, data_type, **kwargs): + """Serialize basic builting data type. + Serializes objects to str, int, float or bool. + + Possible kwargs: + - basic_types_serializers dict[str, callable] : If set, use the callable as serializer + - is_xml bool : If set, use xml_basic_types_serializers + + :param obj data: Object to be serialized. + :param str data_type: Type of object in the iterable. + :rtype: str, int, float, bool + :return: serialized object + """ + custom_serializer = cls._get_custom_serializers(data_type, **kwargs) + if custom_serializer: + return custom_serializer(data) + if data_type == "str": + return cls.serialize_unicode(data) + return eval(data_type)(data) # nosec # pylint: disable=eval-used + + @classmethod + def serialize_unicode(cls, data): + """Special handling for serializing unicode strings in Py2. + Encode to UTF-8 if unicode, otherwise handle as a str. + + :param str data: Object to be serialized. + :rtype: str + :return: serialized object + """ + try: # If I received an enum, return its value + return data.value + except AttributeError: + pass + + try: + if isinstance(data, unicode): # type: ignore + # Don't change it, JSON and XML ElementTree are totally able + # to serialize correctly u'' strings + return data + except NameError: + return str(data) + return str(data) + + def serialize_iter(self, data, iter_type, div=None, **kwargs): + """Serialize iterable. + + Supported kwargs: + - serialization_ctxt dict : The current entry of _attribute_map, or same format. + serialization_ctxt['type'] should be same as data_type. + - is_xml bool : If set, serialize as XML + + :param list data: Object to be serialized. + :param str iter_type: Type of object in the iterable. + :param str div: If set, this str will be used to combine the elements + in the iterable into a combined string. Default is 'None'. + Defaults to False. + :rtype: list, str + :return: serialized iterable + """ + if isinstance(data, str): + raise SerializationError("Refuse str type as a valid iter type.") + + serialization_ctxt = kwargs.get("serialization_ctxt", {}) + is_xml = kwargs.get("is_xml", False) + + serialized = [] + for d in data: + try: + serialized.append(self.serialize_data(d, iter_type, **kwargs)) + except ValueError as err: + if isinstance(err, SerializationError): + raise + serialized.append(None) + + if kwargs.get("do_quote", False): + serialized = ["" if s is None else quote(str(s), safe="") for s in serialized] + + if div: + serialized = ["" if s is None else str(s) for s in serialized] + serialized = div.join(serialized) + + if "xml" in serialization_ctxt or is_xml: + # XML serialization is more complicated + xml_desc = serialization_ctxt.get("xml", {}) + xml_name = xml_desc.get("name") + if not xml_name: + xml_name = serialization_ctxt["key"] + + # Create a wrap node if necessary (use the fact that Element and list have "append") + is_wrapped = xml_desc.get("wrapped", False) + node_name = xml_desc.get("itemsName", xml_name) + if is_wrapped: + final_result = _create_xml_node(xml_name, xml_desc.get("prefix", None), xml_desc.get("ns", None)) + else: + final_result = [] + # All list elements to "local_node" + for el in serialized: + if isinstance(el, ET.Element): + el_node = el + else: + el_node = _create_xml_node(node_name, xml_desc.get("prefix", None), xml_desc.get("ns", None)) + if el is not None: # Otherwise it writes "None" :-p + el_node.text = str(el) + final_result.append(el_node) + return final_result + return serialized + + def serialize_dict(self, attr, dict_type, **kwargs): + """Serialize a dictionary of objects. + + :param dict attr: Object to be serialized. + :param str dict_type: Type of object in the dictionary. + :rtype: dict + :return: serialized dictionary + """ + serialization_ctxt = kwargs.get("serialization_ctxt", {}) + serialized = {} + for key, value in attr.items(): + try: + serialized[self.serialize_unicode(key)] = self.serialize_data(value, dict_type, **kwargs) + except ValueError as err: + if isinstance(err, SerializationError): + raise + serialized[self.serialize_unicode(key)] = None + + if "xml" in serialization_ctxt: + # XML serialization is more complicated + xml_desc = serialization_ctxt["xml"] + xml_name = xml_desc["name"] + + final_result = _create_xml_node(xml_name, xml_desc.get("prefix", None), xml_desc.get("ns", None)) + for key, value in serialized.items(): + ET.SubElement(final_result, key).text = value + return final_result + + return serialized + + def serialize_object(self, attr, **kwargs): # pylint: disable=too-many-return-statements + """Serialize a generic object. + This will be handled as a dictionary. If object passed in is not + a basic type (str, int, float, dict, list) it will simply be + cast to str. + + :param dict attr: Object to be serialized. + :rtype: dict or str + :return: serialized object + """ + if attr is None: + return None + if isinstance(attr, ET.Element): + return attr + obj_type = type(attr) + if obj_type in self.basic_types: + return self.serialize_basic(attr, self.basic_types[obj_type], **kwargs) + if obj_type is _long_type: + return self.serialize_long(attr) + if obj_type is str: + return self.serialize_unicode(attr) + if obj_type is datetime.datetime: + return self.serialize_iso(attr) + if obj_type is datetime.date: + return self.serialize_date(attr) + if obj_type is datetime.time: + return self.serialize_time(attr) + if obj_type is datetime.timedelta: + return self.serialize_duration(attr) + if obj_type is decimal.Decimal: + return self.serialize_decimal(attr) + + # If it's a model or I know this dependency, serialize as a Model + if obj_type in self.dependencies.values() or isinstance(attr, Model): + return self._serialize(attr) + + if obj_type == dict: + serialized = {} + for key, value in attr.items(): + try: + serialized[self.serialize_unicode(key)] = self.serialize_object(value, **kwargs) + except ValueError: + serialized[self.serialize_unicode(key)] = None + return serialized + + if obj_type == list: + serialized = [] + for obj in attr: + try: + serialized.append(self.serialize_object(obj, **kwargs)) + except ValueError: + pass + return serialized + return str(attr) + + @staticmethod + def serialize_enum(attr, enum_obj=None): + try: + result = attr.value + except AttributeError: + result = attr + try: + enum_obj(result) # type: ignore + return result + except ValueError as exc: + for enum_value in enum_obj: # type: ignore + if enum_value.value.lower() == str(attr).lower(): + return enum_value.value + error = "{!r} is not valid value for enum {!r}" + raise SerializationError(error.format(attr, enum_obj)) from exc + + @staticmethod + def serialize_bytearray(attr, **kwargs): # pylint: disable=unused-argument + """Serialize bytearray into base-64 string. + + :param str attr: Object to be serialized. + :rtype: str + :return: serialized base64 + """ + return b64encode(attr).decode() + + @staticmethod + def serialize_base64(attr, **kwargs): # pylint: disable=unused-argument + """Serialize str into base-64 string. + + :param str attr: Object to be serialized. + :rtype: str + :return: serialized base64 + """ + encoded = b64encode(attr).decode("ascii") + return encoded.strip("=").replace("+", "-").replace("/", "_") + + @staticmethod + def serialize_decimal(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Decimal object to float. + + :param decimal attr: Object to be serialized. + :rtype: float + :return: serialized decimal + """ + return float(attr) + + @staticmethod + def serialize_long(attr, **kwargs): # pylint: disable=unused-argument + """Serialize long (Py2) or int (Py3). + + :param int attr: Object to be serialized. + :rtype: int/long + :return: serialized long + """ + return _long_type(attr) + + @staticmethod + def serialize_date(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Date object into ISO-8601 formatted string. + + :param Date attr: Object to be serialized. + :rtype: str + :return: serialized date + """ + if isinstance(attr, str): + attr = isodate.parse_date(attr) + t = "{:04}-{:02}-{:02}".format(attr.year, attr.month, attr.day) + return t + + @staticmethod + def serialize_time(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Time object into ISO-8601 formatted string. + + :param datetime.time attr: Object to be serialized. + :rtype: str + :return: serialized time + """ + if isinstance(attr, str): + attr = isodate.parse_time(attr) + t = "{:02}:{:02}:{:02}".format(attr.hour, attr.minute, attr.second) + if attr.microsecond: + t += ".{:02}".format(attr.microsecond) + return t + + @staticmethod + def serialize_duration(attr, **kwargs): # pylint: disable=unused-argument + """Serialize TimeDelta object into ISO-8601 formatted string. + + :param TimeDelta attr: Object to be serialized. + :rtype: str + :return: serialized duration + """ + if isinstance(attr, str): + attr = isodate.parse_duration(attr) + return isodate.duration_isoformat(attr) + + @staticmethod + def serialize_rfc(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Datetime object into RFC-1123 formatted string. + + :param Datetime attr: Object to be serialized. + :rtype: str + :raises TypeError: if format invalid. + :return: serialized rfc + """ + try: + if not attr.tzinfo: + _LOGGER.warning("Datetime with no tzinfo will be considered UTC.") + utc = attr.utctimetuple() + except AttributeError as exc: + raise TypeError("RFC1123 object must be valid Datetime object.") from exc + + return "{}, {:02} {} {:04} {:02}:{:02}:{:02} GMT".format( + Serializer.days[utc.tm_wday], + utc.tm_mday, + Serializer.months[utc.tm_mon], + utc.tm_year, + utc.tm_hour, + utc.tm_min, + utc.tm_sec, + ) + + @staticmethod + def serialize_iso(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Datetime object into ISO-8601 formatted string. + + :param Datetime attr: Object to be serialized. + :rtype: str + :raises SerializationError: if format invalid. + :return: serialized iso + """ + if isinstance(attr, str): + attr = isodate.parse_datetime(attr) + try: + if not attr.tzinfo: + _LOGGER.warning("Datetime with no tzinfo will be considered UTC.") + utc = attr.utctimetuple() + if utc.tm_year > 9999 or utc.tm_year < 1: + raise OverflowError("Hit max or min date") + + microseconds = str(attr.microsecond).rjust(6, "0").rstrip("0").ljust(3, "0") + if microseconds: + microseconds = "." + microseconds + date = "{:04}-{:02}-{:02}T{:02}:{:02}:{:02}".format( + utc.tm_year, utc.tm_mon, utc.tm_mday, utc.tm_hour, utc.tm_min, utc.tm_sec + ) + return date + microseconds + "Z" + except (ValueError, OverflowError) as err: + msg = "Unable to serialize datetime object." + raise SerializationError(msg) from err + except AttributeError as err: + msg = "ISO-8601 object must be valid Datetime object." + raise TypeError(msg) from err + + @staticmethod + def serialize_unix(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Datetime object into IntTime format. + This is represented as seconds. + + :param Datetime attr: Object to be serialized. + :rtype: int + :raises SerializationError: if format invalid + :return: serialied unix + """ + if isinstance(attr, int): + return attr + try: + if not attr.tzinfo: + _LOGGER.warning("Datetime with no tzinfo will be considered UTC.") + return int(calendar.timegm(attr.utctimetuple())) + except AttributeError as exc: + raise TypeError("Unix time object must be valid Datetime object.") from exc + + +def rest_key_extractor(attr, attr_desc, data): # pylint: disable=unused-argument + key = attr_desc["key"] + working_data = data + + while "." in key: + # Need the cast, as for some reasons "split" is typed as list[str | Any] + dict_keys = cast(List[str], _FLATTEN.split(key)) + if len(dict_keys) == 1: + key = _decode_attribute_map_key(dict_keys[0]) + break + working_key = _decode_attribute_map_key(dict_keys[0]) + working_data = working_data.get(working_key, data) + if working_data is None: + # If at any point while following flatten JSON path see None, it means + # that all properties under are None as well + return None + key = ".".join(dict_keys[1:]) + + return working_data.get(key) + + +def rest_key_case_insensitive_extractor( # pylint: disable=unused-argument, inconsistent-return-statements + attr, attr_desc, data +): + key = attr_desc["key"] + working_data = data + + while "." in key: + dict_keys = _FLATTEN.split(key) + if len(dict_keys) == 1: + key = _decode_attribute_map_key(dict_keys[0]) + break + working_key = _decode_attribute_map_key(dict_keys[0]) + working_data = attribute_key_case_insensitive_extractor(working_key, None, working_data) + if working_data is None: + # If at any point while following flatten JSON path see None, it means + # that all properties under are None as well + return None + key = ".".join(dict_keys[1:]) + + if working_data: + return attribute_key_case_insensitive_extractor(key, None, working_data) + + +def last_rest_key_extractor(attr, attr_desc, data): # pylint: disable=unused-argument + """Extract the attribute in "data" based on the last part of the JSON path key. + + :param str attr: The attribute to extract + :param dict attr_desc: The attribute description + :param dict data: The data to extract from + :rtype: object + :returns: The extracted attribute + """ + key = attr_desc["key"] + dict_keys = _FLATTEN.split(key) + return attribute_key_extractor(dict_keys[-1], None, data) + + +def last_rest_key_case_insensitive_extractor(attr, attr_desc, data): # pylint: disable=unused-argument + """Extract the attribute in "data" based on the last part of the JSON path key. + + This is the case insensitive version of "last_rest_key_extractor" + :param str attr: The attribute to extract + :param dict attr_desc: The attribute description + :param dict data: The data to extract from + :rtype: object + :returns: The extracted attribute + """ + key = attr_desc["key"] + dict_keys = _FLATTEN.split(key) + return attribute_key_case_insensitive_extractor(dict_keys[-1], None, data) + + +def attribute_key_extractor(attr, _, data): + return data.get(attr) + + +def attribute_key_case_insensitive_extractor(attr, _, data): + found_key = None + lower_attr = attr.lower() + for key in data: + if lower_attr == key.lower(): + found_key = key + break + + return data.get(found_key) + + +def _extract_name_from_internal_type(internal_type): + """Given an internal type XML description, extract correct XML name with namespace. + + :param dict internal_type: An model type + :rtype: tuple + :returns: A tuple XML name + namespace dict + """ + internal_type_xml_map = getattr(internal_type, "_xml_map", {}) + xml_name = internal_type_xml_map.get("name", internal_type.__name__) + xml_ns = internal_type_xml_map.get("ns", None) + if xml_ns: + xml_name = "{{{}}}{}".format(xml_ns, xml_name) + return xml_name + + +def xml_key_extractor(attr, attr_desc, data): # pylint: disable=unused-argument,too-many-return-statements + if isinstance(data, dict): + return None + + # Test if this model is XML ready first + if not isinstance(data, ET.Element): + return None + + xml_desc = attr_desc.get("xml", {}) + xml_name = xml_desc.get("name", attr_desc["key"]) + + # Look for a children + is_iter_type = attr_desc["type"].startswith("[") + is_wrapped = xml_desc.get("wrapped", False) + internal_type = attr_desc.get("internalType", None) + internal_type_xml_map = getattr(internal_type, "_xml_map", {}) + + # Integrate namespace if necessary + xml_ns = xml_desc.get("ns", internal_type_xml_map.get("ns", None)) + if xml_ns: + xml_name = "{{{}}}{}".format(xml_ns, xml_name) + + # If it's an attribute, that's simple + if xml_desc.get("attr", False): + return data.get(xml_name) + + # If it's x-ms-text, that's simple too + if xml_desc.get("text", False): + return data.text + + # Scenario where I take the local name: + # - Wrapped node + # - Internal type is an enum (considered basic types) + # - Internal type has no XML/Name node + if is_wrapped or (internal_type and (issubclass(internal_type, Enum) or "name" not in internal_type_xml_map)): + children = data.findall(xml_name) + # If internal type has a local name and it's not a list, I use that name + elif not is_iter_type and internal_type and "name" in internal_type_xml_map: + xml_name = _extract_name_from_internal_type(internal_type) + children = data.findall(xml_name) + # That's an array + else: + if internal_type: # Complex type, ignore itemsName and use the complex type name + items_name = _extract_name_from_internal_type(internal_type) + else: + items_name = xml_desc.get("itemsName", xml_name) + children = data.findall(items_name) + + if len(children) == 0: + if is_iter_type: + if is_wrapped: + return None # is_wrapped no node, we want None + return [] # not wrapped, assume empty list + return None # Assume it's not there, maybe an optional node. + + # If is_iter_type and not wrapped, return all found children + if is_iter_type: + if not is_wrapped: + return children + # Iter and wrapped, should have found one node only (the wrap one) + if len(children) != 1: + raise DeserializationError( + "Tried to deserialize an array not wrapped, and found several nodes '{}'. Maybe you should declare this array as wrapped?".format( + xml_name + ) + ) + return list(children[0]) # Might be empty list and that's ok. + + # Here it's not a itertype, we should have found one element only or empty + if len(children) > 1: + raise DeserializationError("Find several XML '{}' where it was not expected".format(xml_name)) + return children[0] + + +class Deserializer: + """Response object model deserializer. + + :param dict classes: Class type dictionary for deserializing complex types. + :ivar list key_extractors: Ordered list of extractors to be used by this deserializer. + """ + + basic_types = {str: "str", int: "int", bool: "bool", float: "float"} + + valid_date = re.compile(r"\d{4}[-]\d{2}[-]\d{2}T\d{2}:\d{2}:\d{2}\.?\d*Z?[-+]?[\d{2}]?:?[\d{2}]?") + + def __init__(self, classes: Optional[Mapping[str, type]] = None) -> None: + self.deserialize_type = { + "iso-8601": Deserializer.deserialize_iso, + "rfc-1123": Deserializer.deserialize_rfc, + "unix-time": Deserializer.deserialize_unix, + "duration": Deserializer.deserialize_duration, + "date": Deserializer.deserialize_date, + "time": Deserializer.deserialize_time, + "decimal": Deserializer.deserialize_decimal, + "long": Deserializer.deserialize_long, + "bytearray": Deserializer.deserialize_bytearray, + "base64": Deserializer.deserialize_base64, + "object": self.deserialize_object, + "[]": self.deserialize_iter, + "{}": self.deserialize_dict, + } + self.deserialize_expected_types = { + "duration": (isodate.Duration, datetime.timedelta), + "iso-8601": (datetime.datetime), + } + self.dependencies: Dict[str, type] = dict(classes) if classes else {} + self.key_extractors = [rest_key_extractor, xml_key_extractor] + # Additional properties only works if the "rest_key_extractor" is used to + # extract the keys. Making it to work whatever the key extractor is too much + # complicated, with no real scenario for now. + # So adding a flag to disable additional properties detection. This flag should be + # used if your expect the deserialization to NOT come from a JSON REST syntax. + # Otherwise, result are unexpected + self.additional_properties_detection = True + + def __call__(self, target_obj, response_data, content_type=None): + """Call the deserializer to process a REST response. + + :param str target_obj: Target data type to deserialize to. + :param requests.Response response_data: REST response object. + :param str content_type: Swagger "produces" if available. + :raises DeserializationError: if deserialization fails. + :return: Deserialized object. + :rtype: object + """ + data = self._unpack_content(response_data, content_type) + return self._deserialize(target_obj, data) + + def _deserialize(self, target_obj, data): # pylint: disable=inconsistent-return-statements + """Call the deserializer on a model. + + Data needs to be already deserialized as JSON or XML ElementTree + + :param str target_obj: Target data type to deserialize to. + :param object data: Object to deserialize. + :raises DeserializationError: if deserialization fails. + :return: Deserialized object. + :rtype: object + """ + # This is already a model, go recursive just in case + if hasattr(data, "_attribute_map"): + constants = [name for name, config in getattr(data, "_validation", {}).items() if config.get("constant")] + try: + for attr, mapconfig in data._attribute_map.items(): # pylint: disable=protected-access + if attr in constants: + continue + value = getattr(data, attr) + if value is None: + continue + local_type = mapconfig["type"] + internal_data_type = local_type.strip("[]{}") + if internal_data_type not in self.dependencies or isinstance(internal_data_type, Enum): + continue + setattr(data, attr, self._deserialize(local_type, value)) + return data + except AttributeError: + return + + response, class_name = self._classify_target(target_obj, data) + + if isinstance(response, str): + return self.deserialize_data(data, response) + if isinstance(response, type) and issubclass(response, Enum): + return self.deserialize_enum(data, response) + + if data is None or data is CoreNull: + return data + try: + attributes = response._attribute_map # type: ignore # pylint: disable=protected-access + d_attrs = {} + for attr, attr_desc in attributes.items(): + # Check empty string. If it's not empty, someone has a real "additionalProperties"... + if attr == "additional_properties" and attr_desc["key"] == "": + continue + raw_value = None + # Enhance attr_desc with some dynamic data + attr_desc = attr_desc.copy() # Do a copy, do not change the real one + internal_data_type = attr_desc["type"].strip("[]{}") + if internal_data_type in self.dependencies: + attr_desc["internalType"] = self.dependencies[internal_data_type] + + for key_extractor in self.key_extractors: + found_value = key_extractor(attr, attr_desc, data) + if found_value is not None: + if raw_value is not None and raw_value != found_value: + msg = ( + "Ignoring extracted value '%s' from %s for key '%s'" + " (duplicate extraction, follow extractors order)" + ) + _LOGGER.warning(msg, found_value, key_extractor, attr) + continue + raw_value = found_value + + value = self.deserialize_data(raw_value, attr_desc["type"]) + d_attrs[attr] = value + except (AttributeError, TypeError, KeyError) as err: + msg = "Unable to deserialize to object: " + class_name # type: ignore + raise DeserializationError(msg) from err + additional_properties = self._build_additional_properties(attributes, data) + return self._instantiate_model(response, d_attrs, additional_properties) + + def _build_additional_properties(self, attribute_map, data): + if not self.additional_properties_detection: + return None + if "additional_properties" in attribute_map and attribute_map.get("additional_properties", {}).get("key") != "": + # Check empty string. If it's not empty, someone has a real "additionalProperties" + return None + if isinstance(data, ET.Element): + data = {el.tag: el.text for el in data} + + known_keys = { + _decode_attribute_map_key(_FLATTEN.split(desc["key"])[0]) + for desc in attribute_map.values() + if desc["key"] != "" + } + present_keys = set(data.keys()) + missing_keys = present_keys - known_keys + return {key: data[key] for key in missing_keys} + + def _classify_target(self, target, data): + """Check to see whether the deserialization target object can + be classified into a subclass. + Once classification has been determined, initialize object. + + :param str target: The target object type to deserialize to. + :param str/dict data: The response data to deserialize. + :return: The classified target object and its class name. + :rtype: tuple + """ + if target is None: + return None, None + + if isinstance(target, str): + try: + target = self.dependencies[target] + except KeyError: + return target, target + + try: + target = target._classify(data, self.dependencies) # type: ignore # pylint: disable=protected-access + except AttributeError: + pass # Target is not a Model, no classify + return target, target.__class__.__name__ # type: ignore + + def failsafe_deserialize(self, target_obj, data, content_type=None): + """Ignores any errors encountered in deserialization, + and falls back to not deserializing the object. Recommended + for use in error deserialization, as we want to return the + HttpResponseError to users, and not have them deal with + a deserialization error. + + :param str target_obj: The target object type to deserialize to. + :param str/dict data: The response data to deserialize. + :param str content_type: Swagger "produces" if available. + :return: Deserialized object. + :rtype: object + """ + try: + return self(target_obj, data, content_type=content_type) + except: # pylint: disable=bare-except + _LOGGER.debug( + "Ran into a deserialization error. Ignoring since this is failsafe deserialization", exc_info=True + ) + return None + + @staticmethod + def _unpack_content(raw_data, content_type=None): + """Extract the correct structure for deserialization. + + If raw_data is a PipelineResponse, try to extract the result of RawDeserializer. + if we can't, raise. Your Pipeline should have a RawDeserializer. + + If not a pipeline response and raw_data is bytes or string, use content-type + to decode it. If no content-type, try JSON. + + If raw_data is something else, bypass all logic and return it directly. + + :param obj raw_data: Data to be processed. + :param str content_type: How to parse if raw_data is a string/bytes. + :raises JSONDecodeError: If JSON is requested and parsing is impossible. + :raises UnicodeDecodeError: If bytes is not UTF8 + :rtype: object + :return: Unpacked content. + """ + # Assume this is enough to detect a Pipeline Response without importing it + context = getattr(raw_data, "context", {}) + if context: + if RawDeserializer.CONTEXT_NAME in context: + return context[RawDeserializer.CONTEXT_NAME] + raise ValueError("This pipeline didn't have the RawDeserializer policy; can't deserialize") + + # Assume this is enough to recognize universal_http.ClientResponse without importing it + if hasattr(raw_data, "body"): + return RawDeserializer.deserialize_from_http_generics(raw_data.text(), raw_data.headers) + + # Assume this enough to recognize requests.Response without importing it. + if hasattr(raw_data, "_content_consumed"): + return RawDeserializer.deserialize_from_http_generics(raw_data.text, raw_data.headers) + + if isinstance(raw_data, (str, bytes)) or hasattr(raw_data, "read"): + return RawDeserializer.deserialize_from_text(raw_data, content_type) # type: ignore + return raw_data + + def _instantiate_model(self, response, attrs, additional_properties=None): + """Instantiate a response model passing in deserialized args. + + :param Response response: The response model class. + :param dict attrs: The deserialized response attributes. + :param dict additional_properties: Additional properties to be set. + :rtype: Response + :return: The instantiated response model. + """ + if callable(response): + subtype = getattr(response, "_subtype_map", {}) + try: + readonly = [ + k + for k, v in response._validation.items() # pylint: disable=protected-access # type: ignore + if v.get("readonly") + ] + const = [ + k + for k, v in response._validation.items() # pylint: disable=protected-access # type: ignore + if v.get("constant") + ] + kwargs = {k: v for k, v in attrs.items() if k not in subtype and k not in readonly + const} + response_obj = response(**kwargs) + for attr in readonly: + setattr(response_obj, attr, attrs.get(attr)) + if additional_properties: + response_obj.additional_properties = additional_properties # type: ignore + return response_obj + except TypeError as err: + msg = "Unable to deserialize {} into model {}. ".format(kwargs, response) # type: ignore + raise DeserializationError(msg + str(err)) from err + else: + try: + for attr, value in attrs.items(): + setattr(response, attr, value) + return response + except Exception as exp: + msg = "Unable to populate response model. " + msg += "Type: {}, Error: {}".format(type(response), exp) + raise DeserializationError(msg) from exp + + def deserialize_data(self, data, data_type): # pylint: disable=too-many-return-statements + """Process data for deserialization according to data type. + + :param str data: The response string to be deserialized. + :param str data_type: The type to deserialize to. + :raises DeserializationError: if deserialization fails. + :return: Deserialized object. + :rtype: object + """ + if data is None: + return data + + try: + if not data_type: + return data + if data_type in self.basic_types.values(): + return self.deserialize_basic(data, data_type) + if data_type in self.deserialize_type: + if isinstance(data, self.deserialize_expected_types.get(data_type, tuple())): + return data + + is_a_text_parsing_type = lambda x: x not in [ # pylint: disable=unnecessary-lambda-assignment + "object", + "[]", + r"{}", + ] + if isinstance(data, ET.Element) and is_a_text_parsing_type(data_type) and not data.text: + return None + data_val = self.deserialize_type[data_type](data) + return data_val + + iter_type = data_type[0] + data_type[-1] + if iter_type in self.deserialize_type: + return self.deserialize_type[iter_type](data, data_type[1:-1]) + + obj_type = self.dependencies[data_type] + if issubclass(obj_type, Enum): + if isinstance(data, ET.Element): + data = data.text + return self.deserialize_enum(data, obj_type) + + except (ValueError, TypeError, AttributeError) as err: + msg = "Unable to deserialize response data." + msg += " Data: {}, {}".format(data, data_type) + raise DeserializationError(msg) from err + return self._deserialize(obj_type, data) + + def deserialize_iter(self, attr, iter_type): + """Deserialize an iterable. + + :param list attr: Iterable to be deserialized. + :param str iter_type: The type of object in the iterable. + :return: Deserialized iterable. + :rtype: list + """ + if attr is None: + return None + if isinstance(attr, ET.Element): # If I receive an element here, get the children + attr = list(attr) + if not isinstance(attr, (list, set)): + raise DeserializationError("Cannot deserialize as [{}] an object of type {}".format(iter_type, type(attr))) + return [self.deserialize_data(a, iter_type) for a in attr] + + def deserialize_dict(self, attr, dict_type): + """Deserialize a dictionary. + + :param dict/list attr: Dictionary to be deserialized. Also accepts + a list of key, value pairs. + :param str dict_type: The object type of the items in the dictionary. + :return: Deserialized dictionary. + :rtype: dict + """ + if isinstance(attr, list): + return {x["key"]: self.deserialize_data(x["value"], dict_type) for x in attr} + + if isinstance(attr, ET.Element): + # Transform value into {"Key": "value"} + attr = {el.tag: el.text for el in attr} + return {k: self.deserialize_data(v, dict_type) for k, v in attr.items()} + + def deserialize_object(self, attr, **kwargs): # pylint: disable=too-many-return-statements + """Deserialize a generic object. + This will be handled as a dictionary. + + :param dict attr: Dictionary to be deserialized. + :return: Deserialized object. + :rtype: dict + :raises TypeError: if non-builtin datatype encountered. + """ + if attr is None: + return None + if isinstance(attr, ET.Element): + # Do no recurse on XML, just return the tree as-is + return attr + if isinstance(attr, str): + return self.deserialize_basic(attr, "str") + obj_type = type(attr) + if obj_type in self.basic_types: + return self.deserialize_basic(attr, self.basic_types[obj_type]) + if obj_type is _long_type: + return self.deserialize_long(attr) + + if obj_type == dict: + deserialized = {} + for key, value in attr.items(): + try: + deserialized[key] = self.deserialize_object(value, **kwargs) + except ValueError: + deserialized[key] = None + return deserialized + + if obj_type == list: + deserialized = [] + for obj in attr: + try: + deserialized.append(self.deserialize_object(obj, **kwargs)) + except ValueError: + pass + return deserialized + + error = "Cannot deserialize generic object with type: " + raise TypeError(error + str(obj_type)) + + def deserialize_basic(self, attr, data_type): # pylint: disable=too-many-return-statements + """Deserialize basic builtin data type from string. + Will attempt to convert to str, int, float and bool. + This function will also accept '1', '0', 'true' and 'false' as + valid bool values. + + :param str attr: response string to be deserialized. + :param str data_type: deserialization data type. + :return: Deserialized basic type. + :rtype: str, int, float or bool + :raises TypeError: if string format is not valid. + """ + # If we're here, data is supposed to be a basic type. + # If it's still an XML node, take the text + if isinstance(attr, ET.Element): + attr = attr.text + if not attr: + if data_type == "str": + # None or '', node is empty string. + return "" + # None or '', node with a strong type is None. + # Don't try to model "empty bool" or "empty int" + return None + + if data_type == "bool": + if attr in [True, False, 1, 0]: + return bool(attr) + if isinstance(attr, str): + if attr.lower() in ["true", "1"]: + return True + if attr.lower() in ["false", "0"]: + return False + raise TypeError("Invalid boolean value: {}".format(attr)) + + if data_type == "str": + return self.deserialize_unicode(attr) + return eval(data_type)(attr) # nosec # pylint: disable=eval-used + + @staticmethod + def deserialize_unicode(data): + """Preserve unicode objects in Python 2, otherwise return data + as a string. + + :param str data: response string to be deserialized. + :return: Deserialized string. + :rtype: str or unicode + """ + # We might be here because we have an enum modeled as string, + # and we try to deserialize a partial dict with enum inside + if isinstance(data, Enum): + return data + + # Consider this is real string + try: + if isinstance(data, unicode): # type: ignore + return data + except NameError: + return str(data) + return str(data) + + @staticmethod + def deserialize_enum(data, enum_obj): + """Deserialize string into enum object. + + If the string is not a valid enum value it will be returned as-is + and a warning will be logged. + + :param str data: Response string to be deserialized. If this value is + None or invalid it will be returned as-is. + :param Enum enum_obj: Enum object to deserialize to. + :return: Deserialized enum object. + :rtype: Enum + """ + if isinstance(data, enum_obj) or data is None: + return data + if isinstance(data, Enum): + data = data.value + if isinstance(data, int): + # Workaround. We might consider remove it in the future. + try: + return list(enum_obj.__members__.values())[data] + except IndexError as exc: + error = "{!r} is not a valid index for enum {!r}" + raise DeserializationError(error.format(data, enum_obj)) from exc + try: + return enum_obj(str(data)) + except ValueError: + for enum_value in enum_obj: + if enum_value.value.lower() == str(data).lower(): + return enum_value + # We don't fail anymore for unknown value, we deserialize as a string + _LOGGER.warning("Deserializer is not able to find %s as valid enum in %s", data, enum_obj) + return Deserializer.deserialize_unicode(data) + + @staticmethod + def deserialize_bytearray(attr): + """Deserialize string into bytearray. + + :param str attr: response string to be deserialized. + :return: Deserialized bytearray + :rtype: bytearray + :raises TypeError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + return bytearray(b64decode(attr)) # type: ignore + + @staticmethod + def deserialize_base64(attr): + """Deserialize base64 encoded string into string. + + :param str attr: response string to be deserialized. + :return: Deserialized base64 string + :rtype: bytearray + :raises TypeError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + padding = "=" * (3 - (len(attr) + 3) % 4) # type: ignore + attr = attr + padding # type: ignore + encoded = attr.replace("-", "+").replace("_", "/") + return b64decode(encoded) + + @staticmethod + def deserialize_decimal(attr): + """Deserialize string into Decimal object. + + :param str attr: response string to be deserialized. + :return: Deserialized decimal + :raises DeserializationError: if string format invalid. + :rtype: decimal + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + return decimal.Decimal(str(attr)) # type: ignore + except decimal.DecimalException as err: + msg = "Invalid decimal {}".format(attr) + raise DeserializationError(msg) from err + + @staticmethod + def deserialize_long(attr): + """Deserialize string into long (Py2) or int (Py3). + + :param str attr: response string to be deserialized. + :return: Deserialized int + :rtype: long or int + :raises ValueError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + return _long_type(attr) # type: ignore + + @staticmethod + def deserialize_duration(attr): + """Deserialize ISO-8601 formatted string into TimeDelta object. + + :param str attr: response string to be deserialized. + :return: Deserialized duration + :rtype: TimeDelta + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + duration = isodate.parse_duration(attr) + except (ValueError, OverflowError, AttributeError) as err: + msg = "Cannot deserialize duration object." + raise DeserializationError(msg) from err + return duration + + @staticmethod + def deserialize_date(attr): + """Deserialize ISO-8601 formatted string into Date object. + + :param str attr: response string to be deserialized. + :return: Deserialized date + :rtype: Date + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + if re.search(r"[^\W\d_]", attr, re.I + re.U): # type: ignore + raise DeserializationError("Date must have only digits and -. Received: %s" % attr) + # This must NOT use defaultmonth/defaultday. Using None ensure this raises an exception. + return isodate.parse_date(attr, defaultmonth=0, defaultday=0) + + @staticmethod + def deserialize_time(attr): + """Deserialize ISO-8601 formatted string into time object. + + :param str attr: response string to be deserialized. + :return: Deserialized time + :rtype: datetime.time + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + if re.search(r"[^\W\d_]", attr, re.I + re.U): # type: ignore + raise DeserializationError("Date must have only digits and -. Received: %s" % attr) + return isodate.parse_time(attr) + + @staticmethod + def deserialize_rfc(attr): + """Deserialize RFC-1123 formatted string into Datetime object. + + :param str attr: response string to be deserialized. + :return: Deserialized RFC datetime + :rtype: Datetime + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + parsed_date = email.utils.parsedate_tz(attr) # type: ignore + date_obj = datetime.datetime( + *parsed_date[:6], tzinfo=datetime.timezone(datetime.timedelta(minutes=(parsed_date[9] or 0) / 60)) + ) + if not date_obj.tzinfo: + date_obj = date_obj.astimezone(tz=TZ_UTC) + except ValueError as err: + msg = "Cannot deserialize to rfc datetime object." + raise DeserializationError(msg) from err + return date_obj + + @staticmethod + def deserialize_iso(attr): + """Deserialize ISO-8601 formatted string into Datetime object. + + :param str attr: response string to be deserialized. + :return: Deserialized ISO datetime + :rtype: Datetime + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + attr = attr.upper() # type: ignore + match = Deserializer.valid_date.match(attr) + if not match: + raise ValueError("Invalid datetime string: " + attr) + + check_decimal = attr.split(".") + if len(check_decimal) > 1: + decimal_str = "" + for digit in check_decimal[1]: + if digit.isdigit(): + decimal_str += digit + else: + break + if len(decimal_str) > 6: + attr = attr.replace(decimal_str, decimal_str[0:6]) + + date_obj = isodate.parse_datetime(attr) + test_utc = date_obj.utctimetuple() + if test_utc.tm_year > 9999 or test_utc.tm_year < 1: + raise OverflowError("Hit max or min date") + except (ValueError, OverflowError, AttributeError) as err: + msg = "Cannot deserialize datetime object." + raise DeserializationError(msg) from err + return date_obj + + @staticmethod + def deserialize_unix(attr): + """Serialize Datetime object into IntTime format. + This is represented as seconds. + + :param int attr: Object to be serialized. + :return: Deserialized datetime + :rtype: Datetime + :raises DeserializationError: if format invalid + """ + if isinstance(attr, ET.Element): + attr = int(attr.text) # type: ignore + try: + attr = int(attr) + date_obj = datetime.datetime.fromtimestamp(attr, TZ_UTC) + except ValueError as err: + msg = "Cannot deserialize to unix datetime object." + raise DeserializationError(msg) from err + return date_obj diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyDictionaryVersionTolerant/bodydictionaryversiontolerant/aio/_client.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyDictionaryVersionTolerant/bodydictionaryversiontolerant/aio/_client.py index 58fcfc685ae..04e0cb0ea05 100644 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyDictionaryVersionTolerant/bodydictionaryversiontolerant/aio/_client.py +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyDictionaryVersionTolerant/bodydictionaryversiontolerant/aio/_client.py @@ -14,7 +14,7 @@ from azure.core.pipeline import policies from azure.core.rest import AsyncHttpResponse, HttpRequest -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import AutoRestSwaggerBATDictionaryServiceConfiguration from .operations import DictionaryOperations diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyDictionaryVersionTolerant/bodydictionaryversiontolerant/aio/operations/_operations.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyDictionaryVersionTolerant/bodydictionaryversiontolerant/aio/operations/_operations.py index 9a588975eb5..1f76bd2990f 100644 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyDictionaryVersionTolerant/bodydictionaryversiontolerant/aio/operations/_operations.py +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyDictionaryVersionTolerant/bodydictionaryversiontolerant/aio/operations/_operations.py @@ -25,7 +25,7 @@ from azure.core.tracing.decorator_async import distributed_trace_async from azure.core.utils import case_insensitive_dict -from ..._serialization import Deserializer, Serializer +from ..._utils.serialization import Deserializer, Serializer from ...operations._operations import ( build_dictionary_get_array_empty_request, build_dictionary_get_array_item_empty_request, diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyDictionaryVersionTolerant/bodydictionaryversiontolerant/operations/_operations.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyDictionaryVersionTolerant/bodydictionaryversiontolerant/operations/_operations.py index bf0680a3088..cdce9d5f6c7 100644 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyDictionaryVersionTolerant/bodydictionaryversiontolerant/operations/_operations.py +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyDictionaryVersionTolerant/bodydictionaryversiontolerant/operations/_operations.py @@ -26,7 +26,7 @@ from azure.core.utils import case_insensitive_dict from .._configuration import AutoRestSwaggerBATDictionaryServiceConfiguration -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer JSON = MutableMapping[str, Any] T = TypeVar("T") diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyDurationVersionTolerant/bodydurationversiontolerant/_client.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyDurationVersionTolerant/bodydurationversiontolerant/_client.py index 66012287aa9..d9386eec17a 100644 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyDurationVersionTolerant/bodydurationversiontolerant/_client.py +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyDurationVersionTolerant/bodydurationversiontolerant/_client.py @@ -15,7 +15,7 @@ from azure.core.rest import HttpRequest, HttpResponse from ._configuration import AutoRestDurationTestServiceConfiguration -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer from .operations import DurationOperations diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyDurationVersionTolerant/bodydurationversiontolerant/_utils/__init__.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyDurationVersionTolerant/bodydurationversiontolerant/_utils/__init__.py new file mode 100644 index 00000000000..0af9b28f660 --- /dev/null +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyDurationVersionTolerant/bodydurationversiontolerant/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyDurationVersionTolerant/bodydurationversiontolerant/_utils/serialization.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyDurationVersionTolerant/bodydurationversiontolerant/_utils/serialization.py new file mode 100644 index 00000000000..f5187701d7b --- /dev/null +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyDurationVersionTolerant/bodydurationversiontolerant/_utils/serialization.py @@ -0,0 +1,2032 @@ +# pylint: disable=line-too-long,useless-suppression,too-many-lines +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +# pyright: reportUnnecessaryTypeIgnoreComment=false + +from base64 import b64decode, b64encode +import calendar +import datetime +import decimal +import email +from enum import Enum +import json +import logging +import re +import sys +import codecs +from typing import ( + Dict, + Any, + cast, + Optional, + Union, + AnyStr, + IO, + Mapping, + Callable, + MutableMapping, + List, +) + +try: + from urllib import quote # type: ignore +except ImportError: + from urllib.parse import quote +import xml.etree.ElementTree as ET + +import isodate # type: ignore +from typing_extensions import Self + +from azure.core.exceptions import DeserializationError, SerializationError +from azure.core.serialization import NULL as CoreNull + +_BOM = codecs.BOM_UTF8.decode(encoding="utf-8") + +JSON = MutableMapping[str, Any] + + +class RawDeserializer: + + # Accept "text" because we're open minded people... + JSON_REGEXP = re.compile(r"^(application|text)/([a-z+.]+\+)?json$") + + # Name used in context + CONTEXT_NAME = "deserialized_data" + + @classmethod + def deserialize_from_text(cls, data: Optional[Union[AnyStr, IO]], content_type: Optional[str] = None) -> Any: + """Decode data according to content-type. + + Accept a stream of data as well, but will be load at once in memory for now. + + If no content-type, will return the string version (not bytes, not stream) + + :param data: Input, could be bytes or stream (will be decoded with UTF8) or text + :type data: str or bytes or IO + :param str content_type: The content type. + :return: The deserialized data. + :rtype: object + """ + if hasattr(data, "read"): + # Assume a stream + data = cast(IO, data).read() + + if isinstance(data, bytes): + data_as_str = data.decode(encoding="utf-8-sig") + else: + # Explain to mypy the correct type. + data_as_str = cast(str, data) + + # Remove Byte Order Mark if present in string + data_as_str = data_as_str.lstrip(_BOM) + + if content_type is None: + return data + + if cls.JSON_REGEXP.match(content_type): + try: + return json.loads(data_as_str) + except ValueError as err: + raise DeserializationError("JSON is invalid: {}".format(err), err) from err + elif "xml" in (content_type or []): + try: + + try: + if isinstance(data, unicode): # type: ignore + # If I'm Python 2.7 and unicode XML will scream if I try a "fromstring" on unicode string + data_as_str = data_as_str.encode(encoding="utf-8") # type: ignore + except NameError: + pass + + return ET.fromstring(data_as_str) # nosec + except ET.ParseError as err: + # It might be because the server has an issue, and returned JSON with + # content-type XML.... + # So let's try a JSON load, and if it's still broken + # let's flow the initial exception + def _json_attemp(data): + try: + return True, json.loads(data) + except ValueError: + return False, None # Don't care about this one + + success, json_result = _json_attemp(data) + if success: + return json_result + # If i'm here, it's not JSON, it's not XML, let's scream + # and raise the last context in this block (the XML exception) + # The function hack is because Py2.7 messes up with exception + # context otherwise. + _LOGGER.critical("Wasn't XML not JSON, failing") + raise DeserializationError("XML is invalid") from err + elif content_type.startswith("text/"): + return data_as_str + raise DeserializationError("Cannot deserialize content-type: {}".format(content_type)) + + @classmethod + def deserialize_from_http_generics(cls, body_bytes: Optional[Union[AnyStr, IO]], headers: Mapping) -> Any: + """Deserialize from HTTP response. + + Use bytes and headers to NOT use any requests/aiohttp or whatever + specific implementation. + Headers will tested for "content-type" + + :param bytes body_bytes: The body of the response. + :param dict headers: The headers of the response. + :returns: The deserialized data. + :rtype: object + """ + # Try to use content-type from headers if available + content_type = None + if "content-type" in headers: + content_type = headers["content-type"].split(";")[0].strip().lower() + # Ouch, this server did not declare what it sent... + # Let's guess it's JSON... + # Also, since Autorest was considering that an empty body was a valid JSON, + # need that test as well.... + else: + content_type = "application/json" + + if body_bytes: + return cls.deserialize_from_text(body_bytes, content_type) + return None + + +_LOGGER = logging.getLogger(__name__) + +try: + _long_type = long # type: ignore +except NameError: + _long_type = int + +TZ_UTC = datetime.timezone.utc + +_FLATTEN = re.compile(r"(? None: + self.additional_properties: Optional[Dict[str, Any]] = {} + for k in kwargs: # pylint: disable=consider-using-dict-items + if k not in self._attribute_map: + _LOGGER.warning("%s is not a known attribute of class %s and will be ignored", k, self.__class__) + elif k in self._validation and self._validation[k].get("readonly", False): + _LOGGER.warning("Readonly attribute %s will be ignored in class %s", k, self.__class__) + else: + setattr(self, k, kwargs[k]) + + def __eq__(self, other: Any) -> bool: + """Compare objects by comparing all attributes. + + :param object other: The object to compare + :returns: True if objects are equal + :rtype: bool + """ + if isinstance(other, self.__class__): + return self.__dict__ == other.__dict__ + return False + + def __ne__(self, other: Any) -> bool: + """Compare objects by comparing all attributes. + + :param object other: The object to compare + :returns: True if objects are not equal + :rtype: bool + """ + return not self.__eq__(other) + + def __str__(self) -> str: + return str(self.__dict__) + + @classmethod + def enable_additional_properties_sending(cls) -> None: + cls._attribute_map["additional_properties"] = {"key": "", "type": "{object}"} + + @classmethod + def is_xml_model(cls) -> bool: + try: + cls._xml_map # type: ignore + except AttributeError: + return False + return True + + @classmethod + def _create_xml_node(cls): + """Create XML node. + + :returns: The XML node + :rtype: xml.etree.ElementTree.Element + """ + try: + xml_map = cls._xml_map # type: ignore + except AttributeError: + xml_map = {} + + return _create_xml_node(xml_map.get("name", cls.__name__), xml_map.get("prefix", None), xml_map.get("ns", None)) + + def serialize(self, keep_readonly: bool = False, **kwargs: Any) -> JSON: + """Return the JSON that would be sent to server from this model. + + This is an alias to `as_dict(full_restapi_key_transformer, keep_readonly=False)`. + + If you want XML serialization, you can pass the kwargs is_xml=True. + + :param bool keep_readonly: If you want to serialize the readonly attributes + :returns: A dict JSON compatible object + :rtype: dict + """ + serializer = Serializer(self._infer_class_models()) + return serializer._serialize( # type: ignore # pylint: disable=protected-access + self, keep_readonly=keep_readonly, **kwargs + ) + + def as_dict( + self, + keep_readonly: bool = True, + key_transformer: Callable[[str, Dict[str, Any], Any], Any] = attribute_transformer, + **kwargs: Any + ) -> JSON: + """Return a dict that can be serialized using json.dump. + + Advanced usage might optionally use a callback as parameter: + + .. code::python + + def my_key_transformer(key, attr_desc, value): + return key + + Key is the attribute name used in Python. Attr_desc + is a dict of metadata. Currently contains 'type' with the + msrest type and 'key' with the RestAPI encoded key. + Value is the current value in this object. + + The string returned will be used to serialize the key. + If the return type is a list, this is considered hierarchical + result dict. + + See the three examples in this file: + + - attribute_transformer + - full_restapi_key_transformer + - last_restapi_key_transformer + + If you want XML serialization, you can pass the kwargs is_xml=True. + + :param bool keep_readonly: If you want to serialize the readonly attributes + :param function key_transformer: A key transformer function. + :returns: A dict JSON compatible object + :rtype: dict + """ + serializer = Serializer(self._infer_class_models()) + return serializer._serialize( # type: ignore # pylint: disable=protected-access + self, key_transformer=key_transformer, keep_readonly=keep_readonly, **kwargs + ) + + @classmethod + def _infer_class_models(cls): + try: + str_models = cls.__module__.rsplit(".", 1)[0] + models = sys.modules[str_models] + client_models = {k: v for k, v in models.__dict__.items() if isinstance(v, type)} + if cls.__name__ not in client_models: + raise ValueError("Not Autorest generated code") + except Exception: # pylint: disable=broad-exception-caught + # Assume it's not Autorest generated (tests?). Add ourselves as dependencies. + client_models = {cls.__name__: cls} + return client_models + + @classmethod + def deserialize(cls, data: Any, content_type: Optional[str] = None) -> Self: + """Parse a str using the RestAPI syntax and return a model. + + :param str data: A str using RestAPI structure. JSON by default. + :param str content_type: JSON by default, set application/xml if XML. + :returns: An instance of this model + :raises DeserializationError: if something went wrong + :rtype: Self + """ + deserializer = Deserializer(cls._infer_class_models()) + return deserializer(cls.__name__, data, content_type=content_type) # type: ignore + + @classmethod + def from_dict( + cls, + data: Any, + key_extractors: Optional[Callable[[str, Dict[str, Any], Any], Any]] = None, + content_type: Optional[str] = None, + ) -> Self: + """Parse a dict using given key extractor return a model. + + By default consider key + extractors (rest_key_case_insensitive_extractor, attribute_key_case_insensitive_extractor + and last_rest_key_case_insensitive_extractor) + + :param dict data: A dict using RestAPI structure + :param function key_extractors: A key extractor function. + :param str content_type: JSON by default, set application/xml if XML. + :returns: An instance of this model + :raises DeserializationError: if something went wrong + :rtype: Self + """ + deserializer = Deserializer(cls._infer_class_models()) + deserializer.key_extractors = ( # type: ignore + [ # type: ignore + attribute_key_case_insensitive_extractor, + rest_key_case_insensitive_extractor, + last_rest_key_case_insensitive_extractor, + ] + if key_extractors is None + else key_extractors + ) + return deserializer(cls.__name__, data, content_type=content_type) # type: ignore + + @classmethod + def _flatten_subtype(cls, key, objects): + if "_subtype_map" not in cls.__dict__: + return {} + result = dict(cls._subtype_map[key]) + for valuetype in cls._subtype_map[key].values(): + result.update(objects[valuetype]._flatten_subtype(key, objects)) # pylint: disable=protected-access + return result + + @classmethod + def _classify(cls, response, objects): + """Check the class _subtype_map for any child classes. + We want to ignore any inherited _subtype_maps. + + :param dict response: The initial data + :param dict objects: The class objects + :returns: The class to be used + :rtype: class + """ + for subtype_key in cls.__dict__.get("_subtype_map", {}).keys(): + subtype_value = None + + if not isinstance(response, ET.Element): + rest_api_response_key = cls._get_rest_key_parts(subtype_key)[-1] + subtype_value = response.get(rest_api_response_key, None) or response.get(subtype_key, None) + else: + subtype_value = xml_key_extractor(subtype_key, cls._attribute_map[subtype_key], response) + if subtype_value: + # Try to match base class. Can be class name only + # (bug to fix in Autorest to support x-ms-discriminator-name) + if cls.__name__ == subtype_value: + return cls + flatten_mapping_type = cls._flatten_subtype(subtype_key, objects) + try: + return objects[flatten_mapping_type[subtype_value]] # type: ignore + except KeyError: + _LOGGER.warning( + "Subtype value %s has no mapping, use base class %s.", + subtype_value, + cls.__name__, + ) + break + else: + _LOGGER.warning("Discriminator %s is absent or null, use base class %s.", subtype_key, cls.__name__) + break + return cls + + @classmethod + def _get_rest_key_parts(cls, attr_key): + """Get the RestAPI key of this attr, split it and decode part + :param str attr_key: Attribute key must be in attribute_map. + :returns: A list of RestAPI part + :rtype: list + """ + rest_split_key = _FLATTEN.split(cls._attribute_map[attr_key]["key"]) + return [_decode_attribute_map_key(key_part) for key_part in rest_split_key] + + +def _decode_attribute_map_key(key): + """This decode a key in an _attribute_map to the actual key we want to look at + inside the received data. + + :param str key: A key string from the generated code + :returns: The decoded key + :rtype: str + """ + return key.replace("\\.", ".") + + +class Serializer: # pylint: disable=too-many-public-methods + """Request object model serializer.""" + + basic_types = {str: "str", int: "int", bool: "bool", float: "float"} + + _xml_basic_types_serializers = {"bool": lambda x: str(x).lower()} + days = {0: "Mon", 1: "Tue", 2: "Wed", 3: "Thu", 4: "Fri", 5: "Sat", 6: "Sun"} + months = { + 1: "Jan", + 2: "Feb", + 3: "Mar", + 4: "Apr", + 5: "May", + 6: "Jun", + 7: "Jul", + 8: "Aug", + 9: "Sep", + 10: "Oct", + 11: "Nov", + 12: "Dec", + } + validation = { + "min_length": lambda x, y: len(x) < y, + "max_length": lambda x, y: len(x) > y, + "minimum": lambda x, y: x < y, + "maximum": lambda x, y: x > y, + "minimum_ex": lambda x, y: x <= y, + "maximum_ex": lambda x, y: x >= y, + "min_items": lambda x, y: len(x) < y, + "max_items": lambda x, y: len(x) > y, + "pattern": lambda x, y: not re.match(y, x, re.UNICODE), + "unique": lambda x, y: len(x) != len(set(x)), + "multiple": lambda x, y: x % y != 0, + } + + def __init__(self, classes: Optional[Mapping[str, type]] = None) -> None: + self.serialize_type = { + "iso-8601": Serializer.serialize_iso, + "rfc-1123": Serializer.serialize_rfc, + "unix-time": Serializer.serialize_unix, + "duration": Serializer.serialize_duration, + "date": Serializer.serialize_date, + "time": Serializer.serialize_time, + "decimal": Serializer.serialize_decimal, + "long": Serializer.serialize_long, + "bytearray": Serializer.serialize_bytearray, + "base64": Serializer.serialize_base64, + "object": self.serialize_object, + "[]": self.serialize_iter, + "{}": self.serialize_dict, + } + self.dependencies: Dict[str, type] = dict(classes) if classes else {} + self.key_transformer = full_restapi_key_transformer + self.client_side_validation = True + + def _serialize( # pylint: disable=too-many-nested-blocks, too-many-branches, too-many-statements, too-many-locals + self, target_obj, data_type=None, **kwargs + ): + """Serialize data into a string according to type. + + :param object target_obj: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str, dict + :raises SerializationError: if serialization fails. + :returns: The serialized data. + """ + key_transformer = kwargs.get("key_transformer", self.key_transformer) + keep_readonly = kwargs.get("keep_readonly", False) + if target_obj is None: + return None + + attr_name = None + class_name = target_obj.__class__.__name__ + + if data_type: + return self.serialize_data(target_obj, data_type, **kwargs) + + if not hasattr(target_obj, "_attribute_map"): + data_type = type(target_obj).__name__ + if data_type in self.basic_types.values(): + return self.serialize_data(target_obj, data_type, **kwargs) + + # Force "is_xml" kwargs if we detect a XML model + try: + is_xml_model_serialization = kwargs["is_xml"] + except KeyError: + is_xml_model_serialization = kwargs.setdefault("is_xml", target_obj.is_xml_model()) + + serialized = {} + if is_xml_model_serialization: + serialized = target_obj._create_xml_node() # pylint: disable=protected-access + try: + attributes = target_obj._attribute_map # pylint: disable=protected-access + for attr, attr_desc in attributes.items(): + attr_name = attr + if not keep_readonly and target_obj._validation.get( # pylint: disable=protected-access + attr_name, {} + ).get("readonly", False): + continue + + if attr_name == "additional_properties" and attr_desc["key"] == "": + if target_obj.additional_properties is not None: + serialized.update(target_obj.additional_properties) + continue + try: + + orig_attr = getattr(target_obj, attr) + if is_xml_model_serialization: + pass # Don't provide "transformer" for XML for now. Keep "orig_attr" + else: # JSON + keys, orig_attr = key_transformer(attr, attr_desc.copy(), orig_attr) + keys = keys if isinstance(keys, list) else [keys] + + kwargs["serialization_ctxt"] = attr_desc + new_attr = self.serialize_data(orig_attr, attr_desc["type"], **kwargs) + + if is_xml_model_serialization: + xml_desc = attr_desc.get("xml", {}) + xml_name = xml_desc.get("name", attr_desc["key"]) + xml_prefix = xml_desc.get("prefix", None) + xml_ns = xml_desc.get("ns", None) + if xml_desc.get("attr", False): + if xml_ns: + ET.register_namespace(xml_prefix, xml_ns) + xml_name = "{{{}}}{}".format(xml_ns, xml_name) + serialized.set(xml_name, new_attr) # type: ignore + continue + if xml_desc.get("text", False): + serialized.text = new_attr # type: ignore + continue + if isinstance(new_attr, list): + serialized.extend(new_attr) # type: ignore + elif isinstance(new_attr, ET.Element): + # If the down XML has no XML/Name, + # we MUST replace the tag with the local tag. But keeping the namespaces. + if "name" not in getattr(orig_attr, "_xml_map", {}): + splitted_tag = new_attr.tag.split("}") + if len(splitted_tag) == 2: # Namespace + new_attr.tag = "}".join([splitted_tag[0], xml_name]) + else: + new_attr.tag = xml_name + serialized.append(new_attr) # type: ignore + else: # That's a basic type + # Integrate namespace if necessary + local_node = _create_xml_node(xml_name, xml_prefix, xml_ns) + local_node.text = str(new_attr) + serialized.append(local_node) # type: ignore + else: # JSON + for k in reversed(keys): # type: ignore + new_attr = {k: new_attr} + + _new_attr = new_attr + _serialized = serialized + for k in keys: # type: ignore + if k not in _serialized: + _serialized.update(_new_attr) # type: ignore + _new_attr = _new_attr[k] # type: ignore + _serialized = _serialized[k] + except ValueError as err: + if isinstance(err, SerializationError): + raise + + except (AttributeError, KeyError, TypeError) as err: + msg = "Attribute {} in object {} cannot be serialized.\n{}".format(attr_name, class_name, str(target_obj)) + raise SerializationError(msg) from err + return serialized + + def body(self, data, data_type, **kwargs): + """Serialize data intended for a request body. + + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: dict + :raises SerializationError: if serialization fails. + :raises ValueError: if data is None + :returns: The serialized request body + """ + + # Just in case this is a dict + internal_data_type_str = data_type.strip("[]{}") + internal_data_type = self.dependencies.get(internal_data_type_str, None) + try: + is_xml_model_serialization = kwargs["is_xml"] + except KeyError: + if internal_data_type and issubclass(internal_data_type, Model): + is_xml_model_serialization = kwargs.setdefault("is_xml", internal_data_type.is_xml_model()) + else: + is_xml_model_serialization = False + if internal_data_type and not isinstance(internal_data_type, Enum): + try: + deserializer = Deserializer(self.dependencies) + # Since it's on serialization, it's almost sure that format is not JSON REST + # We're not able to deal with additional properties for now. + deserializer.additional_properties_detection = False + if is_xml_model_serialization: + deserializer.key_extractors = [ # type: ignore + attribute_key_case_insensitive_extractor, + ] + else: + deserializer.key_extractors = [ + rest_key_case_insensitive_extractor, + attribute_key_case_insensitive_extractor, + last_rest_key_case_insensitive_extractor, + ] + data = deserializer._deserialize(data_type, data) # pylint: disable=protected-access + except DeserializationError as err: + raise SerializationError("Unable to build a model: " + str(err)) from err + + return self._serialize(data, data_type, **kwargs) + + def url(self, name, data, data_type, **kwargs): + """Serialize data intended for a URL path. + + :param str name: The name of the URL path parameter. + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str + :returns: The serialized URL path + :raises TypeError: if serialization fails. + :raises ValueError: if data is None + """ + try: + output = self.serialize_data(data, data_type, **kwargs) + if data_type == "bool": + output = json.dumps(output) + + if kwargs.get("skip_quote") is True: + output = str(output) + output = output.replace("{", quote("{")).replace("}", quote("}")) + else: + output = quote(str(output), safe="") + except SerializationError as exc: + raise TypeError("{} must be type {}.".format(name, data_type)) from exc + return output + + def query(self, name, data, data_type, **kwargs): + """Serialize data intended for a URL query. + + :param str name: The name of the query parameter. + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str, list + :raises TypeError: if serialization fails. + :raises ValueError: if data is None + :returns: The serialized query parameter + """ + try: + # Treat the list aside, since we don't want to encode the div separator + if data_type.startswith("["): + internal_data_type = data_type[1:-1] + do_quote = not kwargs.get("skip_quote", False) + return self.serialize_iter(data, internal_data_type, do_quote=do_quote, **kwargs) + + # Not a list, regular serialization + output = self.serialize_data(data, data_type, **kwargs) + if data_type == "bool": + output = json.dumps(output) + if kwargs.get("skip_quote") is True: + output = str(output) + else: + output = quote(str(output), safe="") + except SerializationError as exc: + raise TypeError("{} must be type {}.".format(name, data_type)) from exc + return str(output) + + def header(self, name, data, data_type, **kwargs): + """Serialize data intended for a request header. + + :param str name: The name of the header. + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str + :raises TypeError: if serialization fails. + :raises ValueError: if data is None + :returns: The serialized header + """ + try: + if data_type in ["[str]"]: + data = ["" if d is None else d for d in data] + + output = self.serialize_data(data, data_type, **kwargs) + if data_type == "bool": + output = json.dumps(output) + except SerializationError as exc: + raise TypeError("{} must be type {}.".format(name, data_type)) from exc + return str(output) + + def serialize_data(self, data, data_type, **kwargs): + """Serialize generic data according to supplied data type. + + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :raises AttributeError: if required data is None. + :raises ValueError: if data is None + :raises SerializationError: if serialization fails. + :returns: The serialized data. + :rtype: str, int, float, bool, dict, list + """ + if data is None: + raise ValueError("No value for given attribute") + + try: + if data is CoreNull: + return None + if data_type in self.basic_types.values(): + return self.serialize_basic(data, data_type, **kwargs) + + if data_type in self.serialize_type: + return self.serialize_type[data_type](data, **kwargs) + + # If dependencies is empty, try with current data class + # It has to be a subclass of Enum anyway + enum_type = self.dependencies.get(data_type, data.__class__) + if issubclass(enum_type, Enum): + return Serializer.serialize_enum(data, enum_obj=enum_type) + + iter_type = data_type[0] + data_type[-1] + if iter_type in self.serialize_type: + return self.serialize_type[iter_type](data, data_type[1:-1], **kwargs) + + except (ValueError, TypeError) as err: + msg = "Unable to serialize value: {!r} as type: {!r}." + raise SerializationError(msg.format(data, data_type)) from err + return self._serialize(data, **kwargs) + + @classmethod + def _get_custom_serializers(cls, data_type, **kwargs): # pylint: disable=inconsistent-return-statements + custom_serializer = kwargs.get("basic_types_serializers", {}).get(data_type) + if custom_serializer: + return custom_serializer + if kwargs.get("is_xml", False): + return cls._xml_basic_types_serializers.get(data_type) + + @classmethod + def serialize_basic(cls, data, data_type, **kwargs): + """Serialize basic builting data type. + Serializes objects to str, int, float or bool. + + Possible kwargs: + - basic_types_serializers dict[str, callable] : If set, use the callable as serializer + - is_xml bool : If set, use xml_basic_types_serializers + + :param obj data: Object to be serialized. + :param str data_type: Type of object in the iterable. + :rtype: str, int, float, bool + :return: serialized object + """ + custom_serializer = cls._get_custom_serializers(data_type, **kwargs) + if custom_serializer: + return custom_serializer(data) + if data_type == "str": + return cls.serialize_unicode(data) + return eval(data_type)(data) # nosec # pylint: disable=eval-used + + @classmethod + def serialize_unicode(cls, data): + """Special handling for serializing unicode strings in Py2. + Encode to UTF-8 if unicode, otherwise handle as a str. + + :param str data: Object to be serialized. + :rtype: str + :return: serialized object + """ + try: # If I received an enum, return its value + return data.value + except AttributeError: + pass + + try: + if isinstance(data, unicode): # type: ignore + # Don't change it, JSON and XML ElementTree are totally able + # to serialize correctly u'' strings + return data + except NameError: + return str(data) + return str(data) + + def serialize_iter(self, data, iter_type, div=None, **kwargs): + """Serialize iterable. + + Supported kwargs: + - serialization_ctxt dict : The current entry of _attribute_map, or same format. + serialization_ctxt['type'] should be same as data_type. + - is_xml bool : If set, serialize as XML + + :param list data: Object to be serialized. + :param str iter_type: Type of object in the iterable. + :param str div: If set, this str will be used to combine the elements + in the iterable into a combined string. Default is 'None'. + Defaults to False. + :rtype: list, str + :return: serialized iterable + """ + if isinstance(data, str): + raise SerializationError("Refuse str type as a valid iter type.") + + serialization_ctxt = kwargs.get("serialization_ctxt", {}) + is_xml = kwargs.get("is_xml", False) + + serialized = [] + for d in data: + try: + serialized.append(self.serialize_data(d, iter_type, **kwargs)) + except ValueError as err: + if isinstance(err, SerializationError): + raise + serialized.append(None) + + if kwargs.get("do_quote", False): + serialized = ["" if s is None else quote(str(s), safe="") for s in serialized] + + if div: + serialized = ["" if s is None else str(s) for s in serialized] + serialized = div.join(serialized) + + if "xml" in serialization_ctxt or is_xml: + # XML serialization is more complicated + xml_desc = serialization_ctxt.get("xml", {}) + xml_name = xml_desc.get("name") + if not xml_name: + xml_name = serialization_ctxt["key"] + + # Create a wrap node if necessary (use the fact that Element and list have "append") + is_wrapped = xml_desc.get("wrapped", False) + node_name = xml_desc.get("itemsName", xml_name) + if is_wrapped: + final_result = _create_xml_node(xml_name, xml_desc.get("prefix", None), xml_desc.get("ns", None)) + else: + final_result = [] + # All list elements to "local_node" + for el in serialized: + if isinstance(el, ET.Element): + el_node = el + else: + el_node = _create_xml_node(node_name, xml_desc.get("prefix", None), xml_desc.get("ns", None)) + if el is not None: # Otherwise it writes "None" :-p + el_node.text = str(el) + final_result.append(el_node) + return final_result + return serialized + + def serialize_dict(self, attr, dict_type, **kwargs): + """Serialize a dictionary of objects. + + :param dict attr: Object to be serialized. + :param str dict_type: Type of object in the dictionary. + :rtype: dict + :return: serialized dictionary + """ + serialization_ctxt = kwargs.get("serialization_ctxt", {}) + serialized = {} + for key, value in attr.items(): + try: + serialized[self.serialize_unicode(key)] = self.serialize_data(value, dict_type, **kwargs) + except ValueError as err: + if isinstance(err, SerializationError): + raise + serialized[self.serialize_unicode(key)] = None + + if "xml" in serialization_ctxt: + # XML serialization is more complicated + xml_desc = serialization_ctxt["xml"] + xml_name = xml_desc["name"] + + final_result = _create_xml_node(xml_name, xml_desc.get("prefix", None), xml_desc.get("ns", None)) + for key, value in serialized.items(): + ET.SubElement(final_result, key).text = value + return final_result + + return serialized + + def serialize_object(self, attr, **kwargs): # pylint: disable=too-many-return-statements + """Serialize a generic object. + This will be handled as a dictionary. If object passed in is not + a basic type (str, int, float, dict, list) it will simply be + cast to str. + + :param dict attr: Object to be serialized. + :rtype: dict or str + :return: serialized object + """ + if attr is None: + return None + if isinstance(attr, ET.Element): + return attr + obj_type = type(attr) + if obj_type in self.basic_types: + return self.serialize_basic(attr, self.basic_types[obj_type], **kwargs) + if obj_type is _long_type: + return self.serialize_long(attr) + if obj_type is str: + return self.serialize_unicode(attr) + if obj_type is datetime.datetime: + return self.serialize_iso(attr) + if obj_type is datetime.date: + return self.serialize_date(attr) + if obj_type is datetime.time: + return self.serialize_time(attr) + if obj_type is datetime.timedelta: + return self.serialize_duration(attr) + if obj_type is decimal.Decimal: + return self.serialize_decimal(attr) + + # If it's a model or I know this dependency, serialize as a Model + if obj_type in self.dependencies.values() or isinstance(attr, Model): + return self._serialize(attr) + + if obj_type == dict: + serialized = {} + for key, value in attr.items(): + try: + serialized[self.serialize_unicode(key)] = self.serialize_object(value, **kwargs) + except ValueError: + serialized[self.serialize_unicode(key)] = None + return serialized + + if obj_type == list: + serialized = [] + for obj in attr: + try: + serialized.append(self.serialize_object(obj, **kwargs)) + except ValueError: + pass + return serialized + return str(attr) + + @staticmethod + def serialize_enum(attr, enum_obj=None): + try: + result = attr.value + except AttributeError: + result = attr + try: + enum_obj(result) # type: ignore + return result + except ValueError as exc: + for enum_value in enum_obj: # type: ignore + if enum_value.value.lower() == str(attr).lower(): + return enum_value.value + error = "{!r} is not valid value for enum {!r}" + raise SerializationError(error.format(attr, enum_obj)) from exc + + @staticmethod + def serialize_bytearray(attr, **kwargs): # pylint: disable=unused-argument + """Serialize bytearray into base-64 string. + + :param str attr: Object to be serialized. + :rtype: str + :return: serialized base64 + """ + return b64encode(attr).decode() + + @staticmethod + def serialize_base64(attr, **kwargs): # pylint: disable=unused-argument + """Serialize str into base-64 string. + + :param str attr: Object to be serialized. + :rtype: str + :return: serialized base64 + """ + encoded = b64encode(attr).decode("ascii") + return encoded.strip("=").replace("+", "-").replace("/", "_") + + @staticmethod + def serialize_decimal(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Decimal object to float. + + :param decimal attr: Object to be serialized. + :rtype: float + :return: serialized decimal + """ + return float(attr) + + @staticmethod + def serialize_long(attr, **kwargs): # pylint: disable=unused-argument + """Serialize long (Py2) or int (Py3). + + :param int attr: Object to be serialized. + :rtype: int/long + :return: serialized long + """ + return _long_type(attr) + + @staticmethod + def serialize_date(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Date object into ISO-8601 formatted string. + + :param Date attr: Object to be serialized. + :rtype: str + :return: serialized date + """ + if isinstance(attr, str): + attr = isodate.parse_date(attr) + t = "{:04}-{:02}-{:02}".format(attr.year, attr.month, attr.day) + return t + + @staticmethod + def serialize_time(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Time object into ISO-8601 formatted string. + + :param datetime.time attr: Object to be serialized. + :rtype: str + :return: serialized time + """ + if isinstance(attr, str): + attr = isodate.parse_time(attr) + t = "{:02}:{:02}:{:02}".format(attr.hour, attr.minute, attr.second) + if attr.microsecond: + t += ".{:02}".format(attr.microsecond) + return t + + @staticmethod + def serialize_duration(attr, **kwargs): # pylint: disable=unused-argument + """Serialize TimeDelta object into ISO-8601 formatted string. + + :param TimeDelta attr: Object to be serialized. + :rtype: str + :return: serialized duration + """ + if isinstance(attr, str): + attr = isodate.parse_duration(attr) + return isodate.duration_isoformat(attr) + + @staticmethod + def serialize_rfc(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Datetime object into RFC-1123 formatted string. + + :param Datetime attr: Object to be serialized. + :rtype: str + :raises TypeError: if format invalid. + :return: serialized rfc + """ + try: + if not attr.tzinfo: + _LOGGER.warning("Datetime with no tzinfo will be considered UTC.") + utc = attr.utctimetuple() + except AttributeError as exc: + raise TypeError("RFC1123 object must be valid Datetime object.") from exc + + return "{}, {:02} {} {:04} {:02}:{:02}:{:02} GMT".format( + Serializer.days[utc.tm_wday], + utc.tm_mday, + Serializer.months[utc.tm_mon], + utc.tm_year, + utc.tm_hour, + utc.tm_min, + utc.tm_sec, + ) + + @staticmethod + def serialize_iso(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Datetime object into ISO-8601 formatted string. + + :param Datetime attr: Object to be serialized. + :rtype: str + :raises SerializationError: if format invalid. + :return: serialized iso + """ + if isinstance(attr, str): + attr = isodate.parse_datetime(attr) + try: + if not attr.tzinfo: + _LOGGER.warning("Datetime with no tzinfo will be considered UTC.") + utc = attr.utctimetuple() + if utc.tm_year > 9999 or utc.tm_year < 1: + raise OverflowError("Hit max or min date") + + microseconds = str(attr.microsecond).rjust(6, "0").rstrip("0").ljust(3, "0") + if microseconds: + microseconds = "." + microseconds + date = "{:04}-{:02}-{:02}T{:02}:{:02}:{:02}".format( + utc.tm_year, utc.tm_mon, utc.tm_mday, utc.tm_hour, utc.tm_min, utc.tm_sec + ) + return date + microseconds + "Z" + except (ValueError, OverflowError) as err: + msg = "Unable to serialize datetime object." + raise SerializationError(msg) from err + except AttributeError as err: + msg = "ISO-8601 object must be valid Datetime object." + raise TypeError(msg) from err + + @staticmethod + def serialize_unix(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Datetime object into IntTime format. + This is represented as seconds. + + :param Datetime attr: Object to be serialized. + :rtype: int + :raises SerializationError: if format invalid + :return: serialied unix + """ + if isinstance(attr, int): + return attr + try: + if not attr.tzinfo: + _LOGGER.warning("Datetime with no tzinfo will be considered UTC.") + return int(calendar.timegm(attr.utctimetuple())) + except AttributeError as exc: + raise TypeError("Unix time object must be valid Datetime object.") from exc + + +def rest_key_extractor(attr, attr_desc, data): # pylint: disable=unused-argument + key = attr_desc["key"] + working_data = data + + while "." in key: + # Need the cast, as for some reasons "split" is typed as list[str | Any] + dict_keys = cast(List[str], _FLATTEN.split(key)) + if len(dict_keys) == 1: + key = _decode_attribute_map_key(dict_keys[0]) + break + working_key = _decode_attribute_map_key(dict_keys[0]) + working_data = working_data.get(working_key, data) + if working_data is None: + # If at any point while following flatten JSON path see None, it means + # that all properties under are None as well + return None + key = ".".join(dict_keys[1:]) + + return working_data.get(key) + + +def rest_key_case_insensitive_extractor( # pylint: disable=unused-argument, inconsistent-return-statements + attr, attr_desc, data +): + key = attr_desc["key"] + working_data = data + + while "." in key: + dict_keys = _FLATTEN.split(key) + if len(dict_keys) == 1: + key = _decode_attribute_map_key(dict_keys[0]) + break + working_key = _decode_attribute_map_key(dict_keys[0]) + working_data = attribute_key_case_insensitive_extractor(working_key, None, working_data) + if working_data is None: + # If at any point while following flatten JSON path see None, it means + # that all properties under are None as well + return None + key = ".".join(dict_keys[1:]) + + if working_data: + return attribute_key_case_insensitive_extractor(key, None, working_data) + + +def last_rest_key_extractor(attr, attr_desc, data): # pylint: disable=unused-argument + """Extract the attribute in "data" based on the last part of the JSON path key. + + :param str attr: The attribute to extract + :param dict attr_desc: The attribute description + :param dict data: The data to extract from + :rtype: object + :returns: The extracted attribute + """ + key = attr_desc["key"] + dict_keys = _FLATTEN.split(key) + return attribute_key_extractor(dict_keys[-1], None, data) + + +def last_rest_key_case_insensitive_extractor(attr, attr_desc, data): # pylint: disable=unused-argument + """Extract the attribute in "data" based on the last part of the JSON path key. + + This is the case insensitive version of "last_rest_key_extractor" + :param str attr: The attribute to extract + :param dict attr_desc: The attribute description + :param dict data: The data to extract from + :rtype: object + :returns: The extracted attribute + """ + key = attr_desc["key"] + dict_keys = _FLATTEN.split(key) + return attribute_key_case_insensitive_extractor(dict_keys[-1], None, data) + + +def attribute_key_extractor(attr, _, data): + return data.get(attr) + + +def attribute_key_case_insensitive_extractor(attr, _, data): + found_key = None + lower_attr = attr.lower() + for key in data: + if lower_attr == key.lower(): + found_key = key + break + + return data.get(found_key) + + +def _extract_name_from_internal_type(internal_type): + """Given an internal type XML description, extract correct XML name with namespace. + + :param dict internal_type: An model type + :rtype: tuple + :returns: A tuple XML name + namespace dict + """ + internal_type_xml_map = getattr(internal_type, "_xml_map", {}) + xml_name = internal_type_xml_map.get("name", internal_type.__name__) + xml_ns = internal_type_xml_map.get("ns", None) + if xml_ns: + xml_name = "{{{}}}{}".format(xml_ns, xml_name) + return xml_name + + +def xml_key_extractor(attr, attr_desc, data): # pylint: disable=unused-argument,too-many-return-statements + if isinstance(data, dict): + return None + + # Test if this model is XML ready first + if not isinstance(data, ET.Element): + return None + + xml_desc = attr_desc.get("xml", {}) + xml_name = xml_desc.get("name", attr_desc["key"]) + + # Look for a children + is_iter_type = attr_desc["type"].startswith("[") + is_wrapped = xml_desc.get("wrapped", False) + internal_type = attr_desc.get("internalType", None) + internal_type_xml_map = getattr(internal_type, "_xml_map", {}) + + # Integrate namespace if necessary + xml_ns = xml_desc.get("ns", internal_type_xml_map.get("ns", None)) + if xml_ns: + xml_name = "{{{}}}{}".format(xml_ns, xml_name) + + # If it's an attribute, that's simple + if xml_desc.get("attr", False): + return data.get(xml_name) + + # If it's x-ms-text, that's simple too + if xml_desc.get("text", False): + return data.text + + # Scenario where I take the local name: + # - Wrapped node + # - Internal type is an enum (considered basic types) + # - Internal type has no XML/Name node + if is_wrapped or (internal_type and (issubclass(internal_type, Enum) or "name" not in internal_type_xml_map)): + children = data.findall(xml_name) + # If internal type has a local name and it's not a list, I use that name + elif not is_iter_type and internal_type and "name" in internal_type_xml_map: + xml_name = _extract_name_from_internal_type(internal_type) + children = data.findall(xml_name) + # That's an array + else: + if internal_type: # Complex type, ignore itemsName and use the complex type name + items_name = _extract_name_from_internal_type(internal_type) + else: + items_name = xml_desc.get("itemsName", xml_name) + children = data.findall(items_name) + + if len(children) == 0: + if is_iter_type: + if is_wrapped: + return None # is_wrapped no node, we want None + return [] # not wrapped, assume empty list + return None # Assume it's not there, maybe an optional node. + + # If is_iter_type and not wrapped, return all found children + if is_iter_type: + if not is_wrapped: + return children + # Iter and wrapped, should have found one node only (the wrap one) + if len(children) != 1: + raise DeserializationError( + "Tried to deserialize an array not wrapped, and found several nodes '{}'. Maybe you should declare this array as wrapped?".format( + xml_name + ) + ) + return list(children[0]) # Might be empty list and that's ok. + + # Here it's not a itertype, we should have found one element only or empty + if len(children) > 1: + raise DeserializationError("Find several XML '{}' where it was not expected".format(xml_name)) + return children[0] + + +class Deserializer: + """Response object model deserializer. + + :param dict classes: Class type dictionary for deserializing complex types. + :ivar list key_extractors: Ordered list of extractors to be used by this deserializer. + """ + + basic_types = {str: "str", int: "int", bool: "bool", float: "float"} + + valid_date = re.compile(r"\d{4}[-]\d{2}[-]\d{2}T\d{2}:\d{2}:\d{2}\.?\d*Z?[-+]?[\d{2}]?:?[\d{2}]?") + + def __init__(self, classes: Optional[Mapping[str, type]] = None) -> None: + self.deserialize_type = { + "iso-8601": Deserializer.deserialize_iso, + "rfc-1123": Deserializer.deserialize_rfc, + "unix-time": Deserializer.deserialize_unix, + "duration": Deserializer.deserialize_duration, + "date": Deserializer.deserialize_date, + "time": Deserializer.deserialize_time, + "decimal": Deserializer.deserialize_decimal, + "long": Deserializer.deserialize_long, + "bytearray": Deserializer.deserialize_bytearray, + "base64": Deserializer.deserialize_base64, + "object": self.deserialize_object, + "[]": self.deserialize_iter, + "{}": self.deserialize_dict, + } + self.deserialize_expected_types = { + "duration": (isodate.Duration, datetime.timedelta), + "iso-8601": (datetime.datetime), + } + self.dependencies: Dict[str, type] = dict(classes) if classes else {} + self.key_extractors = [rest_key_extractor, xml_key_extractor] + # Additional properties only works if the "rest_key_extractor" is used to + # extract the keys. Making it to work whatever the key extractor is too much + # complicated, with no real scenario for now. + # So adding a flag to disable additional properties detection. This flag should be + # used if your expect the deserialization to NOT come from a JSON REST syntax. + # Otherwise, result are unexpected + self.additional_properties_detection = True + + def __call__(self, target_obj, response_data, content_type=None): + """Call the deserializer to process a REST response. + + :param str target_obj: Target data type to deserialize to. + :param requests.Response response_data: REST response object. + :param str content_type: Swagger "produces" if available. + :raises DeserializationError: if deserialization fails. + :return: Deserialized object. + :rtype: object + """ + data = self._unpack_content(response_data, content_type) + return self._deserialize(target_obj, data) + + def _deserialize(self, target_obj, data): # pylint: disable=inconsistent-return-statements + """Call the deserializer on a model. + + Data needs to be already deserialized as JSON or XML ElementTree + + :param str target_obj: Target data type to deserialize to. + :param object data: Object to deserialize. + :raises DeserializationError: if deserialization fails. + :return: Deserialized object. + :rtype: object + """ + # This is already a model, go recursive just in case + if hasattr(data, "_attribute_map"): + constants = [name for name, config in getattr(data, "_validation", {}).items() if config.get("constant")] + try: + for attr, mapconfig in data._attribute_map.items(): # pylint: disable=protected-access + if attr in constants: + continue + value = getattr(data, attr) + if value is None: + continue + local_type = mapconfig["type"] + internal_data_type = local_type.strip("[]{}") + if internal_data_type not in self.dependencies or isinstance(internal_data_type, Enum): + continue + setattr(data, attr, self._deserialize(local_type, value)) + return data + except AttributeError: + return + + response, class_name = self._classify_target(target_obj, data) + + if isinstance(response, str): + return self.deserialize_data(data, response) + if isinstance(response, type) and issubclass(response, Enum): + return self.deserialize_enum(data, response) + + if data is None or data is CoreNull: + return data + try: + attributes = response._attribute_map # type: ignore # pylint: disable=protected-access + d_attrs = {} + for attr, attr_desc in attributes.items(): + # Check empty string. If it's not empty, someone has a real "additionalProperties"... + if attr == "additional_properties" and attr_desc["key"] == "": + continue + raw_value = None + # Enhance attr_desc with some dynamic data + attr_desc = attr_desc.copy() # Do a copy, do not change the real one + internal_data_type = attr_desc["type"].strip("[]{}") + if internal_data_type in self.dependencies: + attr_desc["internalType"] = self.dependencies[internal_data_type] + + for key_extractor in self.key_extractors: + found_value = key_extractor(attr, attr_desc, data) + if found_value is not None: + if raw_value is not None and raw_value != found_value: + msg = ( + "Ignoring extracted value '%s' from %s for key '%s'" + " (duplicate extraction, follow extractors order)" + ) + _LOGGER.warning(msg, found_value, key_extractor, attr) + continue + raw_value = found_value + + value = self.deserialize_data(raw_value, attr_desc["type"]) + d_attrs[attr] = value + except (AttributeError, TypeError, KeyError) as err: + msg = "Unable to deserialize to object: " + class_name # type: ignore + raise DeserializationError(msg) from err + additional_properties = self._build_additional_properties(attributes, data) + return self._instantiate_model(response, d_attrs, additional_properties) + + def _build_additional_properties(self, attribute_map, data): + if not self.additional_properties_detection: + return None + if "additional_properties" in attribute_map and attribute_map.get("additional_properties", {}).get("key") != "": + # Check empty string. If it's not empty, someone has a real "additionalProperties" + return None + if isinstance(data, ET.Element): + data = {el.tag: el.text for el in data} + + known_keys = { + _decode_attribute_map_key(_FLATTEN.split(desc["key"])[0]) + for desc in attribute_map.values() + if desc["key"] != "" + } + present_keys = set(data.keys()) + missing_keys = present_keys - known_keys + return {key: data[key] for key in missing_keys} + + def _classify_target(self, target, data): + """Check to see whether the deserialization target object can + be classified into a subclass. + Once classification has been determined, initialize object. + + :param str target: The target object type to deserialize to. + :param str/dict data: The response data to deserialize. + :return: The classified target object and its class name. + :rtype: tuple + """ + if target is None: + return None, None + + if isinstance(target, str): + try: + target = self.dependencies[target] + except KeyError: + return target, target + + try: + target = target._classify(data, self.dependencies) # type: ignore # pylint: disable=protected-access + except AttributeError: + pass # Target is not a Model, no classify + return target, target.__class__.__name__ # type: ignore + + def failsafe_deserialize(self, target_obj, data, content_type=None): + """Ignores any errors encountered in deserialization, + and falls back to not deserializing the object. Recommended + for use in error deserialization, as we want to return the + HttpResponseError to users, and not have them deal with + a deserialization error. + + :param str target_obj: The target object type to deserialize to. + :param str/dict data: The response data to deserialize. + :param str content_type: Swagger "produces" if available. + :return: Deserialized object. + :rtype: object + """ + try: + return self(target_obj, data, content_type=content_type) + except: # pylint: disable=bare-except + _LOGGER.debug( + "Ran into a deserialization error. Ignoring since this is failsafe deserialization", exc_info=True + ) + return None + + @staticmethod + def _unpack_content(raw_data, content_type=None): + """Extract the correct structure for deserialization. + + If raw_data is a PipelineResponse, try to extract the result of RawDeserializer. + if we can't, raise. Your Pipeline should have a RawDeserializer. + + If not a pipeline response and raw_data is bytes or string, use content-type + to decode it. If no content-type, try JSON. + + If raw_data is something else, bypass all logic and return it directly. + + :param obj raw_data: Data to be processed. + :param str content_type: How to parse if raw_data is a string/bytes. + :raises JSONDecodeError: If JSON is requested and parsing is impossible. + :raises UnicodeDecodeError: If bytes is not UTF8 + :rtype: object + :return: Unpacked content. + """ + # Assume this is enough to detect a Pipeline Response without importing it + context = getattr(raw_data, "context", {}) + if context: + if RawDeserializer.CONTEXT_NAME in context: + return context[RawDeserializer.CONTEXT_NAME] + raise ValueError("This pipeline didn't have the RawDeserializer policy; can't deserialize") + + # Assume this is enough to recognize universal_http.ClientResponse without importing it + if hasattr(raw_data, "body"): + return RawDeserializer.deserialize_from_http_generics(raw_data.text(), raw_data.headers) + + # Assume this enough to recognize requests.Response without importing it. + if hasattr(raw_data, "_content_consumed"): + return RawDeserializer.deserialize_from_http_generics(raw_data.text, raw_data.headers) + + if isinstance(raw_data, (str, bytes)) or hasattr(raw_data, "read"): + return RawDeserializer.deserialize_from_text(raw_data, content_type) # type: ignore + return raw_data + + def _instantiate_model(self, response, attrs, additional_properties=None): + """Instantiate a response model passing in deserialized args. + + :param Response response: The response model class. + :param dict attrs: The deserialized response attributes. + :param dict additional_properties: Additional properties to be set. + :rtype: Response + :return: The instantiated response model. + """ + if callable(response): + subtype = getattr(response, "_subtype_map", {}) + try: + readonly = [ + k + for k, v in response._validation.items() # pylint: disable=protected-access # type: ignore + if v.get("readonly") + ] + const = [ + k + for k, v in response._validation.items() # pylint: disable=protected-access # type: ignore + if v.get("constant") + ] + kwargs = {k: v for k, v in attrs.items() if k not in subtype and k not in readonly + const} + response_obj = response(**kwargs) + for attr in readonly: + setattr(response_obj, attr, attrs.get(attr)) + if additional_properties: + response_obj.additional_properties = additional_properties # type: ignore + return response_obj + except TypeError as err: + msg = "Unable to deserialize {} into model {}. ".format(kwargs, response) # type: ignore + raise DeserializationError(msg + str(err)) from err + else: + try: + for attr, value in attrs.items(): + setattr(response, attr, value) + return response + except Exception as exp: + msg = "Unable to populate response model. " + msg += "Type: {}, Error: {}".format(type(response), exp) + raise DeserializationError(msg) from exp + + def deserialize_data(self, data, data_type): # pylint: disable=too-many-return-statements + """Process data for deserialization according to data type. + + :param str data: The response string to be deserialized. + :param str data_type: The type to deserialize to. + :raises DeserializationError: if deserialization fails. + :return: Deserialized object. + :rtype: object + """ + if data is None: + return data + + try: + if not data_type: + return data + if data_type in self.basic_types.values(): + return self.deserialize_basic(data, data_type) + if data_type in self.deserialize_type: + if isinstance(data, self.deserialize_expected_types.get(data_type, tuple())): + return data + + is_a_text_parsing_type = lambda x: x not in [ # pylint: disable=unnecessary-lambda-assignment + "object", + "[]", + r"{}", + ] + if isinstance(data, ET.Element) and is_a_text_parsing_type(data_type) and not data.text: + return None + data_val = self.deserialize_type[data_type](data) + return data_val + + iter_type = data_type[0] + data_type[-1] + if iter_type in self.deserialize_type: + return self.deserialize_type[iter_type](data, data_type[1:-1]) + + obj_type = self.dependencies[data_type] + if issubclass(obj_type, Enum): + if isinstance(data, ET.Element): + data = data.text + return self.deserialize_enum(data, obj_type) + + except (ValueError, TypeError, AttributeError) as err: + msg = "Unable to deserialize response data." + msg += " Data: {}, {}".format(data, data_type) + raise DeserializationError(msg) from err + return self._deserialize(obj_type, data) + + def deserialize_iter(self, attr, iter_type): + """Deserialize an iterable. + + :param list attr: Iterable to be deserialized. + :param str iter_type: The type of object in the iterable. + :return: Deserialized iterable. + :rtype: list + """ + if attr is None: + return None + if isinstance(attr, ET.Element): # If I receive an element here, get the children + attr = list(attr) + if not isinstance(attr, (list, set)): + raise DeserializationError("Cannot deserialize as [{}] an object of type {}".format(iter_type, type(attr))) + return [self.deserialize_data(a, iter_type) for a in attr] + + def deserialize_dict(self, attr, dict_type): + """Deserialize a dictionary. + + :param dict/list attr: Dictionary to be deserialized. Also accepts + a list of key, value pairs. + :param str dict_type: The object type of the items in the dictionary. + :return: Deserialized dictionary. + :rtype: dict + """ + if isinstance(attr, list): + return {x["key"]: self.deserialize_data(x["value"], dict_type) for x in attr} + + if isinstance(attr, ET.Element): + # Transform value into {"Key": "value"} + attr = {el.tag: el.text for el in attr} + return {k: self.deserialize_data(v, dict_type) for k, v in attr.items()} + + def deserialize_object(self, attr, **kwargs): # pylint: disable=too-many-return-statements + """Deserialize a generic object. + This will be handled as a dictionary. + + :param dict attr: Dictionary to be deserialized. + :return: Deserialized object. + :rtype: dict + :raises TypeError: if non-builtin datatype encountered. + """ + if attr is None: + return None + if isinstance(attr, ET.Element): + # Do no recurse on XML, just return the tree as-is + return attr + if isinstance(attr, str): + return self.deserialize_basic(attr, "str") + obj_type = type(attr) + if obj_type in self.basic_types: + return self.deserialize_basic(attr, self.basic_types[obj_type]) + if obj_type is _long_type: + return self.deserialize_long(attr) + + if obj_type == dict: + deserialized = {} + for key, value in attr.items(): + try: + deserialized[key] = self.deserialize_object(value, **kwargs) + except ValueError: + deserialized[key] = None + return deserialized + + if obj_type == list: + deserialized = [] + for obj in attr: + try: + deserialized.append(self.deserialize_object(obj, **kwargs)) + except ValueError: + pass + return deserialized + + error = "Cannot deserialize generic object with type: " + raise TypeError(error + str(obj_type)) + + def deserialize_basic(self, attr, data_type): # pylint: disable=too-many-return-statements + """Deserialize basic builtin data type from string. + Will attempt to convert to str, int, float and bool. + This function will also accept '1', '0', 'true' and 'false' as + valid bool values. + + :param str attr: response string to be deserialized. + :param str data_type: deserialization data type. + :return: Deserialized basic type. + :rtype: str, int, float or bool + :raises TypeError: if string format is not valid. + """ + # If we're here, data is supposed to be a basic type. + # If it's still an XML node, take the text + if isinstance(attr, ET.Element): + attr = attr.text + if not attr: + if data_type == "str": + # None or '', node is empty string. + return "" + # None or '', node with a strong type is None. + # Don't try to model "empty bool" or "empty int" + return None + + if data_type == "bool": + if attr in [True, False, 1, 0]: + return bool(attr) + if isinstance(attr, str): + if attr.lower() in ["true", "1"]: + return True + if attr.lower() in ["false", "0"]: + return False + raise TypeError("Invalid boolean value: {}".format(attr)) + + if data_type == "str": + return self.deserialize_unicode(attr) + return eval(data_type)(attr) # nosec # pylint: disable=eval-used + + @staticmethod + def deserialize_unicode(data): + """Preserve unicode objects in Python 2, otherwise return data + as a string. + + :param str data: response string to be deserialized. + :return: Deserialized string. + :rtype: str or unicode + """ + # We might be here because we have an enum modeled as string, + # and we try to deserialize a partial dict with enum inside + if isinstance(data, Enum): + return data + + # Consider this is real string + try: + if isinstance(data, unicode): # type: ignore + return data + except NameError: + return str(data) + return str(data) + + @staticmethod + def deserialize_enum(data, enum_obj): + """Deserialize string into enum object. + + If the string is not a valid enum value it will be returned as-is + and a warning will be logged. + + :param str data: Response string to be deserialized. If this value is + None or invalid it will be returned as-is. + :param Enum enum_obj: Enum object to deserialize to. + :return: Deserialized enum object. + :rtype: Enum + """ + if isinstance(data, enum_obj) or data is None: + return data + if isinstance(data, Enum): + data = data.value + if isinstance(data, int): + # Workaround. We might consider remove it in the future. + try: + return list(enum_obj.__members__.values())[data] + except IndexError as exc: + error = "{!r} is not a valid index for enum {!r}" + raise DeserializationError(error.format(data, enum_obj)) from exc + try: + return enum_obj(str(data)) + except ValueError: + for enum_value in enum_obj: + if enum_value.value.lower() == str(data).lower(): + return enum_value + # We don't fail anymore for unknown value, we deserialize as a string + _LOGGER.warning("Deserializer is not able to find %s as valid enum in %s", data, enum_obj) + return Deserializer.deserialize_unicode(data) + + @staticmethod + def deserialize_bytearray(attr): + """Deserialize string into bytearray. + + :param str attr: response string to be deserialized. + :return: Deserialized bytearray + :rtype: bytearray + :raises TypeError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + return bytearray(b64decode(attr)) # type: ignore + + @staticmethod + def deserialize_base64(attr): + """Deserialize base64 encoded string into string. + + :param str attr: response string to be deserialized. + :return: Deserialized base64 string + :rtype: bytearray + :raises TypeError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + padding = "=" * (3 - (len(attr) + 3) % 4) # type: ignore + attr = attr + padding # type: ignore + encoded = attr.replace("-", "+").replace("_", "/") + return b64decode(encoded) + + @staticmethod + def deserialize_decimal(attr): + """Deserialize string into Decimal object. + + :param str attr: response string to be deserialized. + :return: Deserialized decimal + :raises DeserializationError: if string format invalid. + :rtype: decimal + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + return decimal.Decimal(str(attr)) # type: ignore + except decimal.DecimalException as err: + msg = "Invalid decimal {}".format(attr) + raise DeserializationError(msg) from err + + @staticmethod + def deserialize_long(attr): + """Deserialize string into long (Py2) or int (Py3). + + :param str attr: response string to be deserialized. + :return: Deserialized int + :rtype: long or int + :raises ValueError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + return _long_type(attr) # type: ignore + + @staticmethod + def deserialize_duration(attr): + """Deserialize ISO-8601 formatted string into TimeDelta object. + + :param str attr: response string to be deserialized. + :return: Deserialized duration + :rtype: TimeDelta + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + duration = isodate.parse_duration(attr) + except (ValueError, OverflowError, AttributeError) as err: + msg = "Cannot deserialize duration object." + raise DeserializationError(msg) from err + return duration + + @staticmethod + def deserialize_date(attr): + """Deserialize ISO-8601 formatted string into Date object. + + :param str attr: response string to be deserialized. + :return: Deserialized date + :rtype: Date + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + if re.search(r"[^\W\d_]", attr, re.I + re.U): # type: ignore + raise DeserializationError("Date must have only digits and -. Received: %s" % attr) + # This must NOT use defaultmonth/defaultday. Using None ensure this raises an exception. + return isodate.parse_date(attr, defaultmonth=0, defaultday=0) + + @staticmethod + def deserialize_time(attr): + """Deserialize ISO-8601 formatted string into time object. + + :param str attr: response string to be deserialized. + :return: Deserialized time + :rtype: datetime.time + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + if re.search(r"[^\W\d_]", attr, re.I + re.U): # type: ignore + raise DeserializationError("Date must have only digits and -. Received: %s" % attr) + return isodate.parse_time(attr) + + @staticmethod + def deserialize_rfc(attr): + """Deserialize RFC-1123 formatted string into Datetime object. + + :param str attr: response string to be deserialized. + :return: Deserialized RFC datetime + :rtype: Datetime + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + parsed_date = email.utils.parsedate_tz(attr) # type: ignore + date_obj = datetime.datetime( + *parsed_date[:6], tzinfo=datetime.timezone(datetime.timedelta(minutes=(parsed_date[9] or 0) / 60)) + ) + if not date_obj.tzinfo: + date_obj = date_obj.astimezone(tz=TZ_UTC) + except ValueError as err: + msg = "Cannot deserialize to rfc datetime object." + raise DeserializationError(msg) from err + return date_obj + + @staticmethod + def deserialize_iso(attr): + """Deserialize ISO-8601 formatted string into Datetime object. + + :param str attr: response string to be deserialized. + :return: Deserialized ISO datetime + :rtype: Datetime + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + attr = attr.upper() # type: ignore + match = Deserializer.valid_date.match(attr) + if not match: + raise ValueError("Invalid datetime string: " + attr) + + check_decimal = attr.split(".") + if len(check_decimal) > 1: + decimal_str = "" + for digit in check_decimal[1]: + if digit.isdigit(): + decimal_str += digit + else: + break + if len(decimal_str) > 6: + attr = attr.replace(decimal_str, decimal_str[0:6]) + + date_obj = isodate.parse_datetime(attr) + test_utc = date_obj.utctimetuple() + if test_utc.tm_year > 9999 or test_utc.tm_year < 1: + raise OverflowError("Hit max or min date") + except (ValueError, OverflowError, AttributeError) as err: + msg = "Cannot deserialize datetime object." + raise DeserializationError(msg) from err + return date_obj + + @staticmethod + def deserialize_unix(attr): + """Serialize Datetime object into IntTime format. + This is represented as seconds. + + :param int attr: Object to be serialized. + :return: Deserialized datetime + :rtype: Datetime + :raises DeserializationError: if format invalid + """ + if isinstance(attr, ET.Element): + attr = int(attr.text) # type: ignore + try: + attr = int(attr) + date_obj = datetime.datetime.fromtimestamp(attr, TZ_UTC) + except ValueError as err: + msg = "Cannot deserialize to unix datetime object." + raise DeserializationError(msg) from err + return date_obj diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyDurationVersionTolerant/bodydurationversiontolerant/aio/_client.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyDurationVersionTolerant/bodydurationversiontolerant/aio/_client.py index 53753d25a38..449d62630c0 100644 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyDurationVersionTolerant/bodydurationversiontolerant/aio/_client.py +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyDurationVersionTolerant/bodydurationversiontolerant/aio/_client.py @@ -14,7 +14,7 @@ from azure.core.pipeline import policies from azure.core.rest import AsyncHttpResponse, HttpRequest -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import AutoRestDurationTestServiceConfiguration from .operations import DurationOperations diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyDurationVersionTolerant/bodydurationversiontolerant/aio/operations/_operations.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyDurationVersionTolerant/bodydurationversiontolerant/aio/operations/_operations.py index bc829151ae3..0b866955e48 100644 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyDurationVersionTolerant/bodydurationversiontolerant/aio/operations/_operations.py +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyDurationVersionTolerant/bodydurationversiontolerant/aio/operations/_operations.py @@ -23,7 +23,7 @@ from azure.core.tracing.decorator_async import distributed_trace_async from azure.core.utils import case_insensitive_dict -from ..._serialization import Deserializer, Serializer +from ..._utils.serialization import Deserializer, Serializer from ...operations._operations import ( build_duration_get_invalid_request, build_duration_get_null_request, diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyDurationVersionTolerant/bodydurationversiontolerant/operations/_operations.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyDurationVersionTolerant/bodydurationversiontolerant/operations/_operations.py index b4fc8928afe..f7a0268a07d 100644 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyDurationVersionTolerant/bodydurationversiontolerant/operations/_operations.py +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyDurationVersionTolerant/bodydurationversiontolerant/operations/_operations.py @@ -24,7 +24,7 @@ from azure.core.utils import case_insensitive_dict from .._configuration import AutoRestDurationTestServiceConfiguration -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyFileVersionTolerant/bodyfileversiontolerant/_client.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyFileVersionTolerant/bodyfileversiontolerant/_client.py index c912ab3d421..ea2266559e7 100644 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyFileVersionTolerant/bodyfileversiontolerant/_client.py +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyFileVersionTolerant/bodyfileversiontolerant/_client.py @@ -15,7 +15,7 @@ from azure.core.rest import HttpRequest, HttpResponse from ._configuration import AutoRestSwaggerBATFileServiceConfiguration -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer from .operations import FilesOperations diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyFileVersionTolerant/bodyfileversiontolerant/_utils/__init__.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyFileVersionTolerant/bodyfileversiontolerant/_utils/__init__.py new file mode 100644 index 00000000000..0af9b28f660 --- /dev/null +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyFileVersionTolerant/bodyfileversiontolerant/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyFileVersionTolerant/bodyfileversiontolerant/_utils/serialization.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyFileVersionTolerant/bodyfileversiontolerant/_utils/serialization.py new file mode 100644 index 00000000000..f5187701d7b --- /dev/null +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyFileVersionTolerant/bodyfileversiontolerant/_utils/serialization.py @@ -0,0 +1,2032 @@ +# pylint: disable=line-too-long,useless-suppression,too-many-lines +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +# pyright: reportUnnecessaryTypeIgnoreComment=false + +from base64 import b64decode, b64encode +import calendar +import datetime +import decimal +import email +from enum import Enum +import json +import logging +import re +import sys +import codecs +from typing import ( + Dict, + Any, + cast, + Optional, + Union, + AnyStr, + IO, + Mapping, + Callable, + MutableMapping, + List, +) + +try: + from urllib import quote # type: ignore +except ImportError: + from urllib.parse import quote +import xml.etree.ElementTree as ET + +import isodate # type: ignore +from typing_extensions import Self + +from azure.core.exceptions import DeserializationError, SerializationError +from azure.core.serialization import NULL as CoreNull + +_BOM = codecs.BOM_UTF8.decode(encoding="utf-8") + +JSON = MutableMapping[str, Any] + + +class RawDeserializer: + + # Accept "text" because we're open minded people... + JSON_REGEXP = re.compile(r"^(application|text)/([a-z+.]+\+)?json$") + + # Name used in context + CONTEXT_NAME = "deserialized_data" + + @classmethod + def deserialize_from_text(cls, data: Optional[Union[AnyStr, IO]], content_type: Optional[str] = None) -> Any: + """Decode data according to content-type. + + Accept a stream of data as well, but will be load at once in memory for now. + + If no content-type, will return the string version (not bytes, not stream) + + :param data: Input, could be bytes or stream (will be decoded with UTF8) or text + :type data: str or bytes or IO + :param str content_type: The content type. + :return: The deserialized data. + :rtype: object + """ + if hasattr(data, "read"): + # Assume a stream + data = cast(IO, data).read() + + if isinstance(data, bytes): + data_as_str = data.decode(encoding="utf-8-sig") + else: + # Explain to mypy the correct type. + data_as_str = cast(str, data) + + # Remove Byte Order Mark if present in string + data_as_str = data_as_str.lstrip(_BOM) + + if content_type is None: + return data + + if cls.JSON_REGEXP.match(content_type): + try: + return json.loads(data_as_str) + except ValueError as err: + raise DeserializationError("JSON is invalid: {}".format(err), err) from err + elif "xml" in (content_type or []): + try: + + try: + if isinstance(data, unicode): # type: ignore + # If I'm Python 2.7 and unicode XML will scream if I try a "fromstring" on unicode string + data_as_str = data_as_str.encode(encoding="utf-8") # type: ignore + except NameError: + pass + + return ET.fromstring(data_as_str) # nosec + except ET.ParseError as err: + # It might be because the server has an issue, and returned JSON with + # content-type XML.... + # So let's try a JSON load, and if it's still broken + # let's flow the initial exception + def _json_attemp(data): + try: + return True, json.loads(data) + except ValueError: + return False, None # Don't care about this one + + success, json_result = _json_attemp(data) + if success: + return json_result + # If i'm here, it's not JSON, it's not XML, let's scream + # and raise the last context in this block (the XML exception) + # The function hack is because Py2.7 messes up with exception + # context otherwise. + _LOGGER.critical("Wasn't XML not JSON, failing") + raise DeserializationError("XML is invalid") from err + elif content_type.startswith("text/"): + return data_as_str + raise DeserializationError("Cannot deserialize content-type: {}".format(content_type)) + + @classmethod + def deserialize_from_http_generics(cls, body_bytes: Optional[Union[AnyStr, IO]], headers: Mapping) -> Any: + """Deserialize from HTTP response. + + Use bytes and headers to NOT use any requests/aiohttp or whatever + specific implementation. + Headers will tested for "content-type" + + :param bytes body_bytes: The body of the response. + :param dict headers: The headers of the response. + :returns: The deserialized data. + :rtype: object + """ + # Try to use content-type from headers if available + content_type = None + if "content-type" in headers: + content_type = headers["content-type"].split(";")[0].strip().lower() + # Ouch, this server did not declare what it sent... + # Let's guess it's JSON... + # Also, since Autorest was considering that an empty body was a valid JSON, + # need that test as well.... + else: + content_type = "application/json" + + if body_bytes: + return cls.deserialize_from_text(body_bytes, content_type) + return None + + +_LOGGER = logging.getLogger(__name__) + +try: + _long_type = long # type: ignore +except NameError: + _long_type = int + +TZ_UTC = datetime.timezone.utc + +_FLATTEN = re.compile(r"(? None: + self.additional_properties: Optional[Dict[str, Any]] = {} + for k in kwargs: # pylint: disable=consider-using-dict-items + if k not in self._attribute_map: + _LOGGER.warning("%s is not a known attribute of class %s and will be ignored", k, self.__class__) + elif k in self._validation and self._validation[k].get("readonly", False): + _LOGGER.warning("Readonly attribute %s will be ignored in class %s", k, self.__class__) + else: + setattr(self, k, kwargs[k]) + + def __eq__(self, other: Any) -> bool: + """Compare objects by comparing all attributes. + + :param object other: The object to compare + :returns: True if objects are equal + :rtype: bool + """ + if isinstance(other, self.__class__): + return self.__dict__ == other.__dict__ + return False + + def __ne__(self, other: Any) -> bool: + """Compare objects by comparing all attributes. + + :param object other: The object to compare + :returns: True if objects are not equal + :rtype: bool + """ + return not self.__eq__(other) + + def __str__(self) -> str: + return str(self.__dict__) + + @classmethod + def enable_additional_properties_sending(cls) -> None: + cls._attribute_map["additional_properties"] = {"key": "", "type": "{object}"} + + @classmethod + def is_xml_model(cls) -> bool: + try: + cls._xml_map # type: ignore + except AttributeError: + return False + return True + + @classmethod + def _create_xml_node(cls): + """Create XML node. + + :returns: The XML node + :rtype: xml.etree.ElementTree.Element + """ + try: + xml_map = cls._xml_map # type: ignore + except AttributeError: + xml_map = {} + + return _create_xml_node(xml_map.get("name", cls.__name__), xml_map.get("prefix", None), xml_map.get("ns", None)) + + def serialize(self, keep_readonly: bool = False, **kwargs: Any) -> JSON: + """Return the JSON that would be sent to server from this model. + + This is an alias to `as_dict(full_restapi_key_transformer, keep_readonly=False)`. + + If you want XML serialization, you can pass the kwargs is_xml=True. + + :param bool keep_readonly: If you want to serialize the readonly attributes + :returns: A dict JSON compatible object + :rtype: dict + """ + serializer = Serializer(self._infer_class_models()) + return serializer._serialize( # type: ignore # pylint: disable=protected-access + self, keep_readonly=keep_readonly, **kwargs + ) + + def as_dict( + self, + keep_readonly: bool = True, + key_transformer: Callable[[str, Dict[str, Any], Any], Any] = attribute_transformer, + **kwargs: Any + ) -> JSON: + """Return a dict that can be serialized using json.dump. + + Advanced usage might optionally use a callback as parameter: + + .. code::python + + def my_key_transformer(key, attr_desc, value): + return key + + Key is the attribute name used in Python. Attr_desc + is a dict of metadata. Currently contains 'type' with the + msrest type and 'key' with the RestAPI encoded key. + Value is the current value in this object. + + The string returned will be used to serialize the key. + If the return type is a list, this is considered hierarchical + result dict. + + See the three examples in this file: + + - attribute_transformer + - full_restapi_key_transformer + - last_restapi_key_transformer + + If you want XML serialization, you can pass the kwargs is_xml=True. + + :param bool keep_readonly: If you want to serialize the readonly attributes + :param function key_transformer: A key transformer function. + :returns: A dict JSON compatible object + :rtype: dict + """ + serializer = Serializer(self._infer_class_models()) + return serializer._serialize( # type: ignore # pylint: disable=protected-access + self, key_transformer=key_transformer, keep_readonly=keep_readonly, **kwargs + ) + + @classmethod + def _infer_class_models(cls): + try: + str_models = cls.__module__.rsplit(".", 1)[0] + models = sys.modules[str_models] + client_models = {k: v for k, v in models.__dict__.items() if isinstance(v, type)} + if cls.__name__ not in client_models: + raise ValueError("Not Autorest generated code") + except Exception: # pylint: disable=broad-exception-caught + # Assume it's not Autorest generated (tests?). Add ourselves as dependencies. + client_models = {cls.__name__: cls} + return client_models + + @classmethod + def deserialize(cls, data: Any, content_type: Optional[str] = None) -> Self: + """Parse a str using the RestAPI syntax and return a model. + + :param str data: A str using RestAPI structure. JSON by default. + :param str content_type: JSON by default, set application/xml if XML. + :returns: An instance of this model + :raises DeserializationError: if something went wrong + :rtype: Self + """ + deserializer = Deserializer(cls._infer_class_models()) + return deserializer(cls.__name__, data, content_type=content_type) # type: ignore + + @classmethod + def from_dict( + cls, + data: Any, + key_extractors: Optional[Callable[[str, Dict[str, Any], Any], Any]] = None, + content_type: Optional[str] = None, + ) -> Self: + """Parse a dict using given key extractor return a model. + + By default consider key + extractors (rest_key_case_insensitive_extractor, attribute_key_case_insensitive_extractor + and last_rest_key_case_insensitive_extractor) + + :param dict data: A dict using RestAPI structure + :param function key_extractors: A key extractor function. + :param str content_type: JSON by default, set application/xml if XML. + :returns: An instance of this model + :raises DeserializationError: if something went wrong + :rtype: Self + """ + deserializer = Deserializer(cls._infer_class_models()) + deserializer.key_extractors = ( # type: ignore + [ # type: ignore + attribute_key_case_insensitive_extractor, + rest_key_case_insensitive_extractor, + last_rest_key_case_insensitive_extractor, + ] + if key_extractors is None + else key_extractors + ) + return deserializer(cls.__name__, data, content_type=content_type) # type: ignore + + @classmethod + def _flatten_subtype(cls, key, objects): + if "_subtype_map" not in cls.__dict__: + return {} + result = dict(cls._subtype_map[key]) + for valuetype in cls._subtype_map[key].values(): + result.update(objects[valuetype]._flatten_subtype(key, objects)) # pylint: disable=protected-access + return result + + @classmethod + def _classify(cls, response, objects): + """Check the class _subtype_map for any child classes. + We want to ignore any inherited _subtype_maps. + + :param dict response: The initial data + :param dict objects: The class objects + :returns: The class to be used + :rtype: class + """ + for subtype_key in cls.__dict__.get("_subtype_map", {}).keys(): + subtype_value = None + + if not isinstance(response, ET.Element): + rest_api_response_key = cls._get_rest_key_parts(subtype_key)[-1] + subtype_value = response.get(rest_api_response_key, None) or response.get(subtype_key, None) + else: + subtype_value = xml_key_extractor(subtype_key, cls._attribute_map[subtype_key], response) + if subtype_value: + # Try to match base class. Can be class name only + # (bug to fix in Autorest to support x-ms-discriminator-name) + if cls.__name__ == subtype_value: + return cls + flatten_mapping_type = cls._flatten_subtype(subtype_key, objects) + try: + return objects[flatten_mapping_type[subtype_value]] # type: ignore + except KeyError: + _LOGGER.warning( + "Subtype value %s has no mapping, use base class %s.", + subtype_value, + cls.__name__, + ) + break + else: + _LOGGER.warning("Discriminator %s is absent or null, use base class %s.", subtype_key, cls.__name__) + break + return cls + + @classmethod + def _get_rest_key_parts(cls, attr_key): + """Get the RestAPI key of this attr, split it and decode part + :param str attr_key: Attribute key must be in attribute_map. + :returns: A list of RestAPI part + :rtype: list + """ + rest_split_key = _FLATTEN.split(cls._attribute_map[attr_key]["key"]) + return [_decode_attribute_map_key(key_part) for key_part in rest_split_key] + + +def _decode_attribute_map_key(key): + """This decode a key in an _attribute_map to the actual key we want to look at + inside the received data. + + :param str key: A key string from the generated code + :returns: The decoded key + :rtype: str + """ + return key.replace("\\.", ".") + + +class Serializer: # pylint: disable=too-many-public-methods + """Request object model serializer.""" + + basic_types = {str: "str", int: "int", bool: "bool", float: "float"} + + _xml_basic_types_serializers = {"bool": lambda x: str(x).lower()} + days = {0: "Mon", 1: "Tue", 2: "Wed", 3: "Thu", 4: "Fri", 5: "Sat", 6: "Sun"} + months = { + 1: "Jan", + 2: "Feb", + 3: "Mar", + 4: "Apr", + 5: "May", + 6: "Jun", + 7: "Jul", + 8: "Aug", + 9: "Sep", + 10: "Oct", + 11: "Nov", + 12: "Dec", + } + validation = { + "min_length": lambda x, y: len(x) < y, + "max_length": lambda x, y: len(x) > y, + "minimum": lambda x, y: x < y, + "maximum": lambda x, y: x > y, + "minimum_ex": lambda x, y: x <= y, + "maximum_ex": lambda x, y: x >= y, + "min_items": lambda x, y: len(x) < y, + "max_items": lambda x, y: len(x) > y, + "pattern": lambda x, y: not re.match(y, x, re.UNICODE), + "unique": lambda x, y: len(x) != len(set(x)), + "multiple": lambda x, y: x % y != 0, + } + + def __init__(self, classes: Optional[Mapping[str, type]] = None) -> None: + self.serialize_type = { + "iso-8601": Serializer.serialize_iso, + "rfc-1123": Serializer.serialize_rfc, + "unix-time": Serializer.serialize_unix, + "duration": Serializer.serialize_duration, + "date": Serializer.serialize_date, + "time": Serializer.serialize_time, + "decimal": Serializer.serialize_decimal, + "long": Serializer.serialize_long, + "bytearray": Serializer.serialize_bytearray, + "base64": Serializer.serialize_base64, + "object": self.serialize_object, + "[]": self.serialize_iter, + "{}": self.serialize_dict, + } + self.dependencies: Dict[str, type] = dict(classes) if classes else {} + self.key_transformer = full_restapi_key_transformer + self.client_side_validation = True + + def _serialize( # pylint: disable=too-many-nested-blocks, too-many-branches, too-many-statements, too-many-locals + self, target_obj, data_type=None, **kwargs + ): + """Serialize data into a string according to type. + + :param object target_obj: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str, dict + :raises SerializationError: if serialization fails. + :returns: The serialized data. + """ + key_transformer = kwargs.get("key_transformer", self.key_transformer) + keep_readonly = kwargs.get("keep_readonly", False) + if target_obj is None: + return None + + attr_name = None + class_name = target_obj.__class__.__name__ + + if data_type: + return self.serialize_data(target_obj, data_type, **kwargs) + + if not hasattr(target_obj, "_attribute_map"): + data_type = type(target_obj).__name__ + if data_type in self.basic_types.values(): + return self.serialize_data(target_obj, data_type, **kwargs) + + # Force "is_xml" kwargs if we detect a XML model + try: + is_xml_model_serialization = kwargs["is_xml"] + except KeyError: + is_xml_model_serialization = kwargs.setdefault("is_xml", target_obj.is_xml_model()) + + serialized = {} + if is_xml_model_serialization: + serialized = target_obj._create_xml_node() # pylint: disable=protected-access + try: + attributes = target_obj._attribute_map # pylint: disable=protected-access + for attr, attr_desc in attributes.items(): + attr_name = attr + if not keep_readonly and target_obj._validation.get( # pylint: disable=protected-access + attr_name, {} + ).get("readonly", False): + continue + + if attr_name == "additional_properties" and attr_desc["key"] == "": + if target_obj.additional_properties is not None: + serialized.update(target_obj.additional_properties) + continue + try: + + orig_attr = getattr(target_obj, attr) + if is_xml_model_serialization: + pass # Don't provide "transformer" for XML for now. Keep "orig_attr" + else: # JSON + keys, orig_attr = key_transformer(attr, attr_desc.copy(), orig_attr) + keys = keys if isinstance(keys, list) else [keys] + + kwargs["serialization_ctxt"] = attr_desc + new_attr = self.serialize_data(orig_attr, attr_desc["type"], **kwargs) + + if is_xml_model_serialization: + xml_desc = attr_desc.get("xml", {}) + xml_name = xml_desc.get("name", attr_desc["key"]) + xml_prefix = xml_desc.get("prefix", None) + xml_ns = xml_desc.get("ns", None) + if xml_desc.get("attr", False): + if xml_ns: + ET.register_namespace(xml_prefix, xml_ns) + xml_name = "{{{}}}{}".format(xml_ns, xml_name) + serialized.set(xml_name, new_attr) # type: ignore + continue + if xml_desc.get("text", False): + serialized.text = new_attr # type: ignore + continue + if isinstance(new_attr, list): + serialized.extend(new_attr) # type: ignore + elif isinstance(new_attr, ET.Element): + # If the down XML has no XML/Name, + # we MUST replace the tag with the local tag. But keeping the namespaces. + if "name" not in getattr(orig_attr, "_xml_map", {}): + splitted_tag = new_attr.tag.split("}") + if len(splitted_tag) == 2: # Namespace + new_attr.tag = "}".join([splitted_tag[0], xml_name]) + else: + new_attr.tag = xml_name + serialized.append(new_attr) # type: ignore + else: # That's a basic type + # Integrate namespace if necessary + local_node = _create_xml_node(xml_name, xml_prefix, xml_ns) + local_node.text = str(new_attr) + serialized.append(local_node) # type: ignore + else: # JSON + for k in reversed(keys): # type: ignore + new_attr = {k: new_attr} + + _new_attr = new_attr + _serialized = serialized + for k in keys: # type: ignore + if k not in _serialized: + _serialized.update(_new_attr) # type: ignore + _new_attr = _new_attr[k] # type: ignore + _serialized = _serialized[k] + except ValueError as err: + if isinstance(err, SerializationError): + raise + + except (AttributeError, KeyError, TypeError) as err: + msg = "Attribute {} in object {} cannot be serialized.\n{}".format(attr_name, class_name, str(target_obj)) + raise SerializationError(msg) from err + return serialized + + def body(self, data, data_type, **kwargs): + """Serialize data intended for a request body. + + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: dict + :raises SerializationError: if serialization fails. + :raises ValueError: if data is None + :returns: The serialized request body + """ + + # Just in case this is a dict + internal_data_type_str = data_type.strip("[]{}") + internal_data_type = self.dependencies.get(internal_data_type_str, None) + try: + is_xml_model_serialization = kwargs["is_xml"] + except KeyError: + if internal_data_type and issubclass(internal_data_type, Model): + is_xml_model_serialization = kwargs.setdefault("is_xml", internal_data_type.is_xml_model()) + else: + is_xml_model_serialization = False + if internal_data_type and not isinstance(internal_data_type, Enum): + try: + deserializer = Deserializer(self.dependencies) + # Since it's on serialization, it's almost sure that format is not JSON REST + # We're not able to deal with additional properties for now. + deserializer.additional_properties_detection = False + if is_xml_model_serialization: + deserializer.key_extractors = [ # type: ignore + attribute_key_case_insensitive_extractor, + ] + else: + deserializer.key_extractors = [ + rest_key_case_insensitive_extractor, + attribute_key_case_insensitive_extractor, + last_rest_key_case_insensitive_extractor, + ] + data = deserializer._deserialize(data_type, data) # pylint: disable=protected-access + except DeserializationError as err: + raise SerializationError("Unable to build a model: " + str(err)) from err + + return self._serialize(data, data_type, **kwargs) + + def url(self, name, data, data_type, **kwargs): + """Serialize data intended for a URL path. + + :param str name: The name of the URL path parameter. + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str + :returns: The serialized URL path + :raises TypeError: if serialization fails. + :raises ValueError: if data is None + """ + try: + output = self.serialize_data(data, data_type, **kwargs) + if data_type == "bool": + output = json.dumps(output) + + if kwargs.get("skip_quote") is True: + output = str(output) + output = output.replace("{", quote("{")).replace("}", quote("}")) + else: + output = quote(str(output), safe="") + except SerializationError as exc: + raise TypeError("{} must be type {}.".format(name, data_type)) from exc + return output + + def query(self, name, data, data_type, **kwargs): + """Serialize data intended for a URL query. + + :param str name: The name of the query parameter. + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str, list + :raises TypeError: if serialization fails. + :raises ValueError: if data is None + :returns: The serialized query parameter + """ + try: + # Treat the list aside, since we don't want to encode the div separator + if data_type.startswith("["): + internal_data_type = data_type[1:-1] + do_quote = not kwargs.get("skip_quote", False) + return self.serialize_iter(data, internal_data_type, do_quote=do_quote, **kwargs) + + # Not a list, regular serialization + output = self.serialize_data(data, data_type, **kwargs) + if data_type == "bool": + output = json.dumps(output) + if kwargs.get("skip_quote") is True: + output = str(output) + else: + output = quote(str(output), safe="") + except SerializationError as exc: + raise TypeError("{} must be type {}.".format(name, data_type)) from exc + return str(output) + + def header(self, name, data, data_type, **kwargs): + """Serialize data intended for a request header. + + :param str name: The name of the header. + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str + :raises TypeError: if serialization fails. + :raises ValueError: if data is None + :returns: The serialized header + """ + try: + if data_type in ["[str]"]: + data = ["" if d is None else d for d in data] + + output = self.serialize_data(data, data_type, **kwargs) + if data_type == "bool": + output = json.dumps(output) + except SerializationError as exc: + raise TypeError("{} must be type {}.".format(name, data_type)) from exc + return str(output) + + def serialize_data(self, data, data_type, **kwargs): + """Serialize generic data according to supplied data type. + + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :raises AttributeError: if required data is None. + :raises ValueError: if data is None + :raises SerializationError: if serialization fails. + :returns: The serialized data. + :rtype: str, int, float, bool, dict, list + """ + if data is None: + raise ValueError("No value for given attribute") + + try: + if data is CoreNull: + return None + if data_type in self.basic_types.values(): + return self.serialize_basic(data, data_type, **kwargs) + + if data_type in self.serialize_type: + return self.serialize_type[data_type](data, **kwargs) + + # If dependencies is empty, try with current data class + # It has to be a subclass of Enum anyway + enum_type = self.dependencies.get(data_type, data.__class__) + if issubclass(enum_type, Enum): + return Serializer.serialize_enum(data, enum_obj=enum_type) + + iter_type = data_type[0] + data_type[-1] + if iter_type in self.serialize_type: + return self.serialize_type[iter_type](data, data_type[1:-1], **kwargs) + + except (ValueError, TypeError) as err: + msg = "Unable to serialize value: {!r} as type: {!r}." + raise SerializationError(msg.format(data, data_type)) from err + return self._serialize(data, **kwargs) + + @classmethod + def _get_custom_serializers(cls, data_type, **kwargs): # pylint: disable=inconsistent-return-statements + custom_serializer = kwargs.get("basic_types_serializers", {}).get(data_type) + if custom_serializer: + return custom_serializer + if kwargs.get("is_xml", False): + return cls._xml_basic_types_serializers.get(data_type) + + @classmethod + def serialize_basic(cls, data, data_type, **kwargs): + """Serialize basic builting data type. + Serializes objects to str, int, float or bool. + + Possible kwargs: + - basic_types_serializers dict[str, callable] : If set, use the callable as serializer + - is_xml bool : If set, use xml_basic_types_serializers + + :param obj data: Object to be serialized. + :param str data_type: Type of object in the iterable. + :rtype: str, int, float, bool + :return: serialized object + """ + custom_serializer = cls._get_custom_serializers(data_type, **kwargs) + if custom_serializer: + return custom_serializer(data) + if data_type == "str": + return cls.serialize_unicode(data) + return eval(data_type)(data) # nosec # pylint: disable=eval-used + + @classmethod + def serialize_unicode(cls, data): + """Special handling for serializing unicode strings in Py2. + Encode to UTF-8 if unicode, otherwise handle as a str. + + :param str data: Object to be serialized. + :rtype: str + :return: serialized object + """ + try: # If I received an enum, return its value + return data.value + except AttributeError: + pass + + try: + if isinstance(data, unicode): # type: ignore + # Don't change it, JSON and XML ElementTree are totally able + # to serialize correctly u'' strings + return data + except NameError: + return str(data) + return str(data) + + def serialize_iter(self, data, iter_type, div=None, **kwargs): + """Serialize iterable. + + Supported kwargs: + - serialization_ctxt dict : The current entry of _attribute_map, or same format. + serialization_ctxt['type'] should be same as data_type. + - is_xml bool : If set, serialize as XML + + :param list data: Object to be serialized. + :param str iter_type: Type of object in the iterable. + :param str div: If set, this str will be used to combine the elements + in the iterable into a combined string. Default is 'None'. + Defaults to False. + :rtype: list, str + :return: serialized iterable + """ + if isinstance(data, str): + raise SerializationError("Refuse str type as a valid iter type.") + + serialization_ctxt = kwargs.get("serialization_ctxt", {}) + is_xml = kwargs.get("is_xml", False) + + serialized = [] + for d in data: + try: + serialized.append(self.serialize_data(d, iter_type, **kwargs)) + except ValueError as err: + if isinstance(err, SerializationError): + raise + serialized.append(None) + + if kwargs.get("do_quote", False): + serialized = ["" if s is None else quote(str(s), safe="") for s in serialized] + + if div: + serialized = ["" if s is None else str(s) for s in serialized] + serialized = div.join(serialized) + + if "xml" in serialization_ctxt or is_xml: + # XML serialization is more complicated + xml_desc = serialization_ctxt.get("xml", {}) + xml_name = xml_desc.get("name") + if not xml_name: + xml_name = serialization_ctxt["key"] + + # Create a wrap node if necessary (use the fact that Element and list have "append") + is_wrapped = xml_desc.get("wrapped", False) + node_name = xml_desc.get("itemsName", xml_name) + if is_wrapped: + final_result = _create_xml_node(xml_name, xml_desc.get("prefix", None), xml_desc.get("ns", None)) + else: + final_result = [] + # All list elements to "local_node" + for el in serialized: + if isinstance(el, ET.Element): + el_node = el + else: + el_node = _create_xml_node(node_name, xml_desc.get("prefix", None), xml_desc.get("ns", None)) + if el is not None: # Otherwise it writes "None" :-p + el_node.text = str(el) + final_result.append(el_node) + return final_result + return serialized + + def serialize_dict(self, attr, dict_type, **kwargs): + """Serialize a dictionary of objects. + + :param dict attr: Object to be serialized. + :param str dict_type: Type of object in the dictionary. + :rtype: dict + :return: serialized dictionary + """ + serialization_ctxt = kwargs.get("serialization_ctxt", {}) + serialized = {} + for key, value in attr.items(): + try: + serialized[self.serialize_unicode(key)] = self.serialize_data(value, dict_type, **kwargs) + except ValueError as err: + if isinstance(err, SerializationError): + raise + serialized[self.serialize_unicode(key)] = None + + if "xml" in serialization_ctxt: + # XML serialization is more complicated + xml_desc = serialization_ctxt["xml"] + xml_name = xml_desc["name"] + + final_result = _create_xml_node(xml_name, xml_desc.get("prefix", None), xml_desc.get("ns", None)) + for key, value in serialized.items(): + ET.SubElement(final_result, key).text = value + return final_result + + return serialized + + def serialize_object(self, attr, **kwargs): # pylint: disable=too-many-return-statements + """Serialize a generic object. + This will be handled as a dictionary. If object passed in is not + a basic type (str, int, float, dict, list) it will simply be + cast to str. + + :param dict attr: Object to be serialized. + :rtype: dict or str + :return: serialized object + """ + if attr is None: + return None + if isinstance(attr, ET.Element): + return attr + obj_type = type(attr) + if obj_type in self.basic_types: + return self.serialize_basic(attr, self.basic_types[obj_type], **kwargs) + if obj_type is _long_type: + return self.serialize_long(attr) + if obj_type is str: + return self.serialize_unicode(attr) + if obj_type is datetime.datetime: + return self.serialize_iso(attr) + if obj_type is datetime.date: + return self.serialize_date(attr) + if obj_type is datetime.time: + return self.serialize_time(attr) + if obj_type is datetime.timedelta: + return self.serialize_duration(attr) + if obj_type is decimal.Decimal: + return self.serialize_decimal(attr) + + # If it's a model or I know this dependency, serialize as a Model + if obj_type in self.dependencies.values() or isinstance(attr, Model): + return self._serialize(attr) + + if obj_type == dict: + serialized = {} + for key, value in attr.items(): + try: + serialized[self.serialize_unicode(key)] = self.serialize_object(value, **kwargs) + except ValueError: + serialized[self.serialize_unicode(key)] = None + return serialized + + if obj_type == list: + serialized = [] + for obj in attr: + try: + serialized.append(self.serialize_object(obj, **kwargs)) + except ValueError: + pass + return serialized + return str(attr) + + @staticmethod + def serialize_enum(attr, enum_obj=None): + try: + result = attr.value + except AttributeError: + result = attr + try: + enum_obj(result) # type: ignore + return result + except ValueError as exc: + for enum_value in enum_obj: # type: ignore + if enum_value.value.lower() == str(attr).lower(): + return enum_value.value + error = "{!r} is not valid value for enum {!r}" + raise SerializationError(error.format(attr, enum_obj)) from exc + + @staticmethod + def serialize_bytearray(attr, **kwargs): # pylint: disable=unused-argument + """Serialize bytearray into base-64 string. + + :param str attr: Object to be serialized. + :rtype: str + :return: serialized base64 + """ + return b64encode(attr).decode() + + @staticmethod + def serialize_base64(attr, **kwargs): # pylint: disable=unused-argument + """Serialize str into base-64 string. + + :param str attr: Object to be serialized. + :rtype: str + :return: serialized base64 + """ + encoded = b64encode(attr).decode("ascii") + return encoded.strip("=").replace("+", "-").replace("/", "_") + + @staticmethod + def serialize_decimal(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Decimal object to float. + + :param decimal attr: Object to be serialized. + :rtype: float + :return: serialized decimal + """ + return float(attr) + + @staticmethod + def serialize_long(attr, **kwargs): # pylint: disable=unused-argument + """Serialize long (Py2) or int (Py3). + + :param int attr: Object to be serialized. + :rtype: int/long + :return: serialized long + """ + return _long_type(attr) + + @staticmethod + def serialize_date(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Date object into ISO-8601 formatted string. + + :param Date attr: Object to be serialized. + :rtype: str + :return: serialized date + """ + if isinstance(attr, str): + attr = isodate.parse_date(attr) + t = "{:04}-{:02}-{:02}".format(attr.year, attr.month, attr.day) + return t + + @staticmethod + def serialize_time(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Time object into ISO-8601 formatted string. + + :param datetime.time attr: Object to be serialized. + :rtype: str + :return: serialized time + """ + if isinstance(attr, str): + attr = isodate.parse_time(attr) + t = "{:02}:{:02}:{:02}".format(attr.hour, attr.minute, attr.second) + if attr.microsecond: + t += ".{:02}".format(attr.microsecond) + return t + + @staticmethod + def serialize_duration(attr, **kwargs): # pylint: disable=unused-argument + """Serialize TimeDelta object into ISO-8601 formatted string. + + :param TimeDelta attr: Object to be serialized. + :rtype: str + :return: serialized duration + """ + if isinstance(attr, str): + attr = isodate.parse_duration(attr) + return isodate.duration_isoformat(attr) + + @staticmethod + def serialize_rfc(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Datetime object into RFC-1123 formatted string. + + :param Datetime attr: Object to be serialized. + :rtype: str + :raises TypeError: if format invalid. + :return: serialized rfc + """ + try: + if not attr.tzinfo: + _LOGGER.warning("Datetime with no tzinfo will be considered UTC.") + utc = attr.utctimetuple() + except AttributeError as exc: + raise TypeError("RFC1123 object must be valid Datetime object.") from exc + + return "{}, {:02} {} {:04} {:02}:{:02}:{:02} GMT".format( + Serializer.days[utc.tm_wday], + utc.tm_mday, + Serializer.months[utc.tm_mon], + utc.tm_year, + utc.tm_hour, + utc.tm_min, + utc.tm_sec, + ) + + @staticmethod + def serialize_iso(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Datetime object into ISO-8601 formatted string. + + :param Datetime attr: Object to be serialized. + :rtype: str + :raises SerializationError: if format invalid. + :return: serialized iso + """ + if isinstance(attr, str): + attr = isodate.parse_datetime(attr) + try: + if not attr.tzinfo: + _LOGGER.warning("Datetime with no tzinfo will be considered UTC.") + utc = attr.utctimetuple() + if utc.tm_year > 9999 or utc.tm_year < 1: + raise OverflowError("Hit max or min date") + + microseconds = str(attr.microsecond).rjust(6, "0").rstrip("0").ljust(3, "0") + if microseconds: + microseconds = "." + microseconds + date = "{:04}-{:02}-{:02}T{:02}:{:02}:{:02}".format( + utc.tm_year, utc.tm_mon, utc.tm_mday, utc.tm_hour, utc.tm_min, utc.tm_sec + ) + return date + microseconds + "Z" + except (ValueError, OverflowError) as err: + msg = "Unable to serialize datetime object." + raise SerializationError(msg) from err + except AttributeError as err: + msg = "ISO-8601 object must be valid Datetime object." + raise TypeError(msg) from err + + @staticmethod + def serialize_unix(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Datetime object into IntTime format. + This is represented as seconds. + + :param Datetime attr: Object to be serialized. + :rtype: int + :raises SerializationError: if format invalid + :return: serialied unix + """ + if isinstance(attr, int): + return attr + try: + if not attr.tzinfo: + _LOGGER.warning("Datetime with no tzinfo will be considered UTC.") + return int(calendar.timegm(attr.utctimetuple())) + except AttributeError as exc: + raise TypeError("Unix time object must be valid Datetime object.") from exc + + +def rest_key_extractor(attr, attr_desc, data): # pylint: disable=unused-argument + key = attr_desc["key"] + working_data = data + + while "." in key: + # Need the cast, as for some reasons "split" is typed as list[str | Any] + dict_keys = cast(List[str], _FLATTEN.split(key)) + if len(dict_keys) == 1: + key = _decode_attribute_map_key(dict_keys[0]) + break + working_key = _decode_attribute_map_key(dict_keys[0]) + working_data = working_data.get(working_key, data) + if working_data is None: + # If at any point while following flatten JSON path see None, it means + # that all properties under are None as well + return None + key = ".".join(dict_keys[1:]) + + return working_data.get(key) + + +def rest_key_case_insensitive_extractor( # pylint: disable=unused-argument, inconsistent-return-statements + attr, attr_desc, data +): + key = attr_desc["key"] + working_data = data + + while "." in key: + dict_keys = _FLATTEN.split(key) + if len(dict_keys) == 1: + key = _decode_attribute_map_key(dict_keys[0]) + break + working_key = _decode_attribute_map_key(dict_keys[0]) + working_data = attribute_key_case_insensitive_extractor(working_key, None, working_data) + if working_data is None: + # If at any point while following flatten JSON path see None, it means + # that all properties under are None as well + return None + key = ".".join(dict_keys[1:]) + + if working_data: + return attribute_key_case_insensitive_extractor(key, None, working_data) + + +def last_rest_key_extractor(attr, attr_desc, data): # pylint: disable=unused-argument + """Extract the attribute in "data" based on the last part of the JSON path key. + + :param str attr: The attribute to extract + :param dict attr_desc: The attribute description + :param dict data: The data to extract from + :rtype: object + :returns: The extracted attribute + """ + key = attr_desc["key"] + dict_keys = _FLATTEN.split(key) + return attribute_key_extractor(dict_keys[-1], None, data) + + +def last_rest_key_case_insensitive_extractor(attr, attr_desc, data): # pylint: disable=unused-argument + """Extract the attribute in "data" based on the last part of the JSON path key. + + This is the case insensitive version of "last_rest_key_extractor" + :param str attr: The attribute to extract + :param dict attr_desc: The attribute description + :param dict data: The data to extract from + :rtype: object + :returns: The extracted attribute + """ + key = attr_desc["key"] + dict_keys = _FLATTEN.split(key) + return attribute_key_case_insensitive_extractor(dict_keys[-1], None, data) + + +def attribute_key_extractor(attr, _, data): + return data.get(attr) + + +def attribute_key_case_insensitive_extractor(attr, _, data): + found_key = None + lower_attr = attr.lower() + for key in data: + if lower_attr == key.lower(): + found_key = key + break + + return data.get(found_key) + + +def _extract_name_from_internal_type(internal_type): + """Given an internal type XML description, extract correct XML name with namespace. + + :param dict internal_type: An model type + :rtype: tuple + :returns: A tuple XML name + namespace dict + """ + internal_type_xml_map = getattr(internal_type, "_xml_map", {}) + xml_name = internal_type_xml_map.get("name", internal_type.__name__) + xml_ns = internal_type_xml_map.get("ns", None) + if xml_ns: + xml_name = "{{{}}}{}".format(xml_ns, xml_name) + return xml_name + + +def xml_key_extractor(attr, attr_desc, data): # pylint: disable=unused-argument,too-many-return-statements + if isinstance(data, dict): + return None + + # Test if this model is XML ready first + if not isinstance(data, ET.Element): + return None + + xml_desc = attr_desc.get("xml", {}) + xml_name = xml_desc.get("name", attr_desc["key"]) + + # Look for a children + is_iter_type = attr_desc["type"].startswith("[") + is_wrapped = xml_desc.get("wrapped", False) + internal_type = attr_desc.get("internalType", None) + internal_type_xml_map = getattr(internal_type, "_xml_map", {}) + + # Integrate namespace if necessary + xml_ns = xml_desc.get("ns", internal_type_xml_map.get("ns", None)) + if xml_ns: + xml_name = "{{{}}}{}".format(xml_ns, xml_name) + + # If it's an attribute, that's simple + if xml_desc.get("attr", False): + return data.get(xml_name) + + # If it's x-ms-text, that's simple too + if xml_desc.get("text", False): + return data.text + + # Scenario where I take the local name: + # - Wrapped node + # - Internal type is an enum (considered basic types) + # - Internal type has no XML/Name node + if is_wrapped or (internal_type and (issubclass(internal_type, Enum) or "name" not in internal_type_xml_map)): + children = data.findall(xml_name) + # If internal type has a local name and it's not a list, I use that name + elif not is_iter_type and internal_type and "name" in internal_type_xml_map: + xml_name = _extract_name_from_internal_type(internal_type) + children = data.findall(xml_name) + # That's an array + else: + if internal_type: # Complex type, ignore itemsName and use the complex type name + items_name = _extract_name_from_internal_type(internal_type) + else: + items_name = xml_desc.get("itemsName", xml_name) + children = data.findall(items_name) + + if len(children) == 0: + if is_iter_type: + if is_wrapped: + return None # is_wrapped no node, we want None + return [] # not wrapped, assume empty list + return None # Assume it's not there, maybe an optional node. + + # If is_iter_type and not wrapped, return all found children + if is_iter_type: + if not is_wrapped: + return children + # Iter and wrapped, should have found one node only (the wrap one) + if len(children) != 1: + raise DeserializationError( + "Tried to deserialize an array not wrapped, and found several nodes '{}'. Maybe you should declare this array as wrapped?".format( + xml_name + ) + ) + return list(children[0]) # Might be empty list and that's ok. + + # Here it's not a itertype, we should have found one element only or empty + if len(children) > 1: + raise DeserializationError("Find several XML '{}' where it was not expected".format(xml_name)) + return children[0] + + +class Deserializer: + """Response object model deserializer. + + :param dict classes: Class type dictionary for deserializing complex types. + :ivar list key_extractors: Ordered list of extractors to be used by this deserializer. + """ + + basic_types = {str: "str", int: "int", bool: "bool", float: "float"} + + valid_date = re.compile(r"\d{4}[-]\d{2}[-]\d{2}T\d{2}:\d{2}:\d{2}\.?\d*Z?[-+]?[\d{2}]?:?[\d{2}]?") + + def __init__(self, classes: Optional[Mapping[str, type]] = None) -> None: + self.deserialize_type = { + "iso-8601": Deserializer.deserialize_iso, + "rfc-1123": Deserializer.deserialize_rfc, + "unix-time": Deserializer.deserialize_unix, + "duration": Deserializer.deserialize_duration, + "date": Deserializer.deserialize_date, + "time": Deserializer.deserialize_time, + "decimal": Deserializer.deserialize_decimal, + "long": Deserializer.deserialize_long, + "bytearray": Deserializer.deserialize_bytearray, + "base64": Deserializer.deserialize_base64, + "object": self.deserialize_object, + "[]": self.deserialize_iter, + "{}": self.deserialize_dict, + } + self.deserialize_expected_types = { + "duration": (isodate.Duration, datetime.timedelta), + "iso-8601": (datetime.datetime), + } + self.dependencies: Dict[str, type] = dict(classes) if classes else {} + self.key_extractors = [rest_key_extractor, xml_key_extractor] + # Additional properties only works if the "rest_key_extractor" is used to + # extract the keys. Making it to work whatever the key extractor is too much + # complicated, with no real scenario for now. + # So adding a flag to disable additional properties detection. This flag should be + # used if your expect the deserialization to NOT come from a JSON REST syntax. + # Otherwise, result are unexpected + self.additional_properties_detection = True + + def __call__(self, target_obj, response_data, content_type=None): + """Call the deserializer to process a REST response. + + :param str target_obj: Target data type to deserialize to. + :param requests.Response response_data: REST response object. + :param str content_type: Swagger "produces" if available. + :raises DeserializationError: if deserialization fails. + :return: Deserialized object. + :rtype: object + """ + data = self._unpack_content(response_data, content_type) + return self._deserialize(target_obj, data) + + def _deserialize(self, target_obj, data): # pylint: disable=inconsistent-return-statements + """Call the deserializer on a model. + + Data needs to be already deserialized as JSON or XML ElementTree + + :param str target_obj: Target data type to deserialize to. + :param object data: Object to deserialize. + :raises DeserializationError: if deserialization fails. + :return: Deserialized object. + :rtype: object + """ + # This is already a model, go recursive just in case + if hasattr(data, "_attribute_map"): + constants = [name for name, config in getattr(data, "_validation", {}).items() if config.get("constant")] + try: + for attr, mapconfig in data._attribute_map.items(): # pylint: disable=protected-access + if attr in constants: + continue + value = getattr(data, attr) + if value is None: + continue + local_type = mapconfig["type"] + internal_data_type = local_type.strip("[]{}") + if internal_data_type not in self.dependencies or isinstance(internal_data_type, Enum): + continue + setattr(data, attr, self._deserialize(local_type, value)) + return data + except AttributeError: + return + + response, class_name = self._classify_target(target_obj, data) + + if isinstance(response, str): + return self.deserialize_data(data, response) + if isinstance(response, type) and issubclass(response, Enum): + return self.deserialize_enum(data, response) + + if data is None or data is CoreNull: + return data + try: + attributes = response._attribute_map # type: ignore # pylint: disable=protected-access + d_attrs = {} + for attr, attr_desc in attributes.items(): + # Check empty string. If it's not empty, someone has a real "additionalProperties"... + if attr == "additional_properties" and attr_desc["key"] == "": + continue + raw_value = None + # Enhance attr_desc with some dynamic data + attr_desc = attr_desc.copy() # Do a copy, do not change the real one + internal_data_type = attr_desc["type"].strip("[]{}") + if internal_data_type in self.dependencies: + attr_desc["internalType"] = self.dependencies[internal_data_type] + + for key_extractor in self.key_extractors: + found_value = key_extractor(attr, attr_desc, data) + if found_value is not None: + if raw_value is not None and raw_value != found_value: + msg = ( + "Ignoring extracted value '%s' from %s for key '%s'" + " (duplicate extraction, follow extractors order)" + ) + _LOGGER.warning(msg, found_value, key_extractor, attr) + continue + raw_value = found_value + + value = self.deserialize_data(raw_value, attr_desc["type"]) + d_attrs[attr] = value + except (AttributeError, TypeError, KeyError) as err: + msg = "Unable to deserialize to object: " + class_name # type: ignore + raise DeserializationError(msg) from err + additional_properties = self._build_additional_properties(attributes, data) + return self._instantiate_model(response, d_attrs, additional_properties) + + def _build_additional_properties(self, attribute_map, data): + if not self.additional_properties_detection: + return None + if "additional_properties" in attribute_map and attribute_map.get("additional_properties", {}).get("key") != "": + # Check empty string. If it's not empty, someone has a real "additionalProperties" + return None + if isinstance(data, ET.Element): + data = {el.tag: el.text for el in data} + + known_keys = { + _decode_attribute_map_key(_FLATTEN.split(desc["key"])[0]) + for desc in attribute_map.values() + if desc["key"] != "" + } + present_keys = set(data.keys()) + missing_keys = present_keys - known_keys + return {key: data[key] for key in missing_keys} + + def _classify_target(self, target, data): + """Check to see whether the deserialization target object can + be classified into a subclass. + Once classification has been determined, initialize object. + + :param str target: The target object type to deserialize to. + :param str/dict data: The response data to deserialize. + :return: The classified target object and its class name. + :rtype: tuple + """ + if target is None: + return None, None + + if isinstance(target, str): + try: + target = self.dependencies[target] + except KeyError: + return target, target + + try: + target = target._classify(data, self.dependencies) # type: ignore # pylint: disable=protected-access + except AttributeError: + pass # Target is not a Model, no classify + return target, target.__class__.__name__ # type: ignore + + def failsafe_deserialize(self, target_obj, data, content_type=None): + """Ignores any errors encountered in deserialization, + and falls back to not deserializing the object. Recommended + for use in error deserialization, as we want to return the + HttpResponseError to users, and not have them deal with + a deserialization error. + + :param str target_obj: The target object type to deserialize to. + :param str/dict data: The response data to deserialize. + :param str content_type: Swagger "produces" if available. + :return: Deserialized object. + :rtype: object + """ + try: + return self(target_obj, data, content_type=content_type) + except: # pylint: disable=bare-except + _LOGGER.debug( + "Ran into a deserialization error. Ignoring since this is failsafe deserialization", exc_info=True + ) + return None + + @staticmethod + def _unpack_content(raw_data, content_type=None): + """Extract the correct structure for deserialization. + + If raw_data is a PipelineResponse, try to extract the result of RawDeserializer. + if we can't, raise. Your Pipeline should have a RawDeserializer. + + If not a pipeline response and raw_data is bytes or string, use content-type + to decode it. If no content-type, try JSON. + + If raw_data is something else, bypass all logic and return it directly. + + :param obj raw_data: Data to be processed. + :param str content_type: How to parse if raw_data is a string/bytes. + :raises JSONDecodeError: If JSON is requested and parsing is impossible. + :raises UnicodeDecodeError: If bytes is not UTF8 + :rtype: object + :return: Unpacked content. + """ + # Assume this is enough to detect a Pipeline Response without importing it + context = getattr(raw_data, "context", {}) + if context: + if RawDeserializer.CONTEXT_NAME in context: + return context[RawDeserializer.CONTEXT_NAME] + raise ValueError("This pipeline didn't have the RawDeserializer policy; can't deserialize") + + # Assume this is enough to recognize universal_http.ClientResponse without importing it + if hasattr(raw_data, "body"): + return RawDeserializer.deserialize_from_http_generics(raw_data.text(), raw_data.headers) + + # Assume this enough to recognize requests.Response without importing it. + if hasattr(raw_data, "_content_consumed"): + return RawDeserializer.deserialize_from_http_generics(raw_data.text, raw_data.headers) + + if isinstance(raw_data, (str, bytes)) or hasattr(raw_data, "read"): + return RawDeserializer.deserialize_from_text(raw_data, content_type) # type: ignore + return raw_data + + def _instantiate_model(self, response, attrs, additional_properties=None): + """Instantiate a response model passing in deserialized args. + + :param Response response: The response model class. + :param dict attrs: The deserialized response attributes. + :param dict additional_properties: Additional properties to be set. + :rtype: Response + :return: The instantiated response model. + """ + if callable(response): + subtype = getattr(response, "_subtype_map", {}) + try: + readonly = [ + k + for k, v in response._validation.items() # pylint: disable=protected-access # type: ignore + if v.get("readonly") + ] + const = [ + k + for k, v in response._validation.items() # pylint: disable=protected-access # type: ignore + if v.get("constant") + ] + kwargs = {k: v for k, v in attrs.items() if k not in subtype and k not in readonly + const} + response_obj = response(**kwargs) + for attr in readonly: + setattr(response_obj, attr, attrs.get(attr)) + if additional_properties: + response_obj.additional_properties = additional_properties # type: ignore + return response_obj + except TypeError as err: + msg = "Unable to deserialize {} into model {}. ".format(kwargs, response) # type: ignore + raise DeserializationError(msg + str(err)) from err + else: + try: + for attr, value in attrs.items(): + setattr(response, attr, value) + return response + except Exception as exp: + msg = "Unable to populate response model. " + msg += "Type: {}, Error: {}".format(type(response), exp) + raise DeserializationError(msg) from exp + + def deserialize_data(self, data, data_type): # pylint: disable=too-many-return-statements + """Process data for deserialization according to data type. + + :param str data: The response string to be deserialized. + :param str data_type: The type to deserialize to. + :raises DeserializationError: if deserialization fails. + :return: Deserialized object. + :rtype: object + """ + if data is None: + return data + + try: + if not data_type: + return data + if data_type in self.basic_types.values(): + return self.deserialize_basic(data, data_type) + if data_type in self.deserialize_type: + if isinstance(data, self.deserialize_expected_types.get(data_type, tuple())): + return data + + is_a_text_parsing_type = lambda x: x not in [ # pylint: disable=unnecessary-lambda-assignment + "object", + "[]", + r"{}", + ] + if isinstance(data, ET.Element) and is_a_text_parsing_type(data_type) and not data.text: + return None + data_val = self.deserialize_type[data_type](data) + return data_val + + iter_type = data_type[0] + data_type[-1] + if iter_type in self.deserialize_type: + return self.deserialize_type[iter_type](data, data_type[1:-1]) + + obj_type = self.dependencies[data_type] + if issubclass(obj_type, Enum): + if isinstance(data, ET.Element): + data = data.text + return self.deserialize_enum(data, obj_type) + + except (ValueError, TypeError, AttributeError) as err: + msg = "Unable to deserialize response data." + msg += " Data: {}, {}".format(data, data_type) + raise DeserializationError(msg) from err + return self._deserialize(obj_type, data) + + def deserialize_iter(self, attr, iter_type): + """Deserialize an iterable. + + :param list attr: Iterable to be deserialized. + :param str iter_type: The type of object in the iterable. + :return: Deserialized iterable. + :rtype: list + """ + if attr is None: + return None + if isinstance(attr, ET.Element): # If I receive an element here, get the children + attr = list(attr) + if not isinstance(attr, (list, set)): + raise DeserializationError("Cannot deserialize as [{}] an object of type {}".format(iter_type, type(attr))) + return [self.deserialize_data(a, iter_type) for a in attr] + + def deserialize_dict(self, attr, dict_type): + """Deserialize a dictionary. + + :param dict/list attr: Dictionary to be deserialized. Also accepts + a list of key, value pairs. + :param str dict_type: The object type of the items in the dictionary. + :return: Deserialized dictionary. + :rtype: dict + """ + if isinstance(attr, list): + return {x["key"]: self.deserialize_data(x["value"], dict_type) for x in attr} + + if isinstance(attr, ET.Element): + # Transform value into {"Key": "value"} + attr = {el.tag: el.text for el in attr} + return {k: self.deserialize_data(v, dict_type) for k, v in attr.items()} + + def deserialize_object(self, attr, **kwargs): # pylint: disable=too-many-return-statements + """Deserialize a generic object. + This will be handled as a dictionary. + + :param dict attr: Dictionary to be deserialized. + :return: Deserialized object. + :rtype: dict + :raises TypeError: if non-builtin datatype encountered. + """ + if attr is None: + return None + if isinstance(attr, ET.Element): + # Do no recurse on XML, just return the tree as-is + return attr + if isinstance(attr, str): + return self.deserialize_basic(attr, "str") + obj_type = type(attr) + if obj_type in self.basic_types: + return self.deserialize_basic(attr, self.basic_types[obj_type]) + if obj_type is _long_type: + return self.deserialize_long(attr) + + if obj_type == dict: + deserialized = {} + for key, value in attr.items(): + try: + deserialized[key] = self.deserialize_object(value, **kwargs) + except ValueError: + deserialized[key] = None + return deserialized + + if obj_type == list: + deserialized = [] + for obj in attr: + try: + deserialized.append(self.deserialize_object(obj, **kwargs)) + except ValueError: + pass + return deserialized + + error = "Cannot deserialize generic object with type: " + raise TypeError(error + str(obj_type)) + + def deserialize_basic(self, attr, data_type): # pylint: disable=too-many-return-statements + """Deserialize basic builtin data type from string. + Will attempt to convert to str, int, float and bool. + This function will also accept '1', '0', 'true' and 'false' as + valid bool values. + + :param str attr: response string to be deserialized. + :param str data_type: deserialization data type. + :return: Deserialized basic type. + :rtype: str, int, float or bool + :raises TypeError: if string format is not valid. + """ + # If we're here, data is supposed to be a basic type. + # If it's still an XML node, take the text + if isinstance(attr, ET.Element): + attr = attr.text + if not attr: + if data_type == "str": + # None or '', node is empty string. + return "" + # None or '', node with a strong type is None. + # Don't try to model "empty bool" or "empty int" + return None + + if data_type == "bool": + if attr in [True, False, 1, 0]: + return bool(attr) + if isinstance(attr, str): + if attr.lower() in ["true", "1"]: + return True + if attr.lower() in ["false", "0"]: + return False + raise TypeError("Invalid boolean value: {}".format(attr)) + + if data_type == "str": + return self.deserialize_unicode(attr) + return eval(data_type)(attr) # nosec # pylint: disable=eval-used + + @staticmethod + def deserialize_unicode(data): + """Preserve unicode objects in Python 2, otherwise return data + as a string. + + :param str data: response string to be deserialized. + :return: Deserialized string. + :rtype: str or unicode + """ + # We might be here because we have an enum modeled as string, + # and we try to deserialize a partial dict with enum inside + if isinstance(data, Enum): + return data + + # Consider this is real string + try: + if isinstance(data, unicode): # type: ignore + return data + except NameError: + return str(data) + return str(data) + + @staticmethod + def deserialize_enum(data, enum_obj): + """Deserialize string into enum object. + + If the string is not a valid enum value it will be returned as-is + and a warning will be logged. + + :param str data: Response string to be deserialized. If this value is + None or invalid it will be returned as-is. + :param Enum enum_obj: Enum object to deserialize to. + :return: Deserialized enum object. + :rtype: Enum + """ + if isinstance(data, enum_obj) or data is None: + return data + if isinstance(data, Enum): + data = data.value + if isinstance(data, int): + # Workaround. We might consider remove it in the future. + try: + return list(enum_obj.__members__.values())[data] + except IndexError as exc: + error = "{!r} is not a valid index for enum {!r}" + raise DeserializationError(error.format(data, enum_obj)) from exc + try: + return enum_obj(str(data)) + except ValueError: + for enum_value in enum_obj: + if enum_value.value.lower() == str(data).lower(): + return enum_value + # We don't fail anymore for unknown value, we deserialize as a string + _LOGGER.warning("Deserializer is not able to find %s as valid enum in %s", data, enum_obj) + return Deserializer.deserialize_unicode(data) + + @staticmethod + def deserialize_bytearray(attr): + """Deserialize string into bytearray. + + :param str attr: response string to be deserialized. + :return: Deserialized bytearray + :rtype: bytearray + :raises TypeError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + return bytearray(b64decode(attr)) # type: ignore + + @staticmethod + def deserialize_base64(attr): + """Deserialize base64 encoded string into string. + + :param str attr: response string to be deserialized. + :return: Deserialized base64 string + :rtype: bytearray + :raises TypeError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + padding = "=" * (3 - (len(attr) + 3) % 4) # type: ignore + attr = attr + padding # type: ignore + encoded = attr.replace("-", "+").replace("_", "/") + return b64decode(encoded) + + @staticmethod + def deserialize_decimal(attr): + """Deserialize string into Decimal object. + + :param str attr: response string to be deserialized. + :return: Deserialized decimal + :raises DeserializationError: if string format invalid. + :rtype: decimal + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + return decimal.Decimal(str(attr)) # type: ignore + except decimal.DecimalException as err: + msg = "Invalid decimal {}".format(attr) + raise DeserializationError(msg) from err + + @staticmethod + def deserialize_long(attr): + """Deserialize string into long (Py2) or int (Py3). + + :param str attr: response string to be deserialized. + :return: Deserialized int + :rtype: long or int + :raises ValueError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + return _long_type(attr) # type: ignore + + @staticmethod + def deserialize_duration(attr): + """Deserialize ISO-8601 formatted string into TimeDelta object. + + :param str attr: response string to be deserialized. + :return: Deserialized duration + :rtype: TimeDelta + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + duration = isodate.parse_duration(attr) + except (ValueError, OverflowError, AttributeError) as err: + msg = "Cannot deserialize duration object." + raise DeserializationError(msg) from err + return duration + + @staticmethod + def deserialize_date(attr): + """Deserialize ISO-8601 formatted string into Date object. + + :param str attr: response string to be deserialized. + :return: Deserialized date + :rtype: Date + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + if re.search(r"[^\W\d_]", attr, re.I + re.U): # type: ignore + raise DeserializationError("Date must have only digits and -. Received: %s" % attr) + # This must NOT use defaultmonth/defaultday. Using None ensure this raises an exception. + return isodate.parse_date(attr, defaultmonth=0, defaultday=0) + + @staticmethod + def deserialize_time(attr): + """Deserialize ISO-8601 formatted string into time object. + + :param str attr: response string to be deserialized. + :return: Deserialized time + :rtype: datetime.time + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + if re.search(r"[^\W\d_]", attr, re.I + re.U): # type: ignore + raise DeserializationError("Date must have only digits and -. Received: %s" % attr) + return isodate.parse_time(attr) + + @staticmethod + def deserialize_rfc(attr): + """Deserialize RFC-1123 formatted string into Datetime object. + + :param str attr: response string to be deserialized. + :return: Deserialized RFC datetime + :rtype: Datetime + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + parsed_date = email.utils.parsedate_tz(attr) # type: ignore + date_obj = datetime.datetime( + *parsed_date[:6], tzinfo=datetime.timezone(datetime.timedelta(minutes=(parsed_date[9] or 0) / 60)) + ) + if not date_obj.tzinfo: + date_obj = date_obj.astimezone(tz=TZ_UTC) + except ValueError as err: + msg = "Cannot deserialize to rfc datetime object." + raise DeserializationError(msg) from err + return date_obj + + @staticmethod + def deserialize_iso(attr): + """Deserialize ISO-8601 formatted string into Datetime object. + + :param str attr: response string to be deserialized. + :return: Deserialized ISO datetime + :rtype: Datetime + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + attr = attr.upper() # type: ignore + match = Deserializer.valid_date.match(attr) + if not match: + raise ValueError("Invalid datetime string: " + attr) + + check_decimal = attr.split(".") + if len(check_decimal) > 1: + decimal_str = "" + for digit in check_decimal[1]: + if digit.isdigit(): + decimal_str += digit + else: + break + if len(decimal_str) > 6: + attr = attr.replace(decimal_str, decimal_str[0:6]) + + date_obj = isodate.parse_datetime(attr) + test_utc = date_obj.utctimetuple() + if test_utc.tm_year > 9999 or test_utc.tm_year < 1: + raise OverflowError("Hit max or min date") + except (ValueError, OverflowError, AttributeError) as err: + msg = "Cannot deserialize datetime object." + raise DeserializationError(msg) from err + return date_obj + + @staticmethod + def deserialize_unix(attr): + """Serialize Datetime object into IntTime format. + This is represented as seconds. + + :param int attr: Object to be serialized. + :return: Deserialized datetime + :rtype: Datetime + :raises DeserializationError: if format invalid + """ + if isinstance(attr, ET.Element): + attr = int(attr.text) # type: ignore + try: + attr = int(attr) + date_obj = datetime.datetime.fromtimestamp(attr, TZ_UTC) + except ValueError as err: + msg = "Cannot deserialize to unix datetime object." + raise DeserializationError(msg) from err + return date_obj diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyFileVersionTolerant/bodyfileversiontolerant/aio/_client.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyFileVersionTolerant/bodyfileversiontolerant/aio/_client.py index bd0bcb844f9..1724a497a29 100644 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyFileVersionTolerant/bodyfileversiontolerant/aio/_client.py +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyFileVersionTolerant/bodyfileversiontolerant/aio/_client.py @@ -14,7 +14,7 @@ from azure.core.pipeline import policies from azure.core.rest import AsyncHttpResponse, HttpRequest -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import AutoRestSwaggerBATFileServiceConfiguration from .operations import FilesOperations diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyFileVersionTolerant/bodyfileversiontolerant/aio/operations/_operations.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyFileVersionTolerant/bodyfileversiontolerant/aio/operations/_operations.py index 5cab0963096..1bf47b89dfc 100644 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyFileVersionTolerant/bodyfileversiontolerant/aio/operations/_operations.py +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyFileVersionTolerant/bodyfileversiontolerant/aio/operations/_operations.py @@ -23,7 +23,7 @@ from azure.core.rest import AsyncHttpResponse, HttpRequest from azure.core.tracing.decorator_async import distributed_trace_async -from ..._serialization import Deserializer, Serializer +from ..._utils.serialization import Deserializer, Serializer from ...operations._operations import ( build_files_get_empty_file_request, build_files_get_file_large_request, diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyFileVersionTolerant/bodyfileversiontolerant/operations/_operations.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyFileVersionTolerant/bodyfileversiontolerant/operations/_operations.py index b7f2459445d..4cc0bafa5ac 100644 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyFileVersionTolerant/bodyfileversiontolerant/operations/_operations.py +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyFileVersionTolerant/bodyfileversiontolerant/operations/_operations.py @@ -25,7 +25,7 @@ from azure.core.utils import case_insensitive_dict from .._configuration import AutoRestSwaggerBATFileServiceConfiguration -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyFormDataVersionTolerant/bodyformdataversiontolerant/_client.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyFormDataVersionTolerant/bodyformdataversiontolerant/_client.py index 9f560ff6bb6..0b50613091f 100644 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyFormDataVersionTolerant/bodyformdataversiontolerant/_client.py +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyFormDataVersionTolerant/bodyformdataversiontolerant/_client.py @@ -15,7 +15,7 @@ from azure.core.rest import HttpRequest, HttpResponse from ._configuration import AutoRestSwaggerBATFormDataServiceConfiguration -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer from .operations import FormdataOperations diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyFormDataVersionTolerant/bodyformdataversiontolerant/_utils/__init__.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyFormDataVersionTolerant/bodyformdataversiontolerant/_utils/__init__.py new file mode 100644 index 00000000000..0af9b28f660 --- /dev/null +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyFormDataVersionTolerant/bodyformdataversiontolerant/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyFormDataVersionTolerant/bodyformdataversiontolerant/_utils/serialization.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyFormDataVersionTolerant/bodyformdataversiontolerant/_utils/serialization.py new file mode 100644 index 00000000000..f5187701d7b --- /dev/null +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyFormDataVersionTolerant/bodyformdataversiontolerant/_utils/serialization.py @@ -0,0 +1,2032 @@ +# pylint: disable=line-too-long,useless-suppression,too-many-lines +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +# pyright: reportUnnecessaryTypeIgnoreComment=false + +from base64 import b64decode, b64encode +import calendar +import datetime +import decimal +import email +from enum import Enum +import json +import logging +import re +import sys +import codecs +from typing import ( + Dict, + Any, + cast, + Optional, + Union, + AnyStr, + IO, + Mapping, + Callable, + MutableMapping, + List, +) + +try: + from urllib import quote # type: ignore +except ImportError: + from urllib.parse import quote +import xml.etree.ElementTree as ET + +import isodate # type: ignore +from typing_extensions import Self + +from azure.core.exceptions import DeserializationError, SerializationError +from azure.core.serialization import NULL as CoreNull + +_BOM = codecs.BOM_UTF8.decode(encoding="utf-8") + +JSON = MutableMapping[str, Any] + + +class RawDeserializer: + + # Accept "text" because we're open minded people... + JSON_REGEXP = re.compile(r"^(application|text)/([a-z+.]+\+)?json$") + + # Name used in context + CONTEXT_NAME = "deserialized_data" + + @classmethod + def deserialize_from_text(cls, data: Optional[Union[AnyStr, IO]], content_type: Optional[str] = None) -> Any: + """Decode data according to content-type. + + Accept a stream of data as well, but will be load at once in memory for now. + + If no content-type, will return the string version (not bytes, not stream) + + :param data: Input, could be bytes or stream (will be decoded with UTF8) or text + :type data: str or bytes or IO + :param str content_type: The content type. + :return: The deserialized data. + :rtype: object + """ + if hasattr(data, "read"): + # Assume a stream + data = cast(IO, data).read() + + if isinstance(data, bytes): + data_as_str = data.decode(encoding="utf-8-sig") + else: + # Explain to mypy the correct type. + data_as_str = cast(str, data) + + # Remove Byte Order Mark if present in string + data_as_str = data_as_str.lstrip(_BOM) + + if content_type is None: + return data + + if cls.JSON_REGEXP.match(content_type): + try: + return json.loads(data_as_str) + except ValueError as err: + raise DeserializationError("JSON is invalid: {}".format(err), err) from err + elif "xml" in (content_type or []): + try: + + try: + if isinstance(data, unicode): # type: ignore + # If I'm Python 2.7 and unicode XML will scream if I try a "fromstring" on unicode string + data_as_str = data_as_str.encode(encoding="utf-8") # type: ignore + except NameError: + pass + + return ET.fromstring(data_as_str) # nosec + except ET.ParseError as err: + # It might be because the server has an issue, and returned JSON with + # content-type XML.... + # So let's try a JSON load, and if it's still broken + # let's flow the initial exception + def _json_attemp(data): + try: + return True, json.loads(data) + except ValueError: + return False, None # Don't care about this one + + success, json_result = _json_attemp(data) + if success: + return json_result + # If i'm here, it's not JSON, it's not XML, let's scream + # and raise the last context in this block (the XML exception) + # The function hack is because Py2.7 messes up with exception + # context otherwise. + _LOGGER.critical("Wasn't XML not JSON, failing") + raise DeserializationError("XML is invalid") from err + elif content_type.startswith("text/"): + return data_as_str + raise DeserializationError("Cannot deserialize content-type: {}".format(content_type)) + + @classmethod + def deserialize_from_http_generics(cls, body_bytes: Optional[Union[AnyStr, IO]], headers: Mapping) -> Any: + """Deserialize from HTTP response. + + Use bytes and headers to NOT use any requests/aiohttp or whatever + specific implementation. + Headers will tested for "content-type" + + :param bytes body_bytes: The body of the response. + :param dict headers: The headers of the response. + :returns: The deserialized data. + :rtype: object + """ + # Try to use content-type from headers if available + content_type = None + if "content-type" in headers: + content_type = headers["content-type"].split(";")[0].strip().lower() + # Ouch, this server did not declare what it sent... + # Let's guess it's JSON... + # Also, since Autorest was considering that an empty body was a valid JSON, + # need that test as well.... + else: + content_type = "application/json" + + if body_bytes: + return cls.deserialize_from_text(body_bytes, content_type) + return None + + +_LOGGER = logging.getLogger(__name__) + +try: + _long_type = long # type: ignore +except NameError: + _long_type = int + +TZ_UTC = datetime.timezone.utc + +_FLATTEN = re.compile(r"(? None: + self.additional_properties: Optional[Dict[str, Any]] = {} + for k in kwargs: # pylint: disable=consider-using-dict-items + if k not in self._attribute_map: + _LOGGER.warning("%s is not a known attribute of class %s and will be ignored", k, self.__class__) + elif k in self._validation and self._validation[k].get("readonly", False): + _LOGGER.warning("Readonly attribute %s will be ignored in class %s", k, self.__class__) + else: + setattr(self, k, kwargs[k]) + + def __eq__(self, other: Any) -> bool: + """Compare objects by comparing all attributes. + + :param object other: The object to compare + :returns: True if objects are equal + :rtype: bool + """ + if isinstance(other, self.__class__): + return self.__dict__ == other.__dict__ + return False + + def __ne__(self, other: Any) -> bool: + """Compare objects by comparing all attributes. + + :param object other: The object to compare + :returns: True if objects are not equal + :rtype: bool + """ + return not self.__eq__(other) + + def __str__(self) -> str: + return str(self.__dict__) + + @classmethod + def enable_additional_properties_sending(cls) -> None: + cls._attribute_map["additional_properties"] = {"key": "", "type": "{object}"} + + @classmethod + def is_xml_model(cls) -> bool: + try: + cls._xml_map # type: ignore + except AttributeError: + return False + return True + + @classmethod + def _create_xml_node(cls): + """Create XML node. + + :returns: The XML node + :rtype: xml.etree.ElementTree.Element + """ + try: + xml_map = cls._xml_map # type: ignore + except AttributeError: + xml_map = {} + + return _create_xml_node(xml_map.get("name", cls.__name__), xml_map.get("prefix", None), xml_map.get("ns", None)) + + def serialize(self, keep_readonly: bool = False, **kwargs: Any) -> JSON: + """Return the JSON that would be sent to server from this model. + + This is an alias to `as_dict(full_restapi_key_transformer, keep_readonly=False)`. + + If you want XML serialization, you can pass the kwargs is_xml=True. + + :param bool keep_readonly: If you want to serialize the readonly attributes + :returns: A dict JSON compatible object + :rtype: dict + """ + serializer = Serializer(self._infer_class_models()) + return serializer._serialize( # type: ignore # pylint: disable=protected-access + self, keep_readonly=keep_readonly, **kwargs + ) + + def as_dict( + self, + keep_readonly: bool = True, + key_transformer: Callable[[str, Dict[str, Any], Any], Any] = attribute_transformer, + **kwargs: Any + ) -> JSON: + """Return a dict that can be serialized using json.dump. + + Advanced usage might optionally use a callback as parameter: + + .. code::python + + def my_key_transformer(key, attr_desc, value): + return key + + Key is the attribute name used in Python. Attr_desc + is a dict of metadata. Currently contains 'type' with the + msrest type and 'key' with the RestAPI encoded key. + Value is the current value in this object. + + The string returned will be used to serialize the key. + If the return type is a list, this is considered hierarchical + result dict. + + See the three examples in this file: + + - attribute_transformer + - full_restapi_key_transformer + - last_restapi_key_transformer + + If you want XML serialization, you can pass the kwargs is_xml=True. + + :param bool keep_readonly: If you want to serialize the readonly attributes + :param function key_transformer: A key transformer function. + :returns: A dict JSON compatible object + :rtype: dict + """ + serializer = Serializer(self._infer_class_models()) + return serializer._serialize( # type: ignore # pylint: disable=protected-access + self, key_transformer=key_transformer, keep_readonly=keep_readonly, **kwargs + ) + + @classmethod + def _infer_class_models(cls): + try: + str_models = cls.__module__.rsplit(".", 1)[0] + models = sys.modules[str_models] + client_models = {k: v for k, v in models.__dict__.items() if isinstance(v, type)} + if cls.__name__ not in client_models: + raise ValueError("Not Autorest generated code") + except Exception: # pylint: disable=broad-exception-caught + # Assume it's not Autorest generated (tests?). Add ourselves as dependencies. + client_models = {cls.__name__: cls} + return client_models + + @classmethod + def deserialize(cls, data: Any, content_type: Optional[str] = None) -> Self: + """Parse a str using the RestAPI syntax and return a model. + + :param str data: A str using RestAPI structure. JSON by default. + :param str content_type: JSON by default, set application/xml if XML. + :returns: An instance of this model + :raises DeserializationError: if something went wrong + :rtype: Self + """ + deserializer = Deserializer(cls._infer_class_models()) + return deserializer(cls.__name__, data, content_type=content_type) # type: ignore + + @classmethod + def from_dict( + cls, + data: Any, + key_extractors: Optional[Callable[[str, Dict[str, Any], Any], Any]] = None, + content_type: Optional[str] = None, + ) -> Self: + """Parse a dict using given key extractor return a model. + + By default consider key + extractors (rest_key_case_insensitive_extractor, attribute_key_case_insensitive_extractor + and last_rest_key_case_insensitive_extractor) + + :param dict data: A dict using RestAPI structure + :param function key_extractors: A key extractor function. + :param str content_type: JSON by default, set application/xml if XML. + :returns: An instance of this model + :raises DeserializationError: if something went wrong + :rtype: Self + """ + deserializer = Deserializer(cls._infer_class_models()) + deserializer.key_extractors = ( # type: ignore + [ # type: ignore + attribute_key_case_insensitive_extractor, + rest_key_case_insensitive_extractor, + last_rest_key_case_insensitive_extractor, + ] + if key_extractors is None + else key_extractors + ) + return deserializer(cls.__name__, data, content_type=content_type) # type: ignore + + @classmethod + def _flatten_subtype(cls, key, objects): + if "_subtype_map" not in cls.__dict__: + return {} + result = dict(cls._subtype_map[key]) + for valuetype in cls._subtype_map[key].values(): + result.update(objects[valuetype]._flatten_subtype(key, objects)) # pylint: disable=protected-access + return result + + @classmethod + def _classify(cls, response, objects): + """Check the class _subtype_map for any child classes. + We want to ignore any inherited _subtype_maps. + + :param dict response: The initial data + :param dict objects: The class objects + :returns: The class to be used + :rtype: class + """ + for subtype_key in cls.__dict__.get("_subtype_map", {}).keys(): + subtype_value = None + + if not isinstance(response, ET.Element): + rest_api_response_key = cls._get_rest_key_parts(subtype_key)[-1] + subtype_value = response.get(rest_api_response_key, None) or response.get(subtype_key, None) + else: + subtype_value = xml_key_extractor(subtype_key, cls._attribute_map[subtype_key], response) + if subtype_value: + # Try to match base class. Can be class name only + # (bug to fix in Autorest to support x-ms-discriminator-name) + if cls.__name__ == subtype_value: + return cls + flatten_mapping_type = cls._flatten_subtype(subtype_key, objects) + try: + return objects[flatten_mapping_type[subtype_value]] # type: ignore + except KeyError: + _LOGGER.warning( + "Subtype value %s has no mapping, use base class %s.", + subtype_value, + cls.__name__, + ) + break + else: + _LOGGER.warning("Discriminator %s is absent or null, use base class %s.", subtype_key, cls.__name__) + break + return cls + + @classmethod + def _get_rest_key_parts(cls, attr_key): + """Get the RestAPI key of this attr, split it and decode part + :param str attr_key: Attribute key must be in attribute_map. + :returns: A list of RestAPI part + :rtype: list + """ + rest_split_key = _FLATTEN.split(cls._attribute_map[attr_key]["key"]) + return [_decode_attribute_map_key(key_part) for key_part in rest_split_key] + + +def _decode_attribute_map_key(key): + """This decode a key in an _attribute_map to the actual key we want to look at + inside the received data. + + :param str key: A key string from the generated code + :returns: The decoded key + :rtype: str + """ + return key.replace("\\.", ".") + + +class Serializer: # pylint: disable=too-many-public-methods + """Request object model serializer.""" + + basic_types = {str: "str", int: "int", bool: "bool", float: "float"} + + _xml_basic_types_serializers = {"bool": lambda x: str(x).lower()} + days = {0: "Mon", 1: "Tue", 2: "Wed", 3: "Thu", 4: "Fri", 5: "Sat", 6: "Sun"} + months = { + 1: "Jan", + 2: "Feb", + 3: "Mar", + 4: "Apr", + 5: "May", + 6: "Jun", + 7: "Jul", + 8: "Aug", + 9: "Sep", + 10: "Oct", + 11: "Nov", + 12: "Dec", + } + validation = { + "min_length": lambda x, y: len(x) < y, + "max_length": lambda x, y: len(x) > y, + "minimum": lambda x, y: x < y, + "maximum": lambda x, y: x > y, + "minimum_ex": lambda x, y: x <= y, + "maximum_ex": lambda x, y: x >= y, + "min_items": lambda x, y: len(x) < y, + "max_items": lambda x, y: len(x) > y, + "pattern": lambda x, y: not re.match(y, x, re.UNICODE), + "unique": lambda x, y: len(x) != len(set(x)), + "multiple": lambda x, y: x % y != 0, + } + + def __init__(self, classes: Optional[Mapping[str, type]] = None) -> None: + self.serialize_type = { + "iso-8601": Serializer.serialize_iso, + "rfc-1123": Serializer.serialize_rfc, + "unix-time": Serializer.serialize_unix, + "duration": Serializer.serialize_duration, + "date": Serializer.serialize_date, + "time": Serializer.serialize_time, + "decimal": Serializer.serialize_decimal, + "long": Serializer.serialize_long, + "bytearray": Serializer.serialize_bytearray, + "base64": Serializer.serialize_base64, + "object": self.serialize_object, + "[]": self.serialize_iter, + "{}": self.serialize_dict, + } + self.dependencies: Dict[str, type] = dict(classes) if classes else {} + self.key_transformer = full_restapi_key_transformer + self.client_side_validation = True + + def _serialize( # pylint: disable=too-many-nested-blocks, too-many-branches, too-many-statements, too-many-locals + self, target_obj, data_type=None, **kwargs + ): + """Serialize data into a string according to type. + + :param object target_obj: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str, dict + :raises SerializationError: if serialization fails. + :returns: The serialized data. + """ + key_transformer = kwargs.get("key_transformer", self.key_transformer) + keep_readonly = kwargs.get("keep_readonly", False) + if target_obj is None: + return None + + attr_name = None + class_name = target_obj.__class__.__name__ + + if data_type: + return self.serialize_data(target_obj, data_type, **kwargs) + + if not hasattr(target_obj, "_attribute_map"): + data_type = type(target_obj).__name__ + if data_type in self.basic_types.values(): + return self.serialize_data(target_obj, data_type, **kwargs) + + # Force "is_xml" kwargs if we detect a XML model + try: + is_xml_model_serialization = kwargs["is_xml"] + except KeyError: + is_xml_model_serialization = kwargs.setdefault("is_xml", target_obj.is_xml_model()) + + serialized = {} + if is_xml_model_serialization: + serialized = target_obj._create_xml_node() # pylint: disable=protected-access + try: + attributes = target_obj._attribute_map # pylint: disable=protected-access + for attr, attr_desc in attributes.items(): + attr_name = attr + if not keep_readonly and target_obj._validation.get( # pylint: disable=protected-access + attr_name, {} + ).get("readonly", False): + continue + + if attr_name == "additional_properties" and attr_desc["key"] == "": + if target_obj.additional_properties is not None: + serialized.update(target_obj.additional_properties) + continue + try: + + orig_attr = getattr(target_obj, attr) + if is_xml_model_serialization: + pass # Don't provide "transformer" for XML for now. Keep "orig_attr" + else: # JSON + keys, orig_attr = key_transformer(attr, attr_desc.copy(), orig_attr) + keys = keys if isinstance(keys, list) else [keys] + + kwargs["serialization_ctxt"] = attr_desc + new_attr = self.serialize_data(orig_attr, attr_desc["type"], **kwargs) + + if is_xml_model_serialization: + xml_desc = attr_desc.get("xml", {}) + xml_name = xml_desc.get("name", attr_desc["key"]) + xml_prefix = xml_desc.get("prefix", None) + xml_ns = xml_desc.get("ns", None) + if xml_desc.get("attr", False): + if xml_ns: + ET.register_namespace(xml_prefix, xml_ns) + xml_name = "{{{}}}{}".format(xml_ns, xml_name) + serialized.set(xml_name, new_attr) # type: ignore + continue + if xml_desc.get("text", False): + serialized.text = new_attr # type: ignore + continue + if isinstance(new_attr, list): + serialized.extend(new_attr) # type: ignore + elif isinstance(new_attr, ET.Element): + # If the down XML has no XML/Name, + # we MUST replace the tag with the local tag. But keeping the namespaces. + if "name" not in getattr(orig_attr, "_xml_map", {}): + splitted_tag = new_attr.tag.split("}") + if len(splitted_tag) == 2: # Namespace + new_attr.tag = "}".join([splitted_tag[0], xml_name]) + else: + new_attr.tag = xml_name + serialized.append(new_attr) # type: ignore + else: # That's a basic type + # Integrate namespace if necessary + local_node = _create_xml_node(xml_name, xml_prefix, xml_ns) + local_node.text = str(new_attr) + serialized.append(local_node) # type: ignore + else: # JSON + for k in reversed(keys): # type: ignore + new_attr = {k: new_attr} + + _new_attr = new_attr + _serialized = serialized + for k in keys: # type: ignore + if k not in _serialized: + _serialized.update(_new_attr) # type: ignore + _new_attr = _new_attr[k] # type: ignore + _serialized = _serialized[k] + except ValueError as err: + if isinstance(err, SerializationError): + raise + + except (AttributeError, KeyError, TypeError) as err: + msg = "Attribute {} in object {} cannot be serialized.\n{}".format(attr_name, class_name, str(target_obj)) + raise SerializationError(msg) from err + return serialized + + def body(self, data, data_type, **kwargs): + """Serialize data intended for a request body. + + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: dict + :raises SerializationError: if serialization fails. + :raises ValueError: if data is None + :returns: The serialized request body + """ + + # Just in case this is a dict + internal_data_type_str = data_type.strip("[]{}") + internal_data_type = self.dependencies.get(internal_data_type_str, None) + try: + is_xml_model_serialization = kwargs["is_xml"] + except KeyError: + if internal_data_type and issubclass(internal_data_type, Model): + is_xml_model_serialization = kwargs.setdefault("is_xml", internal_data_type.is_xml_model()) + else: + is_xml_model_serialization = False + if internal_data_type and not isinstance(internal_data_type, Enum): + try: + deserializer = Deserializer(self.dependencies) + # Since it's on serialization, it's almost sure that format is not JSON REST + # We're not able to deal with additional properties for now. + deserializer.additional_properties_detection = False + if is_xml_model_serialization: + deserializer.key_extractors = [ # type: ignore + attribute_key_case_insensitive_extractor, + ] + else: + deserializer.key_extractors = [ + rest_key_case_insensitive_extractor, + attribute_key_case_insensitive_extractor, + last_rest_key_case_insensitive_extractor, + ] + data = deserializer._deserialize(data_type, data) # pylint: disable=protected-access + except DeserializationError as err: + raise SerializationError("Unable to build a model: " + str(err)) from err + + return self._serialize(data, data_type, **kwargs) + + def url(self, name, data, data_type, **kwargs): + """Serialize data intended for a URL path. + + :param str name: The name of the URL path parameter. + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str + :returns: The serialized URL path + :raises TypeError: if serialization fails. + :raises ValueError: if data is None + """ + try: + output = self.serialize_data(data, data_type, **kwargs) + if data_type == "bool": + output = json.dumps(output) + + if kwargs.get("skip_quote") is True: + output = str(output) + output = output.replace("{", quote("{")).replace("}", quote("}")) + else: + output = quote(str(output), safe="") + except SerializationError as exc: + raise TypeError("{} must be type {}.".format(name, data_type)) from exc + return output + + def query(self, name, data, data_type, **kwargs): + """Serialize data intended for a URL query. + + :param str name: The name of the query parameter. + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str, list + :raises TypeError: if serialization fails. + :raises ValueError: if data is None + :returns: The serialized query parameter + """ + try: + # Treat the list aside, since we don't want to encode the div separator + if data_type.startswith("["): + internal_data_type = data_type[1:-1] + do_quote = not kwargs.get("skip_quote", False) + return self.serialize_iter(data, internal_data_type, do_quote=do_quote, **kwargs) + + # Not a list, regular serialization + output = self.serialize_data(data, data_type, **kwargs) + if data_type == "bool": + output = json.dumps(output) + if kwargs.get("skip_quote") is True: + output = str(output) + else: + output = quote(str(output), safe="") + except SerializationError as exc: + raise TypeError("{} must be type {}.".format(name, data_type)) from exc + return str(output) + + def header(self, name, data, data_type, **kwargs): + """Serialize data intended for a request header. + + :param str name: The name of the header. + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str + :raises TypeError: if serialization fails. + :raises ValueError: if data is None + :returns: The serialized header + """ + try: + if data_type in ["[str]"]: + data = ["" if d is None else d for d in data] + + output = self.serialize_data(data, data_type, **kwargs) + if data_type == "bool": + output = json.dumps(output) + except SerializationError as exc: + raise TypeError("{} must be type {}.".format(name, data_type)) from exc + return str(output) + + def serialize_data(self, data, data_type, **kwargs): + """Serialize generic data according to supplied data type. + + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :raises AttributeError: if required data is None. + :raises ValueError: if data is None + :raises SerializationError: if serialization fails. + :returns: The serialized data. + :rtype: str, int, float, bool, dict, list + """ + if data is None: + raise ValueError("No value for given attribute") + + try: + if data is CoreNull: + return None + if data_type in self.basic_types.values(): + return self.serialize_basic(data, data_type, **kwargs) + + if data_type in self.serialize_type: + return self.serialize_type[data_type](data, **kwargs) + + # If dependencies is empty, try with current data class + # It has to be a subclass of Enum anyway + enum_type = self.dependencies.get(data_type, data.__class__) + if issubclass(enum_type, Enum): + return Serializer.serialize_enum(data, enum_obj=enum_type) + + iter_type = data_type[0] + data_type[-1] + if iter_type in self.serialize_type: + return self.serialize_type[iter_type](data, data_type[1:-1], **kwargs) + + except (ValueError, TypeError) as err: + msg = "Unable to serialize value: {!r} as type: {!r}." + raise SerializationError(msg.format(data, data_type)) from err + return self._serialize(data, **kwargs) + + @classmethod + def _get_custom_serializers(cls, data_type, **kwargs): # pylint: disable=inconsistent-return-statements + custom_serializer = kwargs.get("basic_types_serializers", {}).get(data_type) + if custom_serializer: + return custom_serializer + if kwargs.get("is_xml", False): + return cls._xml_basic_types_serializers.get(data_type) + + @classmethod + def serialize_basic(cls, data, data_type, **kwargs): + """Serialize basic builting data type. + Serializes objects to str, int, float or bool. + + Possible kwargs: + - basic_types_serializers dict[str, callable] : If set, use the callable as serializer + - is_xml bool : If set, use xml_basic_types_serializers + + :param obj data: Object to be serialized. + :param str data_type: Type of object in the iterable. + :rtype: str, int, float, bool + :return: serialized object + """ + custom_serializer = cls._get_custom_serializers(data_type, **kwargs) + if custom_serializer: + return custom_serializer(data) + if data_type == "str": + return cls.serialize_unicode(data) + return eval(data_type)(data) # nosec # pylint: disable=eval-used + + @classmethod + def serialize_unicode(cls, data): + """Special handling for serializing unicode strings in Py2. + Encode to UTF-8 if unicode, otherwise handle as a str. + + :param str data: Object to be serialized. + :rtype: str + :return: serialized object + """ + try: # If I received an enum, return its value + return data.value + except AttributeError: + pass + + try: + if isinstance(data, unicode): # type: ignore + # Don't change it, JSON and XML ElementTree are totally able + # to serialize correctly u'' strings + return data + except NameError: + return str(data) + return str(data) + + def serialize_iter(self, data, iter_type, div=None, **kwargs): + """Serialize iterable. + + Supported kwargs: + - serialization_ctxt dict : The current entry of _attribute_map, or same format. + serialization_ctxt['type'] should be same as data_type. + - is_xml bool : If set, serialize as XML + + :param list data: Object to be serialized. + :param str iter_type: Type of object in the iterable. + :param str div: If set, this str will be used to combine the elements + in the iterable into a combined string. Default is 'None'. + Defaults to False. + :rtype: list, str + :return: serialized iterable + """ + if isinstance(data, str): + raise SerializationError("Refuse str type as a valid iter type.") + + serialization_ctxt = kwargs.get("serialization_ctxt", {}) + is_xml = kwargs.get("is_xml", False) + + serialized = [] + for d in data: + try: + serialized.append(self.serialize_data(d, iter_type, **kwargs)) + except ValueError as err: + if isinstance(err, SerializationError): + raise + serialized.append(None) + + if kwargs.get("do_quote", False): + serialized = ["" if s is None else quote(str(s), safe="") for s in serialized] + + if div: + serialized = ["" if s is None else str(s) for s in serialized] + serialized = div.join(serialized) + + if "xml" in serialization_ctxt or is_xml: + # XML serialization is more complicated + xml_desc = serialization_ctxt.get("xml", {}) + xml_name = xml_desc.get("name") + if not xml_name: + xml_name = serialization_ctxt["key"] + + # Create a wrap node if necessary (use the fact that Element and list have "append") + is_wrapped = xml_desc.get("wrapped", False) + node_name = xml_desc.get("itemsName", xml_name) + if is_wrapped: + final_result = _create_xml_node(xml_name, xml_desc.get("prefix", None), xml_desc.get("ns", None)) + else: + final_result = [] + # All list elements to "local_node" + for el in serialized: + if isinstance(el, ET.Element): + el_node = el + else: + el_node = _create_xml_node(node_name, xml_desc.get("prefix", None), xml_desc.get("ns", None)) + if el is not None: # Otherwise it writes "None" :-p + el_node.text = str(el) + final_result.append(el_node) + return final_result + return serialized + + def serialize_dict(self, attr, dict_type, **kwargs): + """Serialize a dictionary of objects. + + :param dict attr: Object to be serialized. + :param str dict_type: Type of object in the dictionary. + :rtype: dict + :return: serialized dictionary + """ + serialization_ctxt = kwargs.get("serialization_ctxt", {}) + serialized = {} + for key, value in attr.items(): + try: + serialized[self.serialize_unicode(key)] = self.serialize_data(value, dict_type, **kwargs) + except ValueError as err: + if isinstance(err, SerializationError): + raise + serialized[self.serialize_unicode(key)] = None + + if "xml" in serialization_ctxt: + # XML serialization is more complicated + xml_desc = serialization_ctxt["xml"] + xml_name = xml_desc["name"] + + final_result = _create_xml_node(xml_name, xml_desc.get("prefix", None), xml_desc.get("ns", None)) + for key, value in serialized.items(): + ET.SubElement(final_result, key).text = value + return final_result + + return serialized + + def serialize_object(self, attr, **kwargs): # pylint: disable=too-many-return-statements + """Serialize a generic object. + This will be handled as a dictionary. If object passed in is not + a basic type (str, int, float, dict, list) it will simply be + cast to str. + + :param dict attr: Object to be serialized. + :rtype: dict or str + :return: serialized object + """ + if attr is None: + return None + if isinstance(attr, ET.Element): + return attr + obj_type = type(attr) + if obj_type in self.basic_types: + return self.serialize_basic(attr, self.basic_types[obj_type], **kwargs) + if obj_type is _long_type: + return self.serialize_long(attr) + if obj_type is str: + return self.serialize_unicode(attr) + if obj_type is datetime.datetime: + return self.serialize_iso(attr) + if obj_type is datetime.date: + return self.serialize_date(attr) + if obj_type is datetime.time: + return self.serialize_time(attr) + if obj_type is datetime.timedelta: + return self.serialize_duration(attr) + if obj_type is decimal.Decimal: + return self.serialize_decimal(attr) + + # If it's a model or I know this dependency, serialize as a Model + if obj_type in self.dependencies.values() or isinstance(attr, Model): + return self._serialize(attr) + + if obj_type == dict: + serialized = {} + for key, value in attr.items(): + try: + serialized[self.serialize_unicode(key)] = self.serialize_object(value, **kwargs) + except ValueError: + serialized[self.serialize_unicode(key)] = None + return serialized + + if obj_type == list: + serialized = [] + for obj in attr: + try: + serialized.append(self.serialize_object(obj, **kwargs)) + except ValueError: + pass + return serialized + return str(attr) + + @staticmethod + def serialize_enum(attr, enum_obj=None): + try: + result = attr.value + except AttributeError: + result = attr + try: + enum_obj(result) # type: ignore + return result + except ValueError as exc: + for enum_value in enum_obj: # type: ignore + if enum_value.value.lower() == str(attr).lower(): + return enum_value.value + error = "{!r} is not valid value for enum {!r}" + raise SerializationError(error.format(attr, enum_obj)) from exc + + @staticmethod + def serialize_bytearray(attr, **kwargs): # pylint: disable=unused-argument + """Serialize bytearray into base-64 string. + + :param str attr: Object to be serialized. + :rtype: str + :return: serialized base64 + """ + return b64encode(attr).decode() + + @staticmethod + def serialize_base64(attr, **kwargs): # pylint: disable=unused-argument + """Serialize str into base-64 string. + + :param str attr: Object to be serialized. + :rtype: str + :return: serialized base64 + """ + encoded = b64encode(attr).decode("ascii") + return encoded.strip("=").replace("+", "-").replace("/", "_") + + @staticmethod + def serialize_decimal(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Decimal object to float. + + :param decimal attr: Object to be serialized. + :rtype: float + :return: serialized decimal + """ + return float(attr) + + @staticmethod + def serialize_long(attr, **kwargs): # pylint: disable=unused-argument + """Serialize long (Py2) or int (Py3). + + :param int attr: Object to be serialized. + :rtype: int/long + :return: serialized long + """ + return _long_type(attr) + + @staticmethod + def serialize_date(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Date object into ISO-8601 formatted string. + + :param Date attr: Object to be serialized. + :rtype: str + :return: serialized date + """ + if isinstance(attr, str): + attr = isodate.parse_date(attr) + t = "{:04}-{:02}-{:02}".format(attr.year, attr.month, attr.day) + return t + + @staticmethod + def serialize_time(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Time object into ISO-8601 formatted string. + + :param datetime.time attr: Object to be serialized. + :rtype: str + :return: serialized time + """ + if isinstance(attr, str): + attr = isodate.parse_time(attr) + t = "{:02}:{:02}:{:02}".format(attr.hour, attr.minute, attr.second) + if attr.microsecond: + t += ".{:02}".format(attr.microsecond) + return t + + @staticmethod + def serialize_duration(attr, **kwargs): # pylint: disable=unused-argument + """Serialize TimeDelta object into ISO-8601 formatted string. + + :param TimeDelta attr: Object to be serialized. + :rtype: str + :return: serialized duration + """ + if isinstance(attr, str): + attr = isodate.parse_duration(attr) + return isodate.duration_isoformat(attr) + + @staticmethod + def serialize_rfc(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Datetime object into RFC-1123 formatted string. + + :param Datetime attr: Object to be serialized. + :rtype: str + :raises TypeError: if format invalid. + :return: serialized rfc + """ + try: + if not attr.tzinfo: + _LOGGER.warning("Datetime with no tzinfo will be considered UTC.") + utc = attr.utctimetuple() + except AttributeError as exc: + raise TypeError("RFC1123 object must be valid Datetime object.") from exc + + return "{}, {:02} {} {:04} {:02}:{:02}:{:02} GMT".format( + Serializer.days[utc.tm_wday], + utc.tm_mday, + Serializer.months[utc.tm_mon], + utc.tm_year, + utc.tm_hour, + utc.tm_min, + utc.tm_sec, + ) + + @staticmethod + def serialize_iso(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Datetime object into ISO-8601 formatted string. + + :param Datetime attr: Object to be serialized. + :rtype: str + :raises SerializationError: if format invalid. + :return: serialized iso + """ + if isinstance(attr, str): + attr = isodate.parse_datetime(attr) + try: + if not attr.tzinfo: + _LOGGER.warning("Datetime with no tzinfo will be considered UTC.") + utc = attr.utctimetuple() + if utc.tm_year > 9999 or utc.tm_year < 1: + raise OverflowError("Hit max or min date") + + microseconds = str(attr.microsecond).rjust(6, "0").rstrip("0").ljust(3, "0") + if microseconds: + microseconds = "." + microseconds + date = "{:04}-{:02}-{:02}T{:02}:{:02}:{:02}".format( + utc.tm_year, utc.tm_mon, utc.tm_mday, utc.tm_hour, utc.tm_min, utc.tm_sec + ) + return date + microseconds + "Z" + except (ValueError, OverflowError) as err: + msg = "Unable to serialize datetime object." + raise SerializationError(msg) from err + except AttributeError as err: + msg = "ISO-8601 object must be valid Datetime object." + raise TypeError(msg) from err + + @staticmethod + def serialize_unix(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Datetime object into IntTime format. + This is represented as seconds. + + :param Datetime attr: Object to be serialized. + :rtype: int + :raises SerializationError: if format invalid + :return: serialied unix + """ + if isinstance(attr, int): + return attr + try: + if not attr.tzinfo: + _LOGGER.warning("Datetime with no tzinfo will be considered UTC.") + return int(calendar.timegm(attr.utctimetuple())) + except AttributeError as exc: + raise TypeError("Unix time object must be valid Datetime object.") from exc + + +def rest_key_extractor(attr, attr_desc, data): # pylint: disable=unused-argument + key = attr_desc["key"] + working_data = data + + while "." in key: + # Need the cast, as for some reasons "split" is typed as list[str | Any] + dict_keys = cast(List[str], _FLATTEN.split(key)) + if len(dict_keys) == 1: + key = _decode_attribute_map_key(dict_keys[0]) + break + working_key = _decode_attribute_map_key(dict_keys[0]) + working_data = working_data.get(working_key, data) + if working_data is None: + # If at any point while following flatten JSON path see None, it means + # that all properties under are None as well + return None + key = ".".join(dict_keys[1:]) + + return working_data.get(key) + + +def rest_key_case_insensitive_extractor( # pylint: disable=unused-argument, inconsistent-return-statements + attr, attr_desc, data +): + key = attr_desc["key"] + working_data = data + + while "." in key: + dict_keys = _FLATTEN.split(key) + if len(dict_keys) == 1: + key = _decode_attribute_map_key(dict_keys[0]) + break + working_key = _decode_attribute_map_key(dict_keys[0]) + working_data = attribute_key_case_insensitive_extractor(working_key, None, working_data) + if working_data is None: + # If at any point while following flatten JSON path see None, it means + # that all properties under are None as well + return None + key = ".".join(dict_keys[1:]) + + if working_data: + return attribute_key_case_insensitive_extractor(key, None, working_data) + + +def last_rest_key_extractor(attr, attr_desc, data): # pylint: disable=unused-argument + """Extract the attribute in "data" based on the last part of the JSON path key. + + :param str attr: The attribute to extract + :param dict attr_desc: The attribute description + :param dict data: The data to extract from + :rtype: object + :returns: The extracted attribute + """ + key = attr_desc["key"] + dict_keys = _FLATTEN.split(key) + return attribute_key_extractor(dict_keys[-1], None, data) + + +def last_rest_key_case_insensitive_extractor(attr, attr_desc, data): # pylint: disable=unused-argument + """Extract the attribute in "data" based on the last part of the JSON path key. + + This is the case insensitive version of "last_rest_key_extractor" + :param str attr: The attribute to extract + :param dict attr_desc: The attribute description + :param dict data: The data to extract from + :rtype: object + :returns: The extracted attribute + """ + key = attr_desc["key"] + dict_keys = _FLATTEN.split(key) + return attribute_key_case_insensitive_extractor(dict_keys[-1], None, data) + + +def attribute_key_extractor(attr, _, data): + return data.get(attr) + + +def attribute_key_case_insensitive_extractor(attr, _, data): + found_key = None + lower_attr = attr.lower() + for key in data: + if lower_attr == key.lower(): + found_key = key + break + + return data.get(found_key) + + +def _extract_name_from_internal_type(internal_type): + """Given an internal type XML description, extract correct XML name with namespace. + + :param dict internal_type: An model type + :rtype: tuple + :returns: A tuple XML name + namespace dict + """ + internal_type_xml_map = getattr(internal_type, "_xml_map", {}) + xml_name = internal_type_xml_map.get("name", internal_type.__name__) + xml_ns = internal_type_xml_map.get("ns", None) + if xml_ns: + xml_name = "{{{}}}{}".format(xml_ns, xml_name) + return xml_name + + +def xml_key_extractor(attr, attr_desc, data): # pylint: disable=unused-argument,too-many-return-statements + if isinstance(data, dict): + return None + + # Test if this model is XML ready first + if not isinstance(data, ET.Element): + return None + + xml_desc = attr_desc.get("xml", {}) + xml_name = xml_desc.get("name", attr_desc["key"]) + + # Look for a children + is_iter_type = attr_desc["type"].startswith("[") + is_wrapped = xml_desc.get("wrapped", False) + internal_type = attr_desc.get("internalType", None) + internal_type_xml_map = getattr(internal_type, "_xml_map", {}) + + # Integrate namespace if necessary + xml_ns = xml_desc.get("ns", internal_type_xml_map.get("ns", None)) + if xml_ns: + xml_name = "{{{}}}{}".format(xml_ns, xml_name) + + # If it's an attribute, that's simple + if xml_desc.get("attr", False): + return data.get(xml_name) + + # If it's x-ms-text, that's simple too + if xml_desc.get("text", False): + return data.text + + # Scenario where I take the local name: + # - Wrapped node + # - Internal type is an enum (considered basic types) + # - Internal type has no XML/Name node + if is_wrapped or (internal_type and (issubclass(internal_type, Enum) or "name" not in internal_type_xml_map)): + children = data.findall(xml_name) + # If internal type has a local name and it's not a list, I use that name + elif not is_iter_type and internal_type and "name" in internal_type_xml_map: + xml_name = _extract_name_from_internal_type(internal_type) + children = data.findall(xml_name) + # That's an array + else: + if internal_type: # Complex type, ignore itemsName and use the complex type name + items_name = _extract_name_from_internal_type(internal_type) + else: + items_name = xml_desc.get("itemsName", xml_name) + children = data.findall(items_name) + + if len(children) == 0: + if is_iter_type: + if is_wrapped: + return None # is_wrapped no node, we want None + return [] # not wrapped, assume empty list + return None # Assume it's not there, maybe an optional node. + + # If is_iter_type and not wrapped, return all found children + if is_iter_type: + if not is_wrapped: + return children + # Iter and wrapped, should have found one node only (the wrap one) + if len(children) != 1: + raise DeserializationError( + "Tried to deserialize an array not wrapped, and found several nodes '{}'. Maybe you should declare this array as wrapped?".format( + xml_name + ) + ) + return list(children[0]) # Might be empty list and that's ok. + + # Here it's not a itertype, we should have found one element only or empty + if len(children) > 1: + raise DeserializationError("Find several XML '{}' where it was not expected".format(xml_name)) + return children[0] + + +class Deserializer: + """Response object model deserializer. + + :param dict classes: Class type dictionary for deserializing complex types. + :ivar list key_extractors: Ordered list of extractors to be used by this deserializer. + """ + + basic_types = {str: "str", int: "int", bool: "bool", float: "float"} + + valid_date = re.compile(r"\d{4}[-]\d{2}[-]\d{2}T\d{2}:\d{2}:\d{2}\.?\d*Z?[-+]?[\d{2}]?:?[\d{2}]?") + + def __init__(self, classes: Optional[Mapping[str, type]] = None) -> None: + self.deserialize_type = { + "iso-8601": Deserializer.deserialize_iso, + "rfc-1123": Deserializer.deserialize_rfc, + "unix-time": Deserializer.deserialize_unix, + "duration": Deserializer.deserialize_duration, + "date": Deserializer.deserialize_date, + "time": Deserializer.deserialize_time, + "decimal": Deserializer.deserialize_decimal, + "long": Deserializer.deserialize_long, + "bytearray": Deserializer.deserialize_bytearray, + "base64": Deserializer.deserialize_base64, + "object": self.deserialize_object, + "[]": self.deserialize_iter, + "{}": self.deserialize_dict, + } + self.deserialize_expected_types = { + "duration": (isodate.Duration, datetime.timedelta), + "iso-8601": (datetime.datetime), + } + self.dependencies: Dict[str, type] = dict(classes) if classes else {} + self.key_extractors = [rest_key_extractor, xml_key_extractor] + # Additional properties only works if the "rest_key_extractor" is used to + # extract the keys. Making it to work whatever the key extractor is too much + # complicated, with no real scenario for now. + # So adding a flag to disable additional properties detection. This flag should be + # used if your expect the deserialization to NOT come from a JSON REST syntax. + # Otherwise, result are unexpected + self.additional_properties_detection = True + + def __call__(self, target_obj, response_data, content_type=None): + """Call the deserializer to process a REST response. + + :param str target_obj: Target data type to deserialize to. + :param requests.Response response_data: REST response object. + :param str content_type: Swagger "produces" if available. + :raises DeserializationError: if deserialization fails. + :return: Deserialized object. + :rtype: object + """ + data = self._unpack_content(response_data, content_type) + return self._deserialize(target_obj, data) + + def _deserialize(self, target_obj, data): # pylint: disable=inconsistent-return-statements + """Call the deserializer on a model. + + Data needs to be already deserialized as JSON or XML ElementTree + + :param str target_obj: Target data type to deserialize to. + :param object data: Object to deserialize. + :raises DeserializationError: if deserialization fails. + :return: Deserialized object. + :rtype: object + """ + # This is already a model, go recursive just in case + if hasattr(data, "_attribute_map"): + constants = [name for name, config in getattr(data, "_validation", {}).items() if config.get("constant")] + try: + for attr, mapconfig in data._attribute_map.items(): # pylint: disable=protected-access + if attr in constants: + continue + value = getattr(data, attr) + if value is None: + continue + local_type = mapconfig["type"] + internal_data_type = local_type.strip("[]{}") + if internal_data_type not in self.dependencies or isinstance(internal_data_type, Enum): + continue + setattr(data, attr, self._deserialize(local_type, value)) + return data + except AttributeError: + return + + response, class_name = self._classify_target(target_obj, data) + + if isinstance(response, str): + return self.deserialize_data(data, response) + if isinstance(response, type) and issubclass(response, Enum): + return self.deserialize_enum(data, response) + + if data is None or data is CoreNull: + return data + try: + attributes = response._attribute_map # type: ignore # pylint: disable=protected-access + d_attrs = {} + for attr, attr_desc in attributes.items(): + # Check empty string. If it's not empty, someone has a real "additionalProperties"... + if attr == "additional_properties" and attr_desc["key"] == "": + continue + raw_value = None + # Enhance attr_desc with some dynamic data + attr_desc = attr_desc.copy() # Do a copy, do not change the real one + internal_data_type = attr_desc["type"].strip("[]{}") + if internal_data_type in self.dependencies: + attr_desc["internalType"] = self.dependencies[internal_data_type] + + for key_extractor in self.key_extractors: + found_value = key_extractor(attr, attr_desc, data) + if found_value is not None: + if raw_value is not None and raw_value != found_value: + msg = ( + "Ignoring extracted value '%s' from %s for key '%s'" + " (duplicate extraction, follow extractors order)" + ) + _LOGGER.warning(msg, found_value, key_extractor, attr) + continue + raw_value = found_value + + value = self.deserialize_data(raw_value, attr_desc["type"]) + d_attrs[attr] = value + except (AttributeError, TypeError, KeyError) as err: + msg = "Unable to deserialize to object: " + class_name # type: ignore + raise DeserializationError(msg) from err + additional_properties = self._build_additional_properties(attributes, data) + return self._instantiate_model(response, d_attrs, additional_properties) + + def _build_additional_properties(self, attribute_map, data): + if not self.additional_properties_detection: + return None + if "additional_properties" in attribute_map and attribute_map.get("additional_properties", {}).get("key") != "": + # Check empty string. If it's not empty, someone has a real "additionalProperties" + return None + if isinstance(data, ET.Element): + data = {el.tag: el.text for el in data} + + known_keys = { + _decode_attribute_map_key(_FLATTEN.split(desc["key"])[0]) + for desc in attribute_map.values() + if desc["key"] != "" + } + present_keys = set(data.keys()) + missing_keys = present_keys - known_keys + return {key: data[key] for key in missing_keys} + + def _classify_target(self, target, data): + """Check to see whether the deserialization target object can + be classified into a subclass. + Once classification has been determined, initialize object. + + :param str target: The target object type to deserialize to. + :param str/dict data: The response data to deserialize. + :return: The classified target object and its class name. + :rtype: tuple + """ + if target is None: + return None, None + + if isinstance(target, str): + try: + target = self.dependencies[target] + except KeyError: + return target, target + + try: + target = target._classify(data, self.dependencies) # type: ignore # pylint: disable=protected-access + except AttributeError: + pass # Target is not a Model, no classify + return target, target.__class__.__name__ # type: ignore + + def failsafe_deserialize(self, target_obj, data, content_type=None): + """Ignores any errors encountered in deserialization, + and falls back to not deserializing the object. Recommended + for use in error deserialization, as we want to return the + HttpResponseError to users, and not have them deal with + a deserialization error. + + :param str target_obj: The target object type to deserialize to. + :param str/dict data: The response data to deserialize. + :param str content_type: Swagger "produces" if available. + :return: Deserialized object. + :rtype: object + """ + try: + return self(target_obj, data, content_type=content_type) + except: # pylint: disable=bare-except + _LOGGER.debug( + "Ran into a deserialization error. Ignoring since this is failsafe deserialization", exc_info=True + ) + return None + + @staticmethod + def _unpack_content(raw_data, content_type=None): + """Extract the correct structure for deserialization. + + If raw_data is a PipelineResponse, try to extract the result of RawDeserializer. + if we can't, raise. Your Pipeline should have a RawDeserializer. + + If not a pipeline response and raw_data is bytes or string, use content-type + to decode it. If no content-type, try JSON. + + If raw_data is something else, bypass all logic and return it directly. + + :param obj raw_data: Data to be processed. + :param str content_type: How to parse if raw_data is a string/bytes. + :raises JSONDecodeError: If JSON is requested and parsing is impossible. + :raises UnicodeDecodeError: If bytes is not UTF8 + :rtype: object + :return: Unpacked content. + """ + # Assume this is enough to detect a Pipeline Response without importing it + context = getattr(raw_data, "context", {}) + if context: + if RawDeserializer.CONTEXT_NAME in context: + return context[RawDeserializer.CONTEXT_NAME] + raise ValueError("This pipeline didn't have the RawDeserializer policy; can't deserialize") + + # Assume this is enough to recognize universal_http.ClientResponse without importing it + if hasattr(raw_data, "body"): + return RawDeserializer.deserialize_from_http_generics(raw_data.text(), raw_data.headers) + + # Assume this enough to recognize requests.Response without importing it. + if hasattr(raw_data, "_content_consumed"): + return RawDeserializer.deserialize_from_http_generics(raw_data.text, raw_data.headers) + + if isinstance(raw_data, (str, bytes)) or hasattr(raw_data, "read"): + return RawDeserializer.deserialize_from_text(raw_data, content_type) # type: ignore + return raw_data + + def _instantiate_model(self, response, attrs, additional_properties=None): + """Instantiate a response model passing in deserialized args. + + :param Response response: The response model class. + :param dict attrs: The deserialized response attributes. + :param dict additional_properties: Additional properties to be set. + :rtype: Response + :return: The instantiated response model. + """ + if callable(response): + subtype = getattr(response, "_subtype_map", {}) + try: + readonly = [ + k + for k, v in response._validation.items() # pylint: disable=protected-access # type: ignore + if v.get("readonly") + ] + const = [ + k + for k, v in response._validation.items() # pylint: disable=protected-access # type: ignore + if v.get("constant") + ] + kwargs = {k: v for k, v in attrs.items() if k not in subtype and k not in readonly + const} + response_obj = response(**kwargs) + for attr in readonly: + setattr(response_obj, attr, attrs.get(attr)) + if additional_properties: + response_obj.additional_properties = additional_properties # type: ignore + return response_obj + except TypeError as err: + msg = "Unable to deserialize {} into model {}. ".format(kwargs, response) # type: ignore + raise DeserializationError(msg + str(err)) from err + else: + try: + for attr, value in attrs.items(): + setattr(response, attr, value) + return response + except Exception as exp: + msg = "Unable to populate response model. " + msg += "Type: {}, Error: {}".format(type(response), exp) + raise DeserializationError(msg) from exp + + def deserialize_data(self, data, data_type): # pylint: disable=too-many-return-statements + """Process data for deserialization according to data type. + + :param str data: The response string to be deserialized. + :param str data_type: The type to deserialize to. + :raises DeserializationError: if deserialization fails. + :return: Deserialized object. + :rtype: object + """ + if data is None: + return data + + try: + if not data_type: + return data + if data_type in self.basic_types.values(): + return self.deserialize_basic(data, data_type) + if data_type in self.deserialize_type: + if isinstance(data, self.deserialize_expected_types.get(data_type, tuple())): + return data + + is_a_text_parsing_type = lambda x: x not in [ # pylint: disable=unnecessary-lambda-assignment + "object", + "[]", + r"{}", + ] + if isinstance(data, ET.Element) and is_a_text_parsing_type(data_type) and not data.text: + return None + data_val = self.deserialize_type[data_type](data) + return data_val + + iter_type = data_type[0] + data_type[-1] + if iter_type in self.deserialize_type: + return self.deserialize_type[iter_type](data, data_type[1:-1]) + + obj_type = self.dependencies[data_type] + if issubclass(obj_type, Enum): + if isinstance(data, ET.Element): + data = data.text + return self.deserialize_enum(data, obj_type) + + except (ValueError, TypeError, AttributeError) as err: + msg = "Unable to deserialize response data." + msg += " Data: {}, {}".format(data, data_type) + raise DeserializationError(msg) from err + return self._deserialize(obj_type, data) + + def deserialize_iter(self, attr, iter_type): + """Deserialize an iterable. + + :param list attr: Iterable to be deserialized. + :param str iter_type: The type of object in the iterable. + :return: Deserialized iterable. + :rtype: list + """ + if attr is None: + return None + if isinstance(attr, ET.Element): # If I receive an element here, get the children + attr = list(attr) + if not isinstance(attr, (list, set)): + raise DeserializationError("Cannot deserialize as [{}] an object of type {}".format(iter_type, type(attr))) + return [self.deserialize_data(a, iter_type) for a in attr] + + def deserialize_dict(self, attr, dict_type): + """Deserialize a dictionary. + + :param dict/list attr: Dictionary to be deserialized. Also accepts + a list of key, value pairs. + :param str dict_type: The object type of the items in the dictionary. + :return: Deserialized dictionary. + :rtype: dict + """ + if isinstance(attr, list): + return {x["key"]: self.deserialize_data(x["value"], dict_type) for x in attr} + + if isinstance(attr, ET.Element): + # Transform value into {"Key": "value"} + attr = {el.tag: el.text for el in attr} + return {k: self.deserialize_data(v, dict_type) for k, v in attr.items()} + + def deserialize_object(self, attr, **kwargs): # pylint: disable=too-many-return-statements + """Deserialize a generic object. + This will be handled as a dictionary. + + :param dict attr: Dictionary to be deserialized. + :return: Deserialized object. + :rtype: dict + :raises TypeError: if non-builtin datatype encountered. + """ + if attr is None: + return None + if isinstance(attr, ET.Element): + # Do no recurse on XML, just return the tree as-is + return attr + if isinstance(attr, str): + return self.deserialize_basic(attr, "str") + obj_type = type(attr) + if obj_type in self.basic_types: + return self.deserialize_basic(attr, self.basic_types[obj_type]) + if obj_type is _long_type: + return self.deserialize_long(attr) + + if obj_type == dict: + deserialized = {} + for key, value in attr.items(): + try: + deserialized[key] = self.deserialize_object(value, **kwargs) + except ValueError: + deserialized[key] = None + return deserialized + + if obj_type == list: + deserialized = [] + for obj in attr: + try: + deserialized.append(self.deserialize_object(obj, **kwargs)) + except ValueError: + pass + return deserialized + + error = "Cannot deserialize generic object with type: " + raise TypeError(error + str(obj_type)) + + def deserialize_basic(self, attr, data_type): # pylint: disable=too-many-return-statements + """Deserialize basic builtin data type from string. + Will attempt to convert to str, int, float and bool. + This function will also accept '1', '0', 'true' and 'false' as + valid bool values. + + :param str attr: response string to be deserialized. + :param str data_type: deserialization data type. + :return: Deserialized basic type. + :rtype: str, int, float or bool + :raises TypeError: if string format is not valid. + """ + # If we're here, data is supposed to be a basic type. + # If it's still an XML node, take the text + if isinstance(attr, ET.Element): + attr = attr.text + if not attr: + if data_type == "str": + # None or '', node is empty string. + return "" + # None or '', node with a strong type is None. + # Don't try to model "empty bool" or "empty int" + return None + + if data_type == "bool": + if attr in [True, False, 1, 0]: + return bool(attr) + if isinstance(attr, str): + if attr.lower() in ["true", "1"]: + return True + if attr.lower() in ["false", "0"]: + return False + raise TypeError("Invalid boolean value: {}".format(attr)) + + if data_type == "str": + return self.deserialize_unicode(attr) + return eval(data_type)(attr) # nosec # pylint: disable=eval-used + + @staticmethod + def deserialize_unicode(data): + """Preserve unicode objects in Python 2, otherwise return data + as a string. + + :param str data: response string to be deserialized. + :return: Deserialized string. + :rtype: str or unicode + """ + # We might be here because we have an enum modeled as string, + # and we try to deserialize a partial dict with enum inside + if isinstance(data, Enum): + return data + + # Consider this is real string + try: + if isinstance(data, unicode): # type: ignore + return data + except NameError: + return str(data) + return str(data) + + @staticmethod + def deserialize_enum(data, enum_obj): + """Deserialize string into enum object. + + If the string is not a valid enum value it will be returned as-is + and a warning will be logged. + + :param str data: Response string to be deserialized. If this value is + None or invalid it will be returned as-is. + :param Enum enum_obj: Enum object to deserialize to. + :return: Deserialized enum object. + :rtype: Enum + """ + if isinstance(data, enum_obj) or data is None: + return data + if isinstance(data, Enum): + data = data.value + if isinstance(data, int): + # Workaround. We might consider remove it in the future. + try: + return list(enum_obj.__members__.values())[data] + except IndexError as exc: + error = "{!r} is not a valid index for enum {!r}" + raise DeserializationError(error.format(data, enum_obj)) from exc + try: + return enum_obj(str(data)) + except ValueError: + for enum_value in enum_obj: + if enum_value.value.lower() == str(data).lower(): + return enum_value + # We don't fail anymore for unknown value, we deserialize as a string + _LOGGER.warning("Deserializer is not able to find %s as valid enum in %s", data, enum_obj) + return Deserializer.deserialize_unicode(data) + + @staticmethod + def deserialize_bytearray(attr): + """Deserialize string into bytearray. + + :param str attr: response string to be deserialized. + :return: Deserialized bytearray + :rtype: bytearray + :raises TypeError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + return bytearray(b64decode(attr)) # type: ignore + + @staticmethod + def deserialize_base64(attr): + """Deserialize base64 encoded string into string. + + :param str attr: response string to be deserialized. + :return: Deserialized base64 string + :rtype: bytearray + :raises TypeError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + padding = "=" * (3 - (len(attr) + 3) % 4) # type: ignore + attr = attr + padding # type: ignore + encoded = attr.replace("-", "+").replace("_", "/") + return b64decode(encoded) + + @staticmethod + def deserialize_decimal(attr): + """Deserialize string into Decimal object. + + :param str attr: response string to be deserialized. + :return: Deserialized decimal + :raises DeserializationError: if string format invalid. + :rtype: decimal + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + return decimal.Decimal(str(attr)) # type: ignore + except decimal.DecimalException as err: + msg = "Invalid decimal {}".format(attr) + raise DeserializationError(msg) from err + + @staticmethod + def deserialize_long(attr): + """Deserialize string into long (Py2) or int (Py3). + + :param str attr: response string to be deserialized. + :return: Deserialized int + :rtype: long or int + :raises ValueError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + return _long_type(attr) # type: ignore + + @staticmethod + def deserialize_duration(attr): + """Deserialize ISO-8601 formatted string into TimeDelta object. + + :param str attr: response string to be deserialized. + :return: Deserialized duration + :rtype: TimeDelta + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + duration = isodate.parse_duration(attr) + except (ValueError, OverflowError, AttributeError) as err: + msg = "Cannot deserialize duration object." + raise DeserializationError(msg) from err + return duration + + @staticmethod + def deserialize_date(attr): + """Deserialize ISO-8601 formatted string into Date object. + + :param str attr: response string to be deserialized. + :return: Deserialized date + :rtype: Date + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + if re.search(r"[^\W\d_]", attr, re.I + re.U): # type: ignore + raise DeserializationError("Date must have only digits and -. Received: %s" % attr) + # This must NOT use defaultmonth/defaultday. Using None ensure this raises an exception. + return isodate.parse_date(attr, defaultmonth=0, defaultday=0) + + @staticmethod + def deserialize_time(attr): + """Deserialize ISO-8601 formatted string into time object. + + :param str attr: response string to be deserialized. + :return: Deserialized time + :rtype: datetime.time + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + if re.search(r"[^\W\d_]", attr, re.I + re.U): # type: ignore + raise DeserializationError("Date must have only digits and -. Received: %s" % attr) + return isodate.parse_time(attr) + + @staticmethod + def deserialize_rfc(attr): + """Deserialize RFC-1123 formatted string into Datetime object. + + :param str attr: response string to be deserialized. + :return: Deserialized RFC datetime + :rtype: Datetime + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + parsed_date = email.utils.parsedate_tz(attr) # type: ignore + date_obj = datetime.datetime( + *parsed_date[:6], tzinfo=datetime.timezone(datetime.timedelta(minutes=(parsed_date[9] or 0) / 60)) + ) + if not date_obj.tzinfo: + date_obj = date_obj.astimezone(tz=TZ_UTC) + except ValueError as err: + msg = "Cannot deserialize to rfc datetime object." + raise DeserializationError(msg) from err + return date_obj + + @staticmethod + def deserialize_iso(attr): + """Deserialize ISO-8601 formatted string into Datetime object. + + :param str attr: response string to be deserialized. + :return: Deserialized ISO datetime + :rtype: Datetime + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + attr = attr.upper() # type: ignore + match = Deserializer.valid_date.match(attr) + if not match: + raise ValueError("Invalid datetime string: " + attr) + + check_decimal = attr.split(".") + if len(check_decimal) > 1: + decimal_str = "" + for digit in check_decimal[1]: + if digit.isdigit(): + decimal_str += digit + else: + break + if len(decimal_str) > 6: + attr = attr.replace(decimal_str, decimal_str[0:6]) + + date_obj = isodate.parse_datetime(attr) + test_utc = date_obj.utctimetuple() + if test_utc.tm_year > 9999 or test_utc.tm_year < 1: + raise OverflowError("Hit max or min date") + except (ValueError, OverflowError, AttributeError) as err: + msg = "Cannot deserialize datetime object." + raise DeserializationError(msg) from err + return date_obj + + @staticmethod + def deserialize_unix(attr): + """Serialize Datetime object into IntTime format. + This is represented as seconds. + + :param int attr: Object to be serialized. + :return: Deserialized datetime + :rtype: Datetime + :raises DeserializationError: if format invalid + """ + if isinstance(attr, ET.Element): + attr = int(attr.text) # type: ignore + try: + attr = int(attr) + date_obj = datetime.datetime.fromtimestamp(attr, TZ_UTC) + except ValueError as err: + msg = "Cannot deserialize to unix datetime object." + raise DeserializationError(msg) from err + return date_obj diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyFormDataVersionTolerant/bodyformdataversiontolerant/_vendor.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyFormDataVersionTolerant/bodyformdataversiontolerant/_utils/utils.py similarity index 100% rename from packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyFormDataVersionTolerant/bodyformdataversiontolerant/_vendor.py rename to packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyFormDataVersionTolerant/bodyformdataversiontolerant/_utils/utils.py diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyFormDataVersionTolerant/bodyformdataversiontolerant/aio/_client.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyFormDataVersionTolerant/bodyformdataversiontolerant/aio/_client.py index 8da45e972e8..b9f45665d2d 100644 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyFormDataVersionTolerant/bodyformdataversiontolerant/aio/_client.py +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyFormDataVersionTolerant/bodyformdataversiontolerant/aio/_client.py @@ -14,7 +14,7 @@ from azure.core.pipeline import policies from azure.core.rest import AsyncHttpResponse, HttpRequest -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import AutoRestSwaggerBATFormDataServiceConfiguration from .operations import FormdataOperations diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyFormDataVersionTolerant/bodyformdataversiontolerant/aio/operations/_operations.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyFormDataVersionTolerant/bodyformdataversiontolerant/aio/operations/_operations.py index 51ceb7ff61f..9bf28c70332 100644 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyFormDataVersionTolerant/bodyformdataversiontolerant/aio/operations/_operations.py +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyFormDataVersionTolerant/bodyformdataversiontolerant/aio/operations/_operations.py @@ -24,10 +24,10 @@ from azure.core.tracing.decorator_async import distributed_trace_async from azure.core.utils import case_insensitive_dict -from ..._serialization import Deserializer, Serializer +from ..._utils.serialization import Deserializer, Serializer +from ..._utils.utils import raise_if_not_implemented from ...operations._operations import build_formdata_upload_file_via_body_request from .._configuration import AutoRestSwaggerBATFormDataServiceConfiguration -from .._vendor import raise_if_not_implemented T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, AsyncHttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyFormDataVersionTolerant/bodyformdataversiontolerant/operations/_operations.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyFormDataVersionTolerant/bodyformdataversiontolerant/operations/_operations.py index 2df421acf43..6f4a3274e0b 100644 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyFormDataVersionTolerant/bodyformdataversiontolerant/operations/_operations.py +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyFormDataVersionTolerant/bodyformdataversiontolerant/operations/_operations.py @@ -25,8 +25,8 @@ from azure.core.utils import case_insensitive_dict from .._configuration import AutoRestSwaggerBATFormDataServiceConfiguration -from .._serialization import Deserializer, Serializer -from .._vendor import raise_if_not_implemented +from .._utils.serialization import Deserializer, Serializer +from .._utils.utils import raise_if_not_implemented T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyFormUrlEncodedDataVersionTolerant/bodyformurlencodeddataversiontolerant/_client.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyFormUrlEncodedDataVersionTolerant/bodyformurlencodeddataversiontolerant/_client.py index 2f76049a992..8fd6dfbfa3a 100644 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyFormUrlEncodedDataVersionTolerant/bodyformurlencodeddataversiontolerant/_client.py +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyFormUrlEncodedDataVersionTolerant/bodyformurlencodeddataversiontolerant/_client.py @@ -15,7 +15,7 @@ from azure.core.rest import HttpRequest, HttpResponse from ._configuration import BodyFormsDataURLEncodedConfiguration -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer from .operations import FormdataurlencodedOperations diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyFormUrlEncodedDataVersionTolerant/bodyformurlencodeddataversiontolerant/_utils/__init__.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyFormUrlEncodedDataVersionTolerant/bodyformurlencodeddataversiontolerant/_utils/__init__.py new file mode 100644 index 00000000000..0af9b28f660 --- /dev/null +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyFormUrlEncodedDataVersionTolerant/bodyformurlencodeddataversiontolerant/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyFormUrlEncodedDataVersionTolerant/bodyformurlencodeddataversiontolerant/_utils/serialization.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyFormUrlEncodedDataVersionTolerant/bodyformurlencodeddataversiontolerant/_utils/serialization.py new file mode 100644 index 00000000000..f5187701d7b --- /dev/null +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyFormUrlEncodedDataVersionTolerant/bodyformurlencodeddataversiontolerant/_utils/serialization.py @@ -0,0 +1,2032 @@ +# pylint: disable=line-too-long,useless-suppression,too-many-lines +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +# pyright: reportUnnecessaryTypeIgnoreComment=false + +from base64 import b64decode, b64encode +import calendar +import datetime +import decimal +import email +from enum import Enum +import json +import logging +import re +import sys +import codecs +from typing import ( + Dict, + Any, + cast, + Optional, + Union, + AnyStr, + IO, + Mapping, + Callable, + MutableMapping, + List, +) + +try: + from urllib import quote # type: ignore +except ImportError: + from urllib.parse import quote +import xml.etree.ElementTree as ET + +import isodate # type: ignore +from typing_extensions import Self + +from azure.core.exceptions import DeserializationError, SerializationError +from azure.core.serialization import NULL as CoreNull + +_BOM = codecs.BOM_UTF8.decode(encoding="utf-8") + +JSON = MutableMapping[str, Any] + + +class RawDeserializer: + + # Accept "text" because we're open minded people... + JSON_REGEXP = re.compile(r"^(application|text)/([a-z+.]+\+)?json$") + + # Name used in context + CONTEXT_NAME = "deserialized_data" + + @classmethod + def deserialize_from_text(cls, data: Optional[Union[AnyStr, IO]], content_type: Optional[str] = None) -> Any: + """Decode data according to content-type. + + Accept a stream of data as well, but will be load at once in memory for now. + + If no content-type, will return the string version (not bytes, not stream) + + :param data: Input, could be bytes or stream (will be decoded with UTF8) or text + :type data: str or bytes or IO + :param str content_type: The content type. + :return: The deserialized data. + :rtype: object + """ + if hasattr(data, "read"): + # Assume a stream + data = cast(IO, data).read() + + if isinstance(data, bytes): + data_as_str = data.decode(encoding="utf-8-sig") + else: + # Explain to mypy the correct type. + data_as_str = cast(str, data) + + # Remove Byte Order Mark if present in string + data_as_str = data_as_str.lstrip(_BOM) + + if content_type is None: + return data + + if cls.JSON_REGEXP.match(content_type): + try: + return json.loads(data_as_str) + except ValueError as err: + raise DeserializationError("JSON is invalid: {}".format(err), err) from err + elif "xml" in (content_type or []): + try: + + try: + if isinstance(data, unicode): # type: ignore + # If I'm Python 2.7 and unicode XML will scream if I try a "fromstring" on unicode string + data_as_str = data_as_str.encode(encoding="utf-8") # type: ignore + except NameError: + pass + + return ET.fromstring(data_as_str) # nosec + except ET.ParseError as err: + # It might be because the server has an issue, and returned JSON with + # content-type XML.... + # So let's try a JSON load, and if it's still broken + # let's flow the initial exception + def _json_attemp(data): + try: + return True, json.loads(data) + except ValueError: + return False, None # Don't care about this one + + success, json_result = _json_attemp(data) + if success: + return json_result + # If i'm here, it's not JSON, it's not XML, let's scream + # and raise the last context in this block (the XML exception) + # The function hack is because Py2.7 messes up with exception + # context otherwise. + _LOGGER.critical("Wasn't XML not JSON, failing") + raise DeserializationError("XML is invalid") from err + elif content_type.startswith("text/"): + return data_as_str + raise DeserializationError("Cannot deserialize content-type: {}".format(content_type)) + + @classmethod + def deserialize_from_http_generics(cls, body_bytes: Optional[Union[AnyStr, IO]], headers: Mapping) -> Any: + """Deserialize from HTTP response. + + Use bytes and headers to NOT use any requests/aiohttp or whatever + specific implementation. + Headers will tested for "content-type" + + :param bytes body_bytes: The body of the response. + :param dict headers: The headers of the response. + :returns: The deserialized data. + :rtype: object + """ + # Try to use content-type from headers if available + content_type = None + if "content-type" in headers: + content_type = headers["content-type"].split(";")[0].strip().lower() + # Ouch, this server did not declare what it sent... + # Let's guess it's JSON... + # Also, since Autorest was considering that an empty body was a valid JSON, + # need that test as well.... + else: + content_type = "application/json" + + if body_bytes: + return cls.deserialize_from_text(body_bytes, content_type) + return None + + +_LOGGER = logging.getLogger(__name__) + +try: + _long_type = long # type: ignore +except NameError: + _long_type = int + +TZ_UTC = datetime.timezone.utc + +_FLATTEN = re.compile(r"(? None: + self.additional_properties: Optional[Dict[str, Any]] = {} + for k in kwargs: # pylint: disable=consider-using-dict-items + if k not in self._attribute_map: + _LOGGER.warning("%s is not a known attribute of class %s and will be ignored", k, self.__class__) + elif k in self._validation and self._validation[k].get("readonly", False): + _LOGGER.warning("Readonly attribute %s will be ignored in class %s", k, self.__class__) + else: + setattr(self, k, kwargs[k]) + + def __eq__(self, other: Any) -> bool: + """Compare objects by comparing all attributes. + + :param object other: The object to compare + :returns: True if objects are equal + :rtype: bool + """ + if isinstance(other, self.__class__): + return self.__dict__ == other.__dict__ + return False + + def __ne__(self, other: Any) -> bool: + """Compare objects by comparing all attributes. + + :param object other: The object to compare + :returns: True if objects are not equal + :rtype: bool + """ + return not self.__eq__(other) + + def __str__(self) -> str: + return str(self.__dict__) + + @classmethod + def enable_additional_properties_sending(cls) -> None: + cls._attribute_map["additional_properties"] = {"key": "", "type": "{object}"} + + @classmethod + def is_xml_model(cls) -> bool: + try: + cls._xml_map # type: ignore + except AttributeError: + return False + return True + + @classmethod + def _create_xml_node(cls): + """Create XML node. + + :returns: The XML node + :rtype: xml.etree.ElementTree.Element + """ + try: + xml_map = cls._xml_map # type: ignore + except AttributeError: + xml_map = {} + + return _create_xml_node(xml_map.get("name", cls.__name__), xml_map.get("prefix", None), xml_map.get("ns", None)) + + def serialize(self, keep_readonly: bool = False, **kwargs: Any) -> JSON: + """Return the JSON that would be sent to server from this model. + + This is an alias to `as_dict(full_restapi_key_transformer, keep_readonly=False)`. + + If you want XML serialization, you can pass the kwargs is_xml=True. + + :param bool keep_readonly: If you want to serialize the readonly attributes + :returns: A dict JSON compatible object + :rtype: dict + """ + serializer = Serializer(self._infer_class_models()) + return serializer._serialize( # type: ignore # pylint: disable=protected-access + self, keep_readonly=keep_readonly, **kwargs + ) + + def as_dict( + self, + keep_readonly: bool = True, + key_transformer: Callable[[str, Dict[str, Any], Any], Any] = attribute_transformer, + **kwargs: Any + ) -> JSON: + """Return a dict that can be serialized using json.dump. + + Advanced usage might optionally use a callback as parameter: + + .. code::python + + def my_key_transformer(key, attr_desc, value): + return key + + Key is the attribute name used in Python. Attr_desc + is a dict of metadata. Currently contains 'type' with the + msrest type and 'key' with the RestAPI encoded key. + Value is the current value in this object. + + The string returned will be used to serialize the key. + If the return type is a list, this is considered hierarchical + result dict. + + See the three examples in this file: + + - attribute_transformer + - full_restapi_key_transformer + - last_restapi_key_transformer + + If you want XML serialization, you can pass the kwargs is_xml=True. + + :param bool keep_readonly: If you want to serialize the readonly attributes + :param function key_transformer: A key transformer function. + :returns: A dict JSON compatible object + :rtype: dict + """ + serializer = Serializer(self._infer_class_models()) + return serializer._serialize( # type: ignore # pylint: disable=protected-access + self, key_transformer=key_transformer, keep_readonly=keep_readonly, **kwargs + ) + + @classmethod + def _infer_class_models(cls): + try: + str_models = cls.__module__.rsplit(".", 1)[0] + models = sys.modules[str_models] + client_models = {k: v for k, v in models.__dict__.items() if isinstance(v, type)} + if cls.__name__ not in client_models: + raise ValueError("Not Autorest generated code") + except Exception: # pylint: disable=broad-exception-caught + # Assume it's not Autorest generated (tests?). Add ourselves as dependencies. + client_models = {cls.__name__: cls} + return client_models + + @classmethod + def deserialize(cls, data: Any, content_type: Optional[str] = None) -> Self: + """Parse a str using the RestAPI syntax and return a model. + + :param str data: A str using RestAPI structure. JSON by default. + :param str content_type: JSON by default, set application/xml if XML. + :returns: An instance of this model + :raises DeserializationError: if something went wrong + :rtype: Self + """ + deserializer = Deserializer(cls._infer_class_models()) + return deserializer(cls.__name__, data, content_type=content_type) # type: ignore + + @classmethod + def from_dict( + cls, + data: Any, + key_extractors: Optional[Callable[[str, Dict[str, Any], Any], Any]] = None, + content_type: Optional[str] = None, + ) -> Self: + """Parse a dict using given key extractor return a model. + + By default consider key + extractors (rest_key_case_insensitive_extractor, attribute_key_case_insensitive_extractor + and last_rest_key_case_insensitive_extractor) + + :param dict data: A dict using RestAPI structure + :param function key_extractors: A key extractor function. + :param str content_type: JSON by default, set application/xml if XML. + :returns: An instance of this model + :raises DeserializationError: if something went wrong + :rtype: Self + """ + deserializer = Deserializer(cls._infer_class_models()) + deserializer.key_extractors = ( # type: ignore + [ # type: ignore + attribute_key_case_insensitive_extractor, + rest_key_case_insensitive_extractor, + last_rest_key_case_insensitive_extractor, + ] + if key_extractors is None + else key_extractors + ) + return deserializer(cls.__name__, data, content_type=content_type) # type: ignore + + @classmethod + def _flatten_subtype(cls, key, objects): + if "_subtype_map" not in cls.__dict__: + return {} + result = dict(cls._subtype_map[key]) + for valuetype in cls._subtype_map[key].values(): + result.update(objects[valuetype]._flatten_subtype(key, objects)) # pylint: disable=protected-access + return result + + @classmethod + def _classify(cls, response, objects): + """Check the class _subtype_map for any child classes. + We want to ignore any inherited _subtype_maps. + + :param dict response: The initial data + :param dict objects: The class objects + :returns: The class to be used + :rtype: class + """ + for subtype_key in cls.__dict__.get("_subtype_map", {}).keys(): + subtype_value = None + + if not isinstance(response, ET.Element): + rest_api_response_key = cls._get_rest_key_parts(subtype_key)[-1] + subtype_value = response.get(rest_api_response_key, None) or response.get(subtype_key, None) + else: + subtype_value = xml_key_extractor(subtype_key, cls._attribute_map[subtype_key], response) + if subtype_value: + # Try to match base class. Can be class name only + # (bug to fix in Autorest to support x-ms-discriminator-name) + if cls.__name__ == subtype_value: + return cls + flatten_mapping_type = cls._flatten_subtype(subtype_key, objects) + try: + return objects[flatten_mapping_type[subtype_value]] # type: ignore + except KeyError: + _LOGGER.warning( + "Subtype value %s has no mapping, use base class %s.", + subtype_value, + cls.__name__, + ) + break + else: + _LOGGER.warning("Discriminator %s is absent or null, use base class %s.", subtype_key, cls.__name__) + break + return cls + + @classmethod + def _get_rest_key_parts(cls, attr_key): + """Get the RestAPI key of this attr, split it and decode part + :param str attr_key: Attribute key must be in attribute_map. + :returns: A list of RestAPI part + :rtype: list + """ + rest_split_key = _FLATTEN.split(cls._attribute_map[attr_key]["key"]) + return [_decode_attribute_map_key(key_part) for key_part in rest_split_key] + + +def _decode_attribute_map_key(key): + """This decode a key in an _attribute_map to the actual key we want to look at + inside the received data. + + :param str key: A key string from the generated code + :returns: The decoded key + :rtype: str + """ + return key.replace("\\.", ".") + + +class Serializer: # pylint: disable=too-many-public-methods + """Request object model serializer.""" + + basic_types = {str: "str", int: "int", bool: "bool", float: "float"} + + _xml_basic_types_serializers = {"bool": lambda x: str(x).lower()} + days = {0: "Mon", 1: "Tue", 2: "Wed", 3: "Thu", 4: "Fri", 5: "Sat", 6: "Sun"} + months = { + 1: "Jan", + 2: "Feb", + 3: "Mar", + 4: "Apr", + 5: "May", + 6: "Jun", + 7: "Jul", + 8: "Aug", + 9: "Sep", + 10: "Oct", + 11: "Nov", + 12: "Dec", + } + validation = { + "min_length": lambda x, y: len(x) < y, + "max_length": lambda x, y: len(x) > y, + "minimum": lambda x, y: x < y, + "maximum": lambda x, y: x > y, + "minimum_ex": lambda x, y: x <= y, + "maximum_ex": lambda x, y: x >= y, + "min_items": lambda x, y: len(x) < y, + "max_items": lambda x, y: len(x) > y, + "pattern": lambda x, y: not re.match(y, x, re.UNICODE), + "unique": lambda x, y: len(x) != len(set(x)), + "multiple": lambda x, y: x % y != 0, + } + + def __init__(self, classes: Optional[Mapping[str, type]] = None) -> None: + self.serialize_type = { + "iso-8601": Serializer.serialize_iso, + "rfc-1123": Serializer.serialize_rfc, + "unix-time": Serializer.serialize_unix, + "duration": Serializer.serialize_duration, + "date": Serializer.serialize_date, + "time": Serializer.serialize_time, + "decimal": Serializer.serialize_decimal, + "long": Serializer.serialize_long, + "bytearray": Serializer.serialize_bytearray, + "base64": Serializer.serialize_base64, + "object": self.serialize_object, + "[]": self.serialize_iter, + "{}": self.serialize_dict, + } + self.dependencies: Dict[str, type] = dict(classes) if classes else {} + self.key_transformer = full_restapi_key_transformer + self.client_side_validation = True + + def _serialize( # pylint: disable=too-many-nested-blocks, too-many-branches, too-many-statements, too-many-locals + self, target_obj, data_type=None, **kwargs + ): + """Serialize data into a string according to type. + + :param object target_obj: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str, dict + :raises SerializationError: if serialization fails. + :returns: The serialized data. + """ + key_transformer = kwargs.get("key_transformer", self.key_transformer) + keep_readonly = kwargs.get("keep_readonly", False) + if target_obj is None: + return None + + attr_name = None + class_name = target_obj.__class__.__name__ + + if data_type: + return self.serialize_data(target_obj, data_type, **kwargs) + + if not hasattr(target_obj, "_attribute_map"): + data_type = type(target_obj).__name__ + if data_type in self.basic_types.values(): + return self.serialize_data(target_obj, data_type, **kwargs) + + # Force "is_xml" kwargs if we detect a XML model + try: + is_xml_model_serialization = kwargs["is_xml"] + except KeyError: + is_xml_model_serialization = kwargs.setdefault("is_xml", target_obj.is_xml_model()) + + serialized = {} + if is_xml_model_serialization: + serialized = target_obj._create_xml_node() # pylint: disable=protected-access + try: + attributes = target_obj._attribute_map # pylint: disable=protected-access + for attr, attr_desc in attributes.items(): + attr_name = attr + if not keep_readonly and target_obj._validation.get( # pylint: disable=protected-access + attr_name, {} + ).get("readonly", False): + continue + + if attr_name == "additional_properties" and attr_desc["key"] == "": + if target_obj.additional_properties is not None: + serialized.update(target_obj.additional_properties) + continue + try: + + orig_attr = getattr(target_obj, attr) + if is_xml_model_serialization: + pass # Don't provide "transformer" for XML for now. Keep "orig_attr" + else: # JSON + keys, orig_attr = key_transformer(attr, attr_desc.copy(), orig_attr) + keys = keys if isinstance(keys, list) else [keys] + + kwargs["serialization_ctxt"] = attr_desc + new_attr = self.serialize_data(orig_attr, attr_desc["type"], **kwargs) + + if is_xml_model_serialization: + xml_desc = attr_desc.get("xml", {}) + xml_name = xml_desc.get("name", attr_desc["key"]) + xml_prefix = xml_desc.get("prefix", None) + xml_ns = xml_desc.get("ns", None) + if xml_desc.get("attr", False): + if xml_ns: + ET.register_namespace(xml_prefix, xml_ns) + xml_name = "{{{}}}{}".format(xml_ns, xml_name) + serialized.set(xml_name, new_attr) # type: ignore + continue + if xml_desc.get("text", False): + serialized.text = new_attr # type: ignore + continue + if isinstance(new_attr, list): + serialized.extend(new_attr) # type: ignore + elif isinstance(new_attr, ET.Element): + # If the down XML has no XML/Name, + # we MUST replace the tag with the local tag. But keeping the namespaces. + if "name" not in getattr(orig_attr, "_xml_map", {}): + splitted_tag = new_attr.tag.split("}") + if len(splitted_tag) == 2: # Namespace + new_attr.tag = "}".join([splitted_tag[0], xml_name]) + else: + new_attr.tag = xml_name + serialized.append(new_attr) # type: ignore + else: # That's a basic type + # Integrate namespace if necessary + local_node = _create_xml_node(xml_name, xml_prefix, xml_ns) + local_node.text = str(new_attr) + serialized.append(local_node) # type: ignore + else: # JSON + for k in reversed(keys): # type: ignore + new_attr = {k: new_attr} + + _new_attr = new_attr + _serialized = serialized + for k in keys: # type: ignore + if k not in _serialized: + _serialized.update(_new_attr) # type: ignore + _new_attr = _new_attr[k] # type: ignore + _serialized = _serialized[k] + except ValueError as err: + if isinstance(err, SerializationError): + raise + + except (AttributeError, KeyError, TypeError) as err: + msg = "Attribute {} in object {} cannot be serialized.\n{}".format(attr_name, class_name, str(target_obj)) + raise SerializationError(msg) from err + return serialized + + def body(self, data, data_type, **kwargs): + """Serialize data intended for a request body. + + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: dict + :raises SerializationError: if serialization fails. + :raises ValueError: if data is None + :returns: The serialized request body + """ + + # Just in case this is a dict + internal_data_type_str = data_type.strip("[]{}") + internal_data_type = self.dependencies.get(internal_data_type_str, None) + try: + is_xml_model_serialization = kwargs["is_xml"] + except KeyError: + if internal_data_type and issubclass(internal_data_type, Model): + is_xml_model_serialization = kwargs.setdefault("is_xml", internal_data_type.is_xml_model()) + else: + is_xml_model_serialization = False + if internal_data_type and not isinstance(internal_data_type, Enum): + try: + deserializer = Deserializer(self.dependencies) + # Since it's on serialization, it's almost sure that format is not JSON REST + # We're not able to deal with additional properties for now. + deserializer.additional_properties_detection = False + if is_xml_model_serialization: + deserializer.key_extractors = [ # type: ignore + attribute_key_case_insensitive_extractor, + ] + else: + deserializer.key_extractors = [ + rest_key_case_insensitive_extractor, + attribute_key_case_insensitive_extractor, + last_rest_key_case_insensitive_extractor, + ] + data = deserializer._deserialize(data_type, data) # pylint: disable=protected-access + except DeserializationError as err: + raise SerializationError("Unable to build a model: " + str(err)) from err + + return self._serialize(data, data_type, **kwargs) + + def url(self, name, data, data_type, **kwargs): + """Serialize data intended for a URL path. + + :param str name: The name of the URL path parameter. + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str + :returns: The serialized URL path + :raises TypeError: if serialization fails. + :raises ValueError: if data is None + """ + try: + output = self.serialize_data(data, data_type, **kwargs) + if data_type == "bool": + output = json.dumps(output) + + if kwargs.get("skip_quote") is True: + output = str(output) + output = output.replace("{", quote("{")).replace("}", quote("}")) + else: + output = quote(str(output), safe="") + except SerializationError as exc: + raise TypeError("{} must be type {}.".format(name, data_type)) from exc + return output + + def query(self, name, data, data_type, **kwargs): + """Serialize data intended for a URL query. + + :param str name: The name of the query parameter. + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str, list + :raises TypeError: if serialization fails. + :raises ValueError: if data is None + :returns: The serialized query parameter + """ + try: + # Treat the list aside, since we don't want to encode the div separator + if data_type.startswith("["): + internal_data_type = data_type[1:-1] + do_quote = not kwargs.get("skip_quote", False) + return self.serialize_iter(data, internal_data_type, do_quote=do_quote, **kwargs) + + # Not a list, regular serialization + output = self.serialize_data(data, data_type, **kwargs) + if data_type == "bool": + output = json.dumps(output) + if kwargs.get("skip_quote") is True: + output = str(output) + else: + output = quote(str(output), safe="") + except SerializationError as exc: + raise TypeError("{} must be type {}.".format(name, data_type)) from exc + return str(output) + + def header(self, name, data, data_type, **kwargs): + """Serialize data intended for a request header. + + :param str name: The name of the header. + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str + :raises TypeError: if serialization fails. + :raises ValueError: if data is None + :returns: The serialized header + """ + try: + if data_type in ["[str]"]: + data = ["" if d is None else d for d in data] + + output = self.serialize_data(data, data_type, **kwargs) + if data_type == "bool": + output = json.dumps(output) + except SerializationError as exc: + raise TypeError("{} must be type {}.".format(name, data_type)) from exc + return str(output) + + def serialize_data(self, data, data_type, **kwargs): + """Serialize generic data according to supplied data type. + + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :raises AttributeError: if required data is None. + :raises ValueError: if data is None + :raises SerializationError: if serialization fails. + :returns: The serialized data. + :rtype: str, int, float, bool, dict, list + """ + if data is None: + raise ValueError("No value for given attribute") + + try: + if data is CoreNull: + return None + if data_type in self.basic_types.values(): + return self.serialize_basic(data, data_type, **kwargs) + + if data_type in self.serialize_type: + return self.serialize_type[data_type](data, **kwargs) + + # If dependencies is empty, try with current data class + # It has to be a subclass of Enum anyway + enum_type = self.dependencies.get(data_type, data.__class__) + if issubclass(enum_type, Enum): + return Serializer.serialize_enum(data, enum_obj=enum_type) + + iter_type = data_type[0] + data_type[-1] + if iter_type in self.serialize_type: + return self.serialize_type[iter_type](data, data_type[1:-1], **kwargs) + + except (ValueError, TypeError) as err: + msg = "Unable to serialize value: {!r} as type: {!r}." + raise SerializationError(msg.format(data, data_type)) from err + return self._serialize(data, **kwargs) + + @classmethod + def _get_custom_serializers(cls, data_type, **kwargs): # pylint: disable=inconsistent-return-statements + custom_serializer = kwargs.get("basic_types_serializers", {}).get(data_type) + if custom_serializer: + return custom_serializer + if kwargs.get("is_xml", False): + return cls._xml_basic_types_serializers.get(data_type) + + @classmethod + def serialize_basic(cls, data, data_type, **kwargs): + """Serialize basic builting data type. + Serializes objects to str, int, float or bool. + + Possible kwargs: + - basic_types_serializers dict[str, callable] : If set, use the callable as serializer + - is_xml bool : If set, use xml_basic_types_serializers + + :param obj data: Object to be serialized. + :param str data_type: Type of object in the iterable. + :rtype: str, int, float, bool + :return: serialized object + """ + custom_serializer = cls._get_custom_serializers(data_type, **kwargs) + if custom_serializer: + return custom_serializer(data) + if data_type == "str": + return cls.serialize_unicode(data) + return eval(data_type)(data) # nosec # pylint: disable=eval-used + + @classmethod + def serialize_unicode(cls, data): + """Special handling for serializing unicode strings in Py2. + Encode to UTF-8 if unicode, otherwise handle as a str. + + :param str data: Object to be serialized. + :rtype: str + :return: serialized object + """ + try: # If I received an enum, return its value + return data.value + except AttributeError: + pass + + try: + if isinstance(data, unicode): # type: ignore + # Don't change it, JSON and XML ElementTree are totally able + # to serialize correctly u'' strings + return data + except NameError: + return str(data) + return str(data) + + def serialize_iter(self, data, iter_type, div=None, **kwargs): + """Serialize iterable. + + Supported kwargs: + - serialization_ctxt dict : The current entry of _attribute_map, or same format. + serialization_ctxt['type'] should be same as data_type. + - is_xml bool : If set, serialize as XML + + :param list data: Object to be serialized. + :param str iter_type: Type of object in the iterable. + :param str div: If set, this str will be used to combine the elements + in the iterable into a combined string. Default is 'None'. + Defaults to False. + :rtype: list, str + :return: serialized iterable + """ + if isinstance(data, str): + raise SerializationError("Refuse str type as a valid iter type.") + + serialization_ctxt = kwargs.get("serialization_ctxt", {}) + is_xml = kwargs.get("is_xml", False) + + serialized = [] + for d in data: + try: + serialized.append(self.serialize_data(d, iter_type, **kwargs)) + except ValueError as err: + if isinstance(err, SerializationError): + raise + serialized.append(None) + + if kwargs.get("do_quote", False): + serialized = ["" if s is None else quote(str(s), safe="") for s in serialized] + + if div: + serialized = ["" if s is None else str(s) for s in serialized] + serialized = div.join(serialized) + + if "xml" in serialization_ctxt or is_xml: + # XML serialization is more complicated + xml_desc = serialization_ctxt.get("xml", {}) + xml_name = xml_desc.get("name") + if not xml_name: + xml_name = serialization_ctxt["key"] + + # Create a wrap node if necessary (use the fact that Element and list have "append") + is_wrapped = xml_desc.get("wrapped", False) + node_name = xml_desc.get("itemsName", xml_name) + if is_wrapped: + final_result = _create_xml_node(xml_name, xml_desc.get("prefix", None), xml_desc.get("ns", None)) + else: + final_result = [] + # All list elements to "local_node" + for el in serialized: + if isinstance(el, ET.Element): + el_node = el + else: + el_node = _create_xml_node(node_name, xml_desc.get("prefix", None), xml_desc.get("ns", None)) + if el is not None: # Otherwise it writes "None" :-p + el_node.text = str(el) + final_result.append(el_node) + return final_result + return serialized + + def serialize_dict(self, attr, dict_type, **kwargs): + """Serialize a dictionary of objects. + + :param dict attr: Object to be serialized. + :param str dict_type: Type of object in the dictionary. + :rtype: dict + :return: serialized dictionary + """ + serialization_ctxt = kwargs.get("serialization_ctxt", {}) + serialized = {} + for key, value in attr.items(): + try: + serialized[self.serialize_unicode(key)] = self.serialize_data(value, dict_type, **kwargs) + except ValueError as err: + if isinstance(err, SerializationError): + raise + serialized[self.serialize_unicode(key)] = None + + if "xml" in serialization_ctxt: + # XML serialization is more complicated + xml_desc = serialization_ctxt["xml"] + xml_name = xml_desc["name"] + + final_result = _create_xml_node(xml_name, xml_desc.get("prefix", None), xml_desc.get("ns", None)) + for key, value in serialized.items(): + ET.SubElement(final_result, key).text = value + return final_result + + return serialized + + def serialize_object(self, attr, **kwargs): # pylint: disable=too-many-return-statements + """Serialize a generic object. + This will be handled as a dictionary. If object passed in is not + a basic type (str, int, float, dict, list) it will simply be + cast to str. + + :param dict attr: Object to be serialized. + :rtype: dict or str + :return: serialized object + """ + if attr is None: + return None + if isinstance(attr, ET.Element): + return attr + obj_type = type(attr) + if obj_type in self.basic_types: + return self.serialize_basic(attr, self.basic_types[obj_type], **kwargs) + if obj_type is _long_type: + return self.serialize_long(attr) + if obj_type is str: + return self.serialize_unicode(attr) + if obj_type is datetime.datetime: + return self.serialize_iso(attr) + if obj_type is datetime.date: + return self.serialize_date(attr) + if obj_type is datetime.time: + return self.serialize_time(attr) + if obj_type is datetime.timedelta: + return self.serialize_duration(attr) + if obj_type is decimal.Decimal: + return self.serialize_decimal(attr) + + # If it's a model or I know this dependency, serialize as a Model + if obj_type in self.dependencies.values() or isinstance(attr, Model): + return self._serialize(attr) + + if obj_type == dict: + serialized = {} + for key, value in attr.items(): + try: + serialized[self.serialize_unicode(key)] = self.serialize_object(value, **kwargs) + except ValueError: + serialized[self.serialize_unicode(key)] = None + return serialized + + if obj_type == list: + serialized = [] + for obj in attr: + try: + serialized.append(self.serialize_object(obj, **kwargs)) + except ValueError: + pass + return serialized + return str(attr) + + @staticmethod + def serialize_enum(attr, enum_obj=None): + try: + result = attr.value + except AttributeError: + result = attr + try: + enum_obj(result) # type: ignore + return result + except ValueError as exc: + for enum_value in enum_obj: # type: ignore + if enum_value.value.lower() == str(attr).lower(): + return enum_value.value + error = "{!r} is not valid value for enum {!r}" + raise SerializationError(error.format(attr, enum_obj)) from exc + + @staticmethod + def serialize_bytearray(attr, **kwargs): # pylint: disable=unused-argument + """Serialize bytearray into base-64 string. + + :param str attr: Object to be serialized. + :rtype: str + :return: serialized base64 + """ + return b64encode(attr).decode() + + @staticmethod + def serialize_base64(attr, **kwargs): # pylint: disable=unused-argument + """Serialize str into base-64 string. + + :param str attr: Object to be serialized. + :rtype: str + :return: serialized base64 + """ + encoded = b64encode(attr).decode("ascii") + return encoded.strip("=").replace("+", "-").replace("/", "_") + + @staticmethod + def serialize_decimal(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Decimal object to float. + + :param decimal attr: Object to be serialized. + :rtype: float + :return: serialized decimal + """ + return float(attr) + + @staticmethod + def serialize_long(attr, **kwargs): # pylint: disable=unused-argument + """Serialize long (Py2) or int (Py3). + + :param int attr: Object to be serialized. + :rtype: int/long + :return: serialized long + """ + return _long_type(attr) + + @staticmethod + def serialize_date(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Date object into ISO-8601 formatted string. + + :param Date attr: Object to be serialized. + :rtype: str + :return: serialized date + """ + if isinstance(attr, str): + attr = isodate.parse_date(attr) + t = "{:04}-{:02}-{:02}".format(attr.year, attr.month, attr.day) + return t + + @staticmethod + def serialize_time(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Time object into ISO-8601 formatted string. + + :param datetime.time attr: Object to be serialized. + :rtype: str + :return: serialized time + """ + if isinstance(attr, str): + attr = isodate.parse_time(attr) + t = "{:02}:{:02}:{:02}".format(attr.hour, attr.minute, attr.second) + if attr.microsecond: + t += ".{:02}".format(attr.microsecond) + return t + + @staticmethod + def serialize_duration(attr, **kwargs): # pylint: disable=unused-argument + """Serialize TimeDelta object into ISO-8601 formatted string. + + :param TimeDelta attr: Object to be serialized. + :rtype: str + :return: serialized duration + """ + if isinstance(attr, str): + attr = isodate.parse_duration(attr) + return isodate.duration_isoformat(attr) + + @staticmethod + def serialize_rfc(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Datetime object into RFC-1123 formatted string. + + :param Datetime attr: Object to be serialized. + :rtype: str + :raises TypeError: if format invalid. + :return: serialized rfc + """ + try: + if not attr.tzinfo: + _LOGGER.warning("Datetime with no tzinfo will be considered UTC.") + utc = attr.utctimetuple() + except AttributeError as exc: + raise TypeError("RFC1123 object must be valid Datetime object.") from exc + + return "{}, {:02} {} {:04} {:02}:{:02}:{:02} GMT".format( + Serializer.days[utc.tm_wday], + utc.tm_mday, + Serializer.months[utc.tm_mon], + utc.tm_year, + utc.tm_hour, + utc.tm_min, + utc.tm_sec, + ) + + @staticmethod + def serialize_iso(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Datetime object into ISO-8601 formatted string. + + :param Datetime attr: Object to be serialized. + :rtype: str + :raises SerializationError: if format invalid. + :return: serialized iso + """ + if isinstance(attr, str): + attr = isodate.parse_datetime(attr) + try: + if not attr.tzinfo: + _LOGGER.warning("Datetime with no tzinfo will be considered UTC.") + utc = attr.utctimetuple() + if utc.tm_year > 9999 or utc.tm_year < 1: + raise OverflowError("Hit max or min date") + + microseconds = str(attr.microsecond).rjust(6, "0").rstrip("0").ljust(3, "0") + if microseconds: + microseconds = "." + microseconds + date = "{:04}-{:02}-{:02}T{:02}:{:02}:{:02}".format( + utc.tm_year, utc.tm_mon, utc.tm_mday, utc.tm_hour, utc.tm_min, utc.tm_sec + ) + return date + microseconds + "Z" + except (ValueError, OverflowError) as err: + msg = "Unable to serialize datetime object." + raise SerializationError(msg) from err + except AttributeError as err: + msg = "ISO-8601 object must be valid Datetime object." + raise TypeError(msg) from err + + @staticmethod + def serialize_unix(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Datetime object into IntTime format. + This is represented as seconds. + + :param Datetime attr: Object to be serialized. + :rtype: int + :raises SerializationError: if format invalid + :return: serialied unix + """ + if isinstance(attr, int): + return attr + try: + if not attr.tzinfo: + _LOGGER.warning("Datetime with no tzinfo will be considered UTC.") + return int(calendar.timegm(attr.utctimetuple())) + except AttributeError as exc: + raise TypeError("Unix time object must be valid Datetime object.") from exc + + +def rest_key_extractor(attr, attr_desc, data): # pylint: disable=unused-argument + key = attr_desc["key"] + working_data = data + + while "." in key: + # Need the cast, as for some reasons "split" is typed as list[str | Any] + dict_keys = cast(List[str], _FLATTEN.split(key)) + if len(dict_keys) == 1: + key = _decode_attribute_map_key(dict_keys[0]) + break + working_key = _decode_attribute_map_key(dict_keys[0]) + working_data = working_data.get(working_key, data) + if working_data is None: + # If at any point while following flatten JSON path see None, it means + # that all properties under are None as well + return None + key = ".".join(dict_keys[1:]) + + return working_data.get(key) + + +def rest_key_case_insensitive_extractor( # pylint: disable=unused-argument, inconsistent-return-statements + attr, attr_desc, data +): + key = attr_desc["key"] + working_data = data + + while "." in key: + dict_keys = _FLATTEN.split(key) + if len(dict_keys) == 1: + key = _decode_attribute_map_key(dict_keys[0]) + break + working_key = _decode_attribute_map_key(dict_keys[0]) + working_data = attribute_key_case_insensitive_extractor(working_key, None, working_data) + if working_data is None: + # If at any point while following flatten JSON path see None, it means + # that all properties under are None as well + return None + key = ".".join(dict_keys[1:]) + + if working_data: + return attribute_key_case_insensitive_extractor(key, None, working_data) + + +def last_rest_key_extractor(attr, attr_desc, data): # pylint: disable=unused-argument + """Extract the attribute in "data" based on the last part of the JSON path key. + + :param str attr: The attribute to extract + :param dict attr_desc: The attribute description + :param dict data: The data to extract from + :rtype: object + :returns: The extracted attribute + """ + key = attr_desc["key"] + dict_keys = _FLATTEN.split(key) + return attribute_key_extractor(dict_keys[-1], None, data) + + +def last_rest_key_case_insensitive_extractor(attr, attr_desc, data): # pylint: disable=unused-argument + """Extract the attribute in "data" based on the last part of the JSON path key. + + This is the case insensitive version of "last_rest_key_extractor" + :param str attr: The attribute to extract + :param dict attr_desc: The attribute description + :param dict data: The data to extract from + :rtype: object + :returns: The extracted attribute + """ + key = attr_desc["key"] + dict_keys = _FLATTEN.split(key) + return attribute_key_case_insensitive_extractor(dict_keys[-1], None, data) + + +def attribute_key_extractor(attr, _, data): + return data.get(attr) + + +def attribute_key_case_insensitive_extractor(attr, _, data): + found_key = None + lower_attr = attr.lower() + for key in data: + if lower_attr == key.lower(): + found_key = key + break + + return data.get(found_key) + + +def _extract_name_from_internal_type(internal_type): + """Given an internal type XML description, extract correct XML name with namespace. + + :param dict internal_type: An model type + :rtype: tuple + :returns: A tuple XML name + namespace dict + """ + internal_type_xml_map = getattr(internal_type, "_xml_map", {}) + xml_name = internal_type_xml_map.get("name", internal_type.__name__) + xml_ns = internal_type_xml_map.get("ns", None) + if xml_ns: + xml_name = "{{{}}}{}".format(xml_ns, xml_name) + return xml_name + + +def xml_key_extractor(attr, attr_desc, data): # pylint: disable=unused-argument,too-many-return-statements + if isinstance(data, dict): + return None + + # Test if this model is XML ready first + if not isinstance(data, ET.Element): + return None + + xml_desc = attr_desc.get("xml", {}) + xml_name = xml_desc.get("name", attr_desc["key"]) + + # Look for a children + is_iter_type = attr_desc["type"].startswith("[") + is_wrapped = xml_desc.get("wrapped", False) + internal_type = attr_desc.get("internalType", None) + internal_type_xml_map = getattr(internal_type, "_xml_map", {}) + + # Integrate namespace if necessary + xml_ns = xml_desc.get("ns", internal_type_xml_map.get("ns", None)) + if xml_ns: + xml_name = "{{{}}}{}".format(xml_ns, xml_name) + + # If it's an attribute, that's simple + if xml_desc.get("attr", False): + return data.get(xml_name) + + # If it's x-ms-text, that's simple too + if xml_desc.get("text", False): + return data.text + + # Scenario where I take the local name: + # - Wrapped node + # - Internal type is an enum (considered basic types) + # - Internal type has no XML/Name node + if is_wrapped or (internal_type and (issubclass(internal_type, Enum) or "name" not in internal_type_xml_map)): + children = data.findall(xml_name) + # If internal type has a local name and it's not a list, I use that name + elif not is_iter_type and internal_type and "name" in internal_type_xml_map: + xml_name = _extract_name_from_internal_type(internal_type) + children = data.findall(xml_name) + # That's an array + else: + if internal_type: # Complex type, ignore itemsName and use the complex type name + items_name = _extract_name_from_internal_type(internal_type) + else: + items_name = xml_desc.get("itemsName", xml_name) + children = data.findall(items_name) + + if len(children) == 0: + if is_iter_type: + if is_wrapped: + return None # is_wrapped no node, we want None + return [] # not wrapped, assume empty list + return None # Assume it's not there, maybe an optional node. + + # If is_iter_type and not wrapped, return all found children + if is_iter_type: + if not is_wrapped: + return children + # Iter and wrapped, should have found one node only (the wrap one) + if len(children) != 1: + raise DeserializationError( + "Tried to deserialize an array not wrapped, and found several nodes '{}'. Maybe you should declare this array as wrapped?".format( + xml_name + ) + ) + return list(children[0]) # Might be empty list and that's ok. + + # Here it's not a itertype, we should have found one element only or empty + if len(children) > 1: + raise DeserializationError("Find several XML '{}' where it was not expected".format(xml_name)) + return children[0] + + +class Deserializer: + """Response object model deserializer. + + :param dict classes: Class type dictionary for deserializing complex types. + :ivar list key_extractors: Ordered list of extractors to be used by this deserializer. + """ + + basic_types = {str: "str", int: "int", bool: "bool", float: "float"} + + valid_date = re.compile(r"\d{4}[-]\d{2}[-]\d{2}T\d{2}:\d{2}:\d{2}\.?\d*Z?[-+]?[\d{2}]?:?[\d{2}]?") + + def __init__(self, classes: Optional[Mapping[str, type]] = None) -> None: + self.deserialize_type = { + "iso-8601": Deserializer.deserialize_iso, + "rfc-1123": Deserializer.deserialize_rfc, + "unix-time": Deserializer.deserialize_unix, + "duration": Deserializer.deserialize_duration, + "date": Deserializer.deserialize_date, + "time": Deserializer.deserialize_time, + "decimal": Deserializer.deserialize_decimal, + "long": Deserializer.deserialize_long, + "bytearray": Deserializer.deserialize_bytearray, + "base64": Deserializer.deserialize_base64, + "object": self.deserialize_object, + "[]": self.deserialize_iter, + "{}": self.deserialize_dict, + } + self.deserialize_expected_types = { + "duration": (isodate.Duration, datetime.timedelta), + "iso-8601": (datetime.datetime), + } + self.dependencies: Dict[str, type] = dict(classes) if classes else {} + self.key_extractors = [rest_key_extractor, xml_key_extractor] + # Additional properties only works if the "rest_key_extractor" is used to + # extract the keys. Making it to work whatever the key extractor is too much + # complicated, with no real scenario for now. + # So adding a flag to disable additional properties detection. This flag should be + # used if your expect the deserialization to NOT come from a JSON REST syntax. + # Otherwise, result are unexpected + self.additional_properties_detection = True + + def __call__(self, target_obj, response_data, content_type=None): + """Call the deserializer to process a REST response. + + :param str target_obj: Target data type to deserialize to. + :param requests.Response response_data: REST response object. + :param str content_type: Swagger "produces" if available. + :raises DeserializationError: if deserialization fails. + :return: Deserialized object. + :rtype: object + """ + data = self._unpack_content(response_data, content_type) + return self._deserialize(target_obj, data) + + def _deserialize(self, target_obj, data): # pylint: disable=inconsistent-return-statements + """Call the deserializer on a model. + + Data needs to be already deserialized as JSON or XML ElementTree + + :param str target_obj: Target data type to deserialize to. + :param object data: Object to deserialize. + :raises DeserializationError: if deserialization fails. + :return: Deserialized object. + :rtype: object + """ + # This is already a model, go recursive just in case + if hasattr(data, "_attribute_map"): + constants = [name for name, config in getattr(data, "_validation", {}).items() if config.get("constant")] + try: + for attr, mapconfig in data._attribute_map.items(): # pylint: disable=protected-access + if attr in constants: + continue + value = getattr(data, attr) + if value is None: + continue + local_type = mapconfig["type"] + internal_data_type = local_type.strip("[]{}") + if internal_data_type not in self.dependencies or isinstance(internal_data_type, Enum): + continue + setattr(data, attr, self._deserialize(local_type, value)) + return data + except AttributeError: + return + + response, class_name = self._classify_target(target_obj, data) + + if isinstance(response, str): + return self.deserialize_data(data, response) + if isinstance(response, type) and issubclass(response, Enum): + return self.deserialize_enum(data, response) + + if data is None or data is CoreNull: + return data + try: + attributes = response._attribute_map # type: ignore # pylint: disable=protected-access + d_attrs = {} + for attr, attr_desc in attributes.items(): + # Check empty string. If it's not empty, someone has a real "additionalProperties"... + if attr == "additional_properties" and attr_desc["key"] == "": + continue + raw_value = None + # Enhance attr_desc with some dynamic data + attr_desc = attr_desc.copy() # Do a copy, do not change the real one + internal_data_type = attr_desc["type"].strip("[]{}") + if internal_data_type in self.dependencies: + attr_desc["internalType"] = self.dependencies[internal_data_type] + + for key_extractor in self.key_extractors: + found_value = key_extractor(attr, attr_desc, data) + if found_value is not None: + if raw_value is not None and raw_value != found_value: + msg = ( + "Ignoring extracted value '%s' from %s for key '%s'" + " (duplicate extraction, follow extractors order)" + ) + _LOGGER.warning(msg, found_value, key_extractor, attr) + continue + raw_value = found_value + + value = self.deserialize_data(raw_value, attr_desc["type"]) + d_attrs[attr] = value + except (AttributeError, TypeError, KeyError) as err: + msg = "Unable to deserialize to object: " + class_name # type: ignore + raise DeserializationError(msg) from err + additional_properties = self._build_additional_properties(attributes, data) + return self._instantiate_model(response, d_attrs, additional_properties) + + def _build_additional_properties(self, attribute_map, data): + if not self.additional_properties_detection: + return None + if "additional_properties" in attribute_map and attribute_map.get("additional_properties", {}).get("key") != "": + # Check empty string. If it's not empty, someone has a real "additionalProperties" + return None + if isinstance(data, ET.Element): + data = {el.tag: el.text for el in data} + + known_keys = { + _decode_attribute_map_key(_FLATTEN.split(desc["key"])[0]) + for desc in attribute_map.values() + if desc["key"] != "" + } + present_keys = set(data.keys()) + missing_keys = present_keys - known_keys + return {key: data[key] for key in missing_keys} + + def _classify_target(self, target, data): + """Check to see whether the deserialization target object can + be classified into a subclass. + Once classification has been determined, initialize object. + + :param str target: The target object type to deserialize to. + :param str/dict data: The response data to deserialize. + :return: The classified target object and its class name. + :rtype: tuple + """ + if target is None: + return None, None + + if isinstance(target, str): + try: + target = self.dependencies[target] + except KeyError: + return target, target + + try: + target = target._classify(data, self.dependencies) # type: ignore # pylint: disable=protected-access + except AttributeError: + pass # Target is not a Model, no classify + return target, target.__class__.__name__ # type: ignore + + def failsafe_deserialize(self, target_obj, data, content_type=None): + """Ignores any errors encountered in deserialization, + and falls back to not deserializing the object. Recommended + for use in error deserialization, as we want to return the + HttpResponseError to users, and not have them deal with + a deserialization error. + + :param str target_obj: The target object type to deserialize to. + :param str/dict data: The response data to deserialize. + :param str content_type: Swagger "produces" if available. + :return: Deserialized object. + :rtype: object + """ + try: + return self(target_obj, data, content_type=content_type) + except: # pylint: disable=bare-except + _LOGGER.debug( + "Ran into a deserialization error. Ignoring since this is failsafe deserialization", exc_info=True + ) + return None + + @staticmethod + def _unpack_content(raw_data, content_type=None): + """Extract the correct structure for deserialization. + + If raw_data is a PipelineResponse, try to extract the result of RawDeserializer. + if we can't, raise. Your Pipeline should have a RawDeserializer. + + If not a pipeline response and raw_data is bytes or string, use content-type + to decode it. If no content-type, try JSON. + + If raw_data is something else, bypass all logic and return it directly. + + :param obj raw_data: Data to be processed. + :param str content_type: How to parse if raw_data is a string/bytes. + :raises JSONDecodeError: If JSON is requested and parsing is impossible. + :raises UnicodeDecodeError: If bytes is not UTF8 + :rtype: object + :return: Unpacked content. + """ + # Assume this is enough to detect a Pipeline Response without importing it + context = getattr(raw_data, "context", {}) + if context: + if RawDeserializer.CONTEXT_NAME in context: + return context[RawDeserializer.CONTEXT_NAME] + raise ValueError("This pipeline didn't have the RawDeserializer policy; can't deserialize") + + # Assume this is enough to recognize universal_http.ClientResponse without importing it + if hasattr(raw_data, "body"): + return RawDeserializer.deserialize_from_http_generics(raw_data.text(), raw_data.headers) + + # Assume this enough to recognize requests.Response without importing it. + if hasattr(raw_data, "_content_consumed"): + return RawDeserializer.deserialize_from_http_generics(raw_data.text, raw_data.headers) + + if isinstance(raw_data, (str, bytes)) or hasattr(raw_data, "read"): + return RawDeserializer.deserialize_from_text(raw_data, content_type) # type: ignore + return raw_data + + def _instantiate_model(self, response, attrs, additional_properties=None): + """Instantiate a response model passing in deserialized args. + + :param Response response: The response model class. + :param dict attrs: The deserialized response attributes. + :param dict additional_properties: Additional properties to be set. + :rtype: Response + :return: The instantiated response model. + """ + if callable(response): + subtype = getattr(response, "_subtype_map", {}) + try: + readonly = [ + k + for k, v in response._validation.items() # pylint: disable=protected-access # type: ignore + if v.get("readonly") + ] + const = [ + k + for k, v in response._validation.items() # pylint: disable=protected-access # type: ignore + if v.get("constant") + ] + kwargs = {k: v for k, v in attrs.items() if k not in subtype and k not in readonly + const} + response_obj = response(**kwargs) + for attr in readonly: + setattr(response_obj, attr, attrs.get(attr)) + if additional_properties: + response_obj.additional_properties = additional_properties # type: ignore + return response_obj + except TypeError as err: + msg = "Unable to deserialize {} into model {}. ".format(kwargs, response) # type: ignore + raise DeserializationError(msg + str(err)) from err + else: + try: + for attr, value in attrs.items(): + setattr(response, attr, value) + return response + except Exception as exp: + msg = "Unable to populate response model. " + msg += "Type: {}, Error: {}".format(type(response), exp) + raise DeserializationError(msg) from exp + + def deserialize_data(self, data, data_type): # pylint: disable=too-many-return-statements + """Process data for deserialization according to data type. + + :param str data: The response string to be deserialized. + :param str data_type: The type to deserialize to. + :raises DeserializationError: if deserialization fails. + :return: Deserialized object. + :rtype: object + """ + if data is None: + return data + + try: + if not data_type: + return data + if data_type in self.basic_types.values(): + return self.deserialize_basic(data, data_type) + if data_type in self.deserialize_type: + if isinstance(data, self.deserialize_expected_types.get(data_type, tuple())): + return data + + is_a_text_parsing_type = lambda x: x not in [ # pylint: disable=unnecessary-lambda-assignment + "object", + "[]", + r"{}", + ] + if isinstance(data, ET.Element) and is_a_text_parsing_type(data_type) and not data.text: + return None + data_val = self.deserialize_type[data_type](data) + return data_val + + iter_type = data_type[0] + data_type[-1] + if iter_type in self.deserialize_type: + return self.deserialize_type[iter_type](data, data_type[1:-1]) + + obj_type = self.dependencies[data_type] + if issubclass(obj_type, Enum): + if isinstance(data, ET.Element): + data = data.text + return self.deserialize_enum(data, obj_type) + + except (ValueError, TypeError, AttributeError) as err: + msg = "Unable to deserialize response data." + msg += " Data: {}, {}".format(data, data_type) + raise DeserializationError(msg) from err + return self._deserialize(obj_type, data) + + def deserialize_iter(self, attr, iter_type): + """Deserialize an iterable. + + :param list attr: Iterable to be deserialized. + :param str iter_type: The type of object in the iterable. + :return: Deserialized iterable. + :rtype: list + """ + if attr is None: + return None + if isinstance(attr, ET.Element): # If I receive an element here, get the children + attr = list(attr) + if not isinstance(attr, (list, set)): + raise DeserializationError("Cannot deserialize as [{}] an object of type {}".format(iter_type, type(attr))) + return [self.deserialize_data(a, iter_type) for a in attr] + + def deserialize_dict(self, attr, dict_type): + """Deserialize a dictionary. + + :param dict/list attr: Dictionary to be deserialized. Also accepts + a list of key, value pairs. + :param str dict_type: The object type of the items in the dictionary. + :return: Deserialized dictionary. + :rtype: dict + """ + if isinstance(attr, list): + return {x["key"]: self.deserialize_data(x["value"], dict_type) for x in attr} + + if isinstance(attr, ET.Element): + # Transform value into {"Key": "value"} + attr = {el.tag: el.text for el in attr} + return {k: self.deserialize_data(v, dict_type) for k, v in attr.items()} + + def deserialize_object(self, attr, **kwargs): # pylint: disable=too-many-return-statements + """Deserialize a generic object. + This will be handled as a dictionary. + + :param dict attr: Dictionary to be deserialized. + :return: Deserialized object. + :rtype: dict + :raises TypeError: if non-builtin datatype encountered. + """ + if attr is None: + return None + if isinstance(attr, ET.Element): + # Do no recurse on XML, just return the tree as-is + return attr + if isinstance(attr, str): + return self.deserialize_basic(attr, "str") + obj_type = type(attr) + if obj_type in self.basic_types: + return self.deserialize_basic(attr, self.basic_types[obj_type]) + if obj_type is _long_type: + return self.deserialize_long(attr) + + if obj_type == dict: + deserialized = {} + for key, value in attr.items(): + try: + deserialized[key] = self.deserialize_object(value, **kwargs) + except ValueError: + deserialized[key] = None + return deserialized + + if obj_type == list: + deserialized = [] + for obj in attr: + try: + deserialized.append(self.deserialize_object(obj, **kwargs)) + except ValueError: + pass + return deserialized + + error = "Cannot deserialize generic object with type: " + raise TypeError(error + str(obj_type)) + + def deserialize_basic(self, attr, data_type): # pylint: disable=too-many-return-statements + """Deserialize basic builtin data type from string. + Will attempt to convert to str, int, float and bool. + This function will also accept '1', '0', 'true' and 'false' as + valid bool values. + + :param str attr: response string to be deserialized. + :param str data_type: deserialization data type. + :return: Deserialized basic type. + :rtype: str, int, float or bool + :raises TypeError: if string format is not valid. + """ + # If we're here, data is supposed to be a basic type. + # If it's still an XML node, take the text + if isinstance(attr, ET.Element): + attr = attr.text + if not attr: + if data_type == "str": + # None or '', node is empty string. + return "" + # None or '', node with a strong type is None. + # Don't try to model "empty bool" or "empty int" + return None + + if data_type == "bool": + if attr in [True, False, 1, 0]: + return bool(attr) + if isinstance(attr, str): + if attr.lower() in ["true", "1"]: + return True + if attr.lower() in ["false", "0"]: + return False + raise TypeError("Invalid boolean value: {}".format(attr)) + + if data_type == "str": + return self.deserialize_unicode(attr) + return eval(data_type)(attr) # nosec # pylint: disable=eval-used + + @staticmethod + def deserialize_unicode(data): + """Preserve unicode objects in Python 2, otherwise return data + as a string. + + :param str data: response string to be deserialized. + :return: Deserialized string. + :rtype: str or unicode + """ + # We might be here because we have an enum modeled as string, + # and we try to deserialize a partial dict with enum inside + if isinstance(data, Enum): + return data + + # Consider this is real string + try: + if isinstance(data, unicode): # type: ignore + return data + except NameError: + return str(data) + return str(data) + + @staticmethod + def deserialize_enum(data, enum_obj): + """Deserialize string into enum object. + + If the string is not a valid enum value it will be returned as-is + and a warning will be logged. + + :param str data: Response string to be deserialized. If this value is + None or invalid it will be returned as-is. + :param Enum enum_obj: Enum object to deserialize to. + :return: Deserialized enum object. + :rtype: Enum + """ + if isinstance(data, enum_obj) or data is None: + return data + if isinstance(data, Enum): + data = data.value + if isinstance(data, int): + # Workaround. We might consider remove it in the future. + try: + return list(enum_obj.__members__.values())[data] + except IndexError as exc: + error = "{!r} is not a valid index for enum {!r}" + raise DeserializationError(error.format(data, enum_obj)) from exc + try: + return enum_obj(str(data)) + except ValueError: + for enum_value in enum_obj: + if enum_value.value.lower() == str(data).lower(): + return enum_value + # We don't fail anymore for unknown value, we deserialize as a string + _LOGGER.warning("Deserializer is not able to find %s as valid enum in %s", data, enum_obj) + return Deserializer.deserialize_unicode(data) + + @staticmethod + def deserialize_bytearray(attr): + """Deserialize string into bytearray. + + :param str attr: response string to be deserialized. + :return: Deserialized bytearray + :rtype: bytearray + :raises TypeError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + return bytearray(b64decode(attr)) # type: ignore + + @staticmethod + def deserialize_base64(attr): + """Deserialize base64 encoded string into string. + + :param str attr: response string to be deserialized. + :return: Deserialized base64 string + :rtype: bytearray + :raises TypeError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + padding = "=" * (3 - (len(attr) + 3) % 4) # type: ignore + attr = attr + padding # type: ignore + encoded = attr.replace("-", "+").replace("_", "/") + return b64decode(encoded) + + @staticmethod + def deserialize_decimal(attr): + """Deserialize string into Decimal object. + + :param str attr: response string to be deserialized. + :return: Deserialized decimal + :raises DeserializationError: if string format invalid. + :rtype: decimal + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + return decimal.Decimal(str(attr)) # type: ignore + except decimal.DecimalException as err: + msg = "Invalid decimal {}".format(attr) + raise DeserializationError(msg) from err + + @staticmethod + def deserialize_long(attr): + """Deserialize string into long (Py2) or int (Py3). + + :param str attr: response string to be deserialized. + :return: Deserialized int + :rtype: long or int + :raises ValueError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + return _long_type(attr) # type: ignore + + @staticmethod + def deserialize_duration(attr): + """Deserialize ISO-8601 formatted string into TimeDelta object. + + :param str attr: response string to be deserialized. + :return: Deserialized duration + :rtype: TimeDelta + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + duration = isodate.parse_duration(attr) + except (ValueError, OverflowError, AttributeError) as err: + msg = "Cannot deserialize duration object." + raise DeserializationError(msg) from err + return duration + + @staticmethod + def deserialize_date(attr): + """Deserialize ISO-8601 formatted string into Date object. + + :param str attr: response string to be deserialized. + :return: Deserialized date + :rtype: Date + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + if re.search(r"[^\W\d_]", attr, re.I + re.U): # type: ignore + raise DeserializationError("Date must have only digits and -. Received: %s" % attr) + # This must NOT use defaultmonth/defaultday. Using None ensure this raises an exception. + return isodate.parse_date(attr, defaultmonth=0, defaultday=0) + + @staticmethod + def deserialize_time(attr): + """Deserialize ISO-8601 formatted string into time object. + + :param str attr: response string to be deserialized. + :return: Deserialized time + :rtype: datetime.time + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + if re.search(r"[^\W\d_]", attr, re.I + re.U): # type: ignore + raise DeserializationError("Date must have only digits and -. Received: %s" % attr) + return isodate.parse_time(attr) + + @staticmethod + def deserialize_rfc(attr): + """Deserialize RFC-1123 formatted string into Datetime object. + + :param str attr: response string to be deserialized. + :return: Deserialized RFC datetime + :rtype: Datetime + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + parsed_date = email.utils.parsedate_tz(attr) # type: ignore + date_obj = datetime.datetime( + *parsed_date[:6], tzinfo=datetime.timezone(datetime.timedelta(minutes=(parsed_date[9] or 0) / 60)) + ) + if not date_obj.tzinfo: + date_obj = date_obj.astimezone(tz=TZ_UTC) + except ValueError as err: + msg = "Cannot deserialize to rfc datetime object." + raise DeserializationError(msg) from err + return date_obj + + @staticmethod + def deserialize_iso(attr): + """Deserialize ISO-8601 formatted string into Datetime object. + + :param str attr: response string to be deserialized. + :return: Deserialized ISO datetime + :rtype: Datetime + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + attr = attr.upper() # type: ignore + match = Deserializer.valid_date.match(attr) + if not match: + raise ValueError("Invalid datetime string: " + attr) + + check_decimal = attr.split(".") + if len(check_decimal) > 1: + decimal_str = "" + for digit in check_decimal[1]: + if digit.isdigit(): + decimal_str += digit + else: + break + if len(decimal_str) > 6: + attr = attr.replace(decimal_str, decimal_str[0:6]) + + date_obj = isodate.parse_datetime(attr) + test_utc = date_obj.utctimetuple() + if test_utc.tm_year > 9999 or test_utc.tm_year < 1: + raise OverflowError("Hit max or min date") + except (ValueError, OverflowError, AttributeError) as err: + msg = "Cannot deserialize datetime object." + raise DeserializationError(msg) from err + return date_obj + + @staticmethod + def deserialize_unix(attr): + """Serialize Datetime object into IntTime format. + This is represented as seconds. + + :param int attr: Object to be serialized. + :return: Deserialized datetime + :rtype: Datetime + :raises DeserializationError: if format invalid + """ + if isinstance(attr, ET.Element): + attr = int(attr.text) # type: ignore + try: + attr = int(attr) + date_obj = datetime.datetime.fromtimestamp(attr, TZ_UTC) + except ValueError as err: + msg = "Cannot deserialize to unix datetime object." + raise DeserializationError(msg) from err + return date_obj diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyFormDataVersionTolerant/bodyformdataversiontolerant/aio/_vendor.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyFormUrlEncodedDataVersionTolerant/bodyformurlencodeddataversiontolerant/_utils/utils.py similarity index 100% rename from packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyFormDataVersionTolerant/bodyformdataversiontolerant/aio/_vendor.py rename to packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyFormUrlEncodedDataVersionTolerant/bodyformurlencodeddataversiontolerant/_utils/utils.py diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyFormUrlEncodedDataVersionTolerant/bodyformurlencodeddataversiontolerant/_vendor.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyFormUrlEncodedDataVersionTolerant/bodyformurlencodeddataversiontolerant/_vendor.py deleted file mode 100644 index 3e21ea6effc..00000000000 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyFormUrlEncodedDataVersionTolerant/bodyformurlencodeddataversiontolerant/_vendor.py +++ /dev/null @@ -1,17 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) AutoRest Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - - -def raise_if_not_implemented(cls, abstract_methods): - not_implemented = [f for f in abstract_methods if not callable(getattr(cls, f, None))] - if not_implemented: - raise NotImplementedError( - "The following methods on operation group '{}' are not implemented: '{}'." - " Please refer to https://aka.ms/azsdk/python/dpcodegen/python/customize to learn how to customize.".format( - cls.__name__, "', '".join(not_implemented) - ) - ) diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyFormUrlEncodedDataVersionTolerant/bodyformurlencodeddataversiontolerant/aio/_client.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyFormUrlEncodedDataVersionTolerant/bodyformurlencodeddataversiontolerant/aio/_client.py index 642fb99c6af..b3033c96c14 100644 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyFormUrlEncodedDataVersionTolerant/bodyformurlencodeddataversiontolerant/aio/_client.py +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyFormUrlEncodedDataVersionTolerant/bodyformurlencodeddataversiontolerant/aio/_client.py @@ -14,7 +14,7 @@ from azure.core.pipeline import policies from azure.core.rest import AsyncHttpResponse, HttpRequest -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import BodyFormsDataURLEncodedConfiguration from .operations import FormdataurlencodedOperations diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyFormUrlEncodedDataVersionTolerant/bodyformurlencodeddataversiontolerant/aio/_vendor.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyFormUrlEncodedDataVersionTolerant/bodyformurlencodeddataversiontolerant/aio/_vendor.py deleted file mode 100644 index 3e21ea6effc..00000000000 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyFormUrlEncodedDataVersionTolerant/bodyformurlencodeddataversiontolerant/aio/_vendor.py +++ /dev/null @@ -1,17 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) AutoRest Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - - -def raise_if_not_implemented(cls, abstract_methods): - not_implemented = [f for f in abstract_methods if not callable(getattr(cls, f, None))] - if not_implemented: - raise NotImplementedError( - "The following methods on operation group '{}' are not implemented: '{}'." - " Please refer to https://aka.ms/azsdk/python/dpcodegen/python/customize to learn how to customize.".format( - cls.__name__, "', '".join(not_implemented) - ) - ) diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyFormUrlEncodedDataVersionTolerant/bodyformurlencodeddataversiontolerant/aio/operations/_operations.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyFormUrlEncodedDataVersionTolerant/bodyformurlencodeddataversiontolerant/aio/operations/_operations.py index 3406c03fa98..81095fb5725 100644 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyFormUrlEncodedDataVersionTolerant/bodyformurlencodeddataversiontolerant/aio/operations/_operations.py +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyFormUrlEncodedDataVersionTolerant/bodyformurlencodeddataversiontolerant/aio/operations/_operations.py @@ -7,9 +7,9 @@ # -------------------------------------------------------------------------- from azure.core import AsyncPipelineClient -from ..._serialization import Deserializer, Serializer +from ..._utils.serialization import Deserializer, Serializer +from ..._utils.utils import raise_if_not_implemented from .._configuration import BodyFormsDataURLEncodedConfiguration -from .._vendor import raise_if_not_implemented class FormdataurlencodedOperations: # pylint: disable=abstract-class-instantiated diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyFormUrlEncodedDataVersionTolerant/bodyformurlencodeddataversiontolerant/operations/_operations.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyFormUrlEncodedDataVersionTolerant/bodyformurlencodeddataversiontolerant/operations/_operations.py index 9435c7fd051..437e4e541c4 100644 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyFormUrlEncodedDataVersionTolerant/bodyformurlencodeddataversiontolerant/operations/_operations.py +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyFormUrlEncodedDataVersionTolerant/bodyformurlencodeddataversiontolerant/operations/_operations.py @@ -8,8 +8,8 @@ from azure.core import PipelineClient from .._configuration import BodyFormsDataURLEncodedConfiguration -from .._serialization import Deserializer, Serializer -from .._vendor import raise_if_not_implemented +from .._utils.serialization import Deserializer, Serializer +from .._utils.utils import raise_if_not_implemented class FormdataurlencodedOperations: # pylint: disable=abstract-class-instantiated diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyIntegerVersionTolerant/bodyintegerversiontolerant/_client.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyIntegerVersionTolerant/bodyintegerversiontolerant/_client.py index 2b189b6c855..5452ce36a51 100644 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyIntegerVersionTolerant/bodyintegerversiontolerant/_client.py +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyIntegerVersionTolerant/bodyintegerversiontolerant/_client.py @@ -15,7 +15,7 @@ from azure.core.rest import HttpRequest, HttpResponse from ._configuration import AutoRestIntegerTestServiceConfiguration -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer from .operations import IntOperations diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyIntegerVersionTolerant/bodyintegerversiontolerant/_utils/__init__.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyIntegerVersionTolerant/bodyintegerversiontolerant/_utils/__init__.py new file mode 100644 index 00000000000..0af9b28f660 --- /dev/null +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyIntegerVersionTolerant/bodyintegerversiontolerant/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyIntegerVersionTolerant/bodyintegerversiontolerant/_utils/serialization.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyIntegerVersionTolerant/bodyintegerversiontolerant/_utils/serialization.py new file mode 100644 index 00000000000..f5187701d7b --- /dev/null +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyIntegerVersionTolerant/bodyintegerversiontolerant/_utils/serialization.py @@ -0,0 +1,2032 @@ +# pylint: disable=line-too-long,useless-suppression,too-many-lines +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +# pyright: reportUnnecessaryTypeIgnoreComment=false + +from base64 import b64decode, b64encode +import calendar +import datetime +import decimal +import email +from enum import Enum +import json +import logging +import re +import sys +import codecs +from typing import ( + Dict, + Any, + cast, + Optional, + Union, + AnyStr, + IO, + Mapping, + Callable, + MutableMapping, + List, +) + +try: + from urllib import quote # type: ignore +except ImportError: + from urllib.parse import quote +import xml.etree.ElementTree as ET + +import isodate # type: ignore +from typing_extensions import Self + +from azure.core.exceptions import DeserializationError, SerializationError +from azure.core.serialization import NULL as CoreNull + +_BOM = codecs.BOM_UTF8.decode(encoding="utf-8") + +JSON = MutableMapping[str, Any] + + +class RawDeserializer: + + # Accept "text" because we're open minded people... + JSON_REGEXP = re.compile(r"^(application|text)/([a-z+.]+\+)?json$") + + # Name used in context + CONTEXT_NAME = "deserialized_data" + + @classmethod + def deserialize_from_text(cls, data: Optional[Union[AnyStr, IO]], content_type: Optional[str] = None) -> Any: + """Decode data according to content-type. + + Accept a stream of data as well, but will be load at once in memory for now. + + If no content-type, will return the string version (not bytes, not stream) + + :param data: Input, could be bytes or stream (will be decoded with UTF8) or text + :type data: str or bytes or IO + :param str content_type: The content type. + :return: The deserialized data. + :rtype: object + """ + if hasattr(data, "read"): + # Assume a stream + data = cast(IO, data).read() + + if isinstance(data, bytes): + data_as_str = data.decode(encoding="utf-8-sig") + else: + # Explain to mypy the correct type. + data_as_str = cast(str, data) + + # Remove Byte Order Mark if present in string + data_as_str = data_as_str.lstrip(_BOM) + + if content_type is None: + return data + + if cls.JSON_REGEXP.match(content_type): + try: + return json.loads(data_as_str) + except ValueError as err: + raise DeserializationError("JSON is invalid: {}".format(err), err) from err + elif "xml" in (content_type or []): + try: + + try: + if isinstance(data, unicode): # type: ignore + # If I'm Python 2.7 and unicode XML will scream if I try a "fromstring" on unicode string + data_as_str = data_as_str.encode(encoding="utf-8") # type: ignore + except NameError: + pass + + return ET.fromstring(data_as_str) # nosec + except ET.ParseError as err: + # It might be because the server has an issue, and returned JSON with + # content-type XML.... + # So let's try a JSON load, and if it's still broken + # let's flow the initial exception + def _json_attemp(data): + try: + return True, json.loads(data) + except ValueError: + return False, None # Don't care about this one + + success, json_result = _json_attemp(data) + if success: + return json_result + # If i'm here, it's not JSON, it's not XML, let's scream + # and raise the last context in this block (the XML exception) + # The function hack is because Py2.7 messes up with exception + # context otherwise. + _LOGGER.critical("Wasn't XML not JSON, failing") + raise DeserializationError("XML is invalid") from err + elif content_type.startswith("text/"): + return data_as_str + raise DeserializationError("Cannot deserialize content-type: {}".format(content_type)) + + @classmethod + def deserialize_from_http_generics(cls, body_bytes: Optional[Union[AnyStr, IO]], headers: Mapping) -> Any: + """Deserialize from HTTP response. + + Use bytes and headers to NOT use any requests/aiohttp or whatever + specific implementation. + Headers will tested for "content-type" + + :param bytes body_bytes: The body of the response. + :param dict headers: The headers of the response. + :returns: The deserialized data. + :rtype: object + """ + # Try to use content-type from headers if available + content_type = None + if "content-type" in headers: + content_type = headers["content-type"].split(";")[0].strip().lower() + # Ouch, this server did not declare what it sent... + # Let's guess it's JSON... + # Also, since Autorest was considering that an empty body was a valid JSON, + # need that test as well.... + else: + content_type = "application/json" + + if body_bytes: + return cls.deserialize_from_text(body_bytes, content_type) + return None + + +_LOGGER = logging.getLogger(__name__) + +try: + _long_type = long # type: ignore +except NameError: + _long_type = int + +TZ_UTC = datetime.timezone.utc + +_FLATTEN = re.compile(r"(? None: + self.additional_properties: Optional[Dict[str, Any]] = {} + for k in kwargs: # pylint: disable=consider-using-dict-items + if k not in self._attribute_map: + _LOGGER.warning("%s is not a known attribute of class %s and will be ignored", k, self.__class__) + elif k in self._validation and self._validation[k].get("readonly", False): + _LOGGER.warning("Readonly attribute %s will be ignored in class %s", k, self.__class__) + else: + setattr(self, k, kwargs[k]) + + def __eq__(self, other: Any) -> bool: + """Compare objects by comparing all attributes. + + :param object other: The object to compare + :returns: True if objects are equal + :rtype: bool + """ + if isinstance(other, self.__class__): + return self.__dict__ == other.__dict__ + return False + + def __ne__(self, other: Any) -> bool: + """Compare objects by comparing all attributes. + + :param object other: The object to compare + :returns: True if objects are not equal + :rtype: bool + """ + return not self.__eq__(other) + + def __str__(self) -> str: + return str(self.__dict__) + + @classmethod + def enable_additional_properties_sending(cls) -> None: + cls._attribute_map["additional_properties"] = {"key": "", "type": "{object}"} + + @classmethod + def is_xml_model(cls) -> bool: + try: + cls._xml_map # type: ignore + except AttributeError: + return False + return True + + @classmethod + def _create_xml_node(cls): + """Create XML node. + + :returns: The XML node + :rtype: xml.etree.ElementTree.Element + """ + try: + xml_map = cls._xml_map # type: ignore + except AttributeError: + xml_map = {} + + return _create_xml_node(xml_map.get("name", cls.__name__), xml_map.get("prefix", None), xml_map.get("ns", None)) + + def serialize(self, keep_readonly: bool = False, **kwargs: Any) -> JSON: + """Return the JSON that would be sent to server from this model. + + This is an alias to `as_dict(full_restapi_key_transformer, keep_readonly=False)`. + + If you want XML serialization, you can pass the kwargs is_xml=True. + + :param bool keep_readonly: If you want to serialize the readonly attributes + :returns: A dict JSON compatible object + :rtype: dict + """ + serializer = Serializer(self._infer_class_models()) + return serializer._serialize( # type: ignore # pylint: disable=protected-access + self, keep_readonly=keep_readonly, **kwargs + ) + + def as_dict( + self, + keep_readonly: bool = True, + key_transformer: Callable[[str, Dict[str, Any], Any], Any] = attribute_transformer, + **kwargs: Any + ) -> JSON: + """Return a dict that can be serialized using json.dump. + + Advanced usage might optionally use a callback as parameter: + + .. code::python + + def my_key_transformer(key, attr_desc, value): + return key + + Key is the attribute name used in Python. Attr_desc + is a dict of metadata. Currently contains 'type' with the + msrest type and 'key' with the RestAPI encoded key. + Value is the current value in this object. + + The string returned will be used to serialize the key. + If the return type is a list, this is considered hierarchical + result dict. + + See the three examples in this file: + + - attribute_transformer + - full_restapi_key_transformer + - last_restapi_key_transformer + + If you want XML serialization, you can pass the kwargs is_xml=True. + + :param bool keep_readonly: If you want to serialize the readonly attributes + :param function key_transformer: A key transformer function. + :returns: A dict JSON compatible object + :rtype: dict + """ + serializer = Serializer(self._infer_class_models()) + return serializer._serialize( # type: ignore # pylint: disable=protected-access + self, key_transformer=key_transformer, keep_readonly=keep_readonly, **kwargs + ) + + @classmethod + def _infer_class_models(cls): + try: + str_models = cls.__module__.rsplit(".", 1)[0] + models = sys.modules[str_models] + client_models = {k: v for k, v in models.__dict__.items() if isinstance(v, type)} + if cls.__name__ not in client_models: + raise ValueError("Not Autorest generated code") + except Exception: # pylint: disable=broad-exception-caught + # Assume it's not Autorest generated (tests?). Add ourselves as dependencies. + client_models = {cls.__name__: cls} + return client_models + + @classmethod + def deserialize(cls, data: Any, content_type: Optional[str] = None) -> Self: + """Parse a str using the RestAPI syntax and return a model. + + :param str data: A str using RestAPI structure. JSON by default. + :param str content_type: JSON by default, set application/xml if XML. + :returns: An instance of this model + :raises DeserializationError: if something went wrong + :rtype: Self + """ + deserializer = Deserializer(cls._infer_class_models()) + return deserializer(cls.__name__, data, content_type=content_type) # type: ignore + + @classmethod + def from_dict( + cls, + data: Any, + key_extractors: Optional[Callable[[str, Dict[str, Any], Any], Any]] = None, + content_type: Optional[str] = None, + ) -> Self: + """Parse a dict using given key extractor return a model. + + By default consider key + extractors (rest_key_case_insensitive_extractor, attribute_key_case_insensitive_extractor + and last_rest_key_case_insensitive_extractor) + + :param dict data: A dict using RestAPI structure + :param function key_extractors: A key extractor function. + :param str content_type: JSON by default, set application/xml if XML. + :returns: An instance of this model + :raises DeserializationError: if something went wrong + :rtype: Self + """ + deserializer = Deserializer(cls._infer_class_models()) + deserializer.key_extractors = ( # type: ignore + [ # type: ignore + attribute_key_case_insensitive_extractor, + rest_key_case_insensitive_extractor, + last_rest_key_case_insensitive_extractor, + ] + if key_extractors is None + else key_extractors + ) + return deserializer(cls.__name__, data, content_type=content_type) # type: ignore + + @classmethod + def _flatten_subtype(cls, key, objects): + if "_subtype_map" not in cls.__dict__: + return {} + result = dict(cls._subtype_map[key]) + for valuetype in cls._subtype_map[key].values(): + result.update(objects[valuetype]._flatten_subtype(key, objects)) # pylint: disable=protected-access + return result + + @classmethod + def _classify(cls, response, objects): + """Check the class _subtype_map for any child classes. + We want to ignore any inherited _subtype_maps. + + :param dict response: The initial data + :param dict objects: The class objects + :returns: The class to be used + :rtype: class + """ + for subtype_key in cls.__dict__.get("_subtype_map", {}).keys(): + subtype_value = None + + if not isinstance(response, ET.Element): + rest_api_response_key = cls._get_rest_key_parts(subtype_key)[-1] + subtype_value = response.get(rest_api_response_key, None) or response.get(subtype_key, None) + else: + subtype_value = xml_key_extractor(subtype_key, cls._attribute_map[subtype_key], response) + if subtype_value: + # Try to match base class. Can be class name only + # (bug to fix in Autorest to support x-ms-discriminator-name) + if cls.__name__ == subtype_value: + return cls + flatten_mapping_type = cls._flatten_subtype(subtype_key, objects) + try: + return objects[flatten_mapping_type[subtype_value]] # type: ignore + except KeyError: + _LOGGER.warning( + "Subtype value %s has no mapping, use base class %s.", + subtype_value, + cls.__name__, + ) + break + else: + _LOGGER.warning("Discriminator %s is absent or null, use base class %s.", subtype_key, cls.__name__) + break + return cls + + @classmethod + def _get_rest_key_parts(cls, attr_key): + """Get the RestAPI key of this attr, split it and decode part + :param str attr_key: Attribute key must be in attribute_map. + :returns: A list of RestAPI part + :rtype: list + """ + rest_split_key = _FLATTEN.split(cls._attribute_map[attr_key]["key"]) + return [_decode_attribute_map_key(key_part) for key_part in rest_split_key] + + +def _decode_attribute_map_key(key): + """This decode a key in an _attribute_map to the actual key we want to look at + inside the received data. + + :param str key: A key string from the generated code + :returns: The decoded key + :rtype: str + """ + return key.replace("\\.", ".") + + +class Serializer: # pylint: disable=too-many-public-methods + """Request object model serializer.""" + + basic_types = {str: "str", int: "int", bool: "bool", float: "float"} + + _xml_basic_types_serializers = {"bool": lambda x: str(x).lower()} + days = {0: "Mon", 1: "Tue", 2: "Wed", 3: "Thu", 4: "Fri", 5: "Sat", 6: "Sun"} + months = { + 1: "Jan", + 2: "Feb", + 3: "Mar", + 4: "Apr", + 5: "May", + 6: "Jun", + 7: "Jul", + 8: "Aug", + 9: "Sep", + 10: "Oct", + 11: "Nov", + 12: "Dec", + } + validation = { + "min_length": lambda x, y: len(x) < y, + "max_length": lambda x, y: len(x) > y, + "minimum": lambda x, y: x < y, + "maximum": lambda x, y: x > y, + "minimum_ex": lambda x, y: x <= y, + "maximum_ex": lambda x, y: x >= y, + "min_items": lambda x, y: len(x) < y, + "max_items": lambda x, y: len(x) > y, + "pattern": lambda x, y: not re.match(y, x, re.UNICODE), + "unique": lambda x, y: len(x) != len(set(x)), + "multiple": lambda x, y: x % y != 0, + } + + def __init__(self, classes: Optional[Mapping[str, type]] = None) -> None: + self.serialize_type = { + "iso-8601": Serializer.serialize_iso, + "rfc-1123": Serializer.serialize_rfc, + "unix-time": Serializer.serialize_unix, + "duration": Serializer.serialize_duration, + "date": Serializer.serialize_date, + "time": Serializer.serialize_time, + "decimal": Serializer.serialize_decimal, + "long": Serializer.serialize_long, + "bytearray": Serializer.serialize_bytearray, + "base64": Serializer.serialize_base64, + "object": self.serialize_object, + "[]": self.serialize_iter, + "{}": self.serialize_dict, + } + self.dependencies: Dict[str, type] = dict(classes) if classes else {} + self.key_transformer = full_restapi_key_transformer + self.client_side_validation = True + + def _serialize( # pylint: disable=too-many-nested-blocks, too-many-branches, too-many-statements, too-many-locals + self, target_obj, data_type=None, **kwargs + ): + """Serialize data into a string according to type. + + :param object target_obj: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str, dict + :raises SerializationError: if serialization fails. + :returns: The serialized data. + """ + key_transformer = kwargs.get("key_transformer", self.key_transformer) + keep_readonly = kwargs.get("keep_readonly", False) + if target_obj is None: + return None + + attr_name = None + class_name = target_obj.__class__.__name__ + + if data_type: + return self.serialize_data(target_obj, data_type, **kwargs) + + if not hasattr(target_obj, "_attribute_map"): + data_type = type(target_obj).__name__ + if data_type in self.basic_types.values(): + return self.serialize_data(target_obj, data_type, **kwargs) + + # Force "is_xml" kwargs if we detect a XML model + try: + is_xml_model_serialization = kwargs["is_xml"] + except KeyError: + is_xml_model_serialization = kwargs.setdefault("is_xml", target_obj.is_xml_model()) + + serialized = {} + if is_xml_model_serialization: + serialized = target_obj._create_xml_node() # pylint: disable=protected-access + try: + attributes = target_obj._attribute_map # pylint: disable=protected-access + for attr, attr_desc in attributes.items(): + attr_name = attr + if not keep_readonly and target_obj._validation.get( # pylint: disable=protected-access + attr_name, {} + ).get("readonly", False): + continue + + if attr_name == "additional_properties" and attr_desc["key"] == "": + if target_obj.additional_properties is not None: + serialized.update(target_obj.additional_properties) + continue + try: + + orig_attr = getattr(target_obj, attr) + if is_xml_model_serialization: + pass # Don't provide "transformer" for XML for now. Keep "orig_attr" + else: # JSON + keys, orig_attr = key_transformer(attr, attr_desc.copy(), orig_attr) + keys = keys if isinstance(keys, list) else [keys] + + kwargs["serialization_ctxt"] = attr_desc + new_attr = self.serialize_data(orig_attr, attr_desc["type"], **kwargs) + + if is_xml_model_serialization: + xml_desc = attr_desc.get("xml", {}) + xml_name = xml_desc.get("name", attr_desc["key"]) + xml_prefix = xml_desc.get("prefix", None) + xml_ns = xml_desc.get("ns", None) + if xml_desc.get("attr", False): + if xml_ns: + ET.register_namespace(xml_prefix, xml_ns) + xml_name = "{{{}}}{}".format(xml_ns, xml_name) + serialized.set(xml_name, new_attr) # type: ignore + continue + if xml_desc.get("text", False): + serialized.text = new_attr # type: ignore + continue + if isinstance(new_attr, list): + serialized.extend(new_attr) # type: ignore + elif isinstance(new_attr, ET.Element): + # If the down XML has no XML/Name, + # we MUST replace the tag with the local tag. But keeping the namespaces. + if "name" not in getattr(orig_attr, "_xml_map", {}): + splitted_tag = new_attr.tag.split("}") + if len(splitted_tag) == 2: # Namespace + new_attr.tag = "}".join([splitted_tag[0], xml_name]) + else: + new_attr.tag = xml_name + serialized.append(new_attr) # type: ignore + else: # That's a basic type + # Integrate namespace if necessary + local_node = _create_xml_node(xml_name, xml_prefix, xml_ns) + local_node.text = str(new_attr) + serialized.append(local_node) # type: ignore + else: # JSON + for k in reversed(keys): # type: ignore + new_attr = {k: new_attr} + + _new_attr = new_attr + _serialized = serialized + for k in keys: # type: ignore + if k not in _serialized: + _serialized.update(_new_attr) # type: ignore + _new_attr = _new_attr[k] # type: ignore + _serialized = _serialized[k] + except ValueError as err: + if isinstance(err, SerializationError): + raise + + except (AttributeError, KeyError, TypeError) as err: + msg = "Attribute {} in object {} cannot be serialized.\n{}".format(attr_name, class_name, str(target_obj)) + raise SerializationError(msg) from err + return serialized + + def body(self, data, data_type, **kwargs): + """Serialize data intended for a request body. + + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: dict + :raises SerializationError: if serialization fails. + :raises ValueError: if data is None + :returns: The serialized request body + """ + + # Just in case this is a dict + internal_data_type_str = data_type.strip("[]{}") + internal_data_type = self.dependencies.get(internal_data_type_str, None) + try: + is_xml_model_serialization = kwargs["is_xml"] + except KeyError: + if internal_data_type and issubclass(internal_data_type, Model): + is_xml_model_serialization = kwargs.setdefault("is_xml", internal_data_type.is_xml_model()) + else: + is_xml_model_serialization = False + if internal_data_type and not isinstance(internal_data_type, Enum): + try: + deserializer = Deserializer(self.dependencies) + # Since it's on serialization, it's almost sure that format is not JSON REST + # We're not able to deal with additional properties for now. + deserializer.additional_properties_detection = False + if is_xml_model_serialization: + deserializer.key_extractors = [ # type: ignore + attribute_key_case_insensitive_extractor, + ] + else: + deserializer.key_extractors = [ + rest_key_case_insensitive_extractor, + attribute_key_case_insensitive_extractor, + last_rest_key_case_insensitive_extractor, + ] + data = deserializer._deserialize(data_type, data) # pylint: disable=protected-access + except DeserializationError as err: + raise SerializationError("Unable to build a model: " + str(err)) from err + + return self._serialize(data, data_type, **kwargs) + + def url(self, name, data, data_type, **kwargs): + """Serialize data intended for a URL path. + + :param str name: The name of the URL path parameter. + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str + :returns: The serialized URL path + :raises TypeError: if serialization fails. + :raises ValueError: if data is None + """ + try: + output = self.serialize_data(data, data_type, **kwargs) + if data_type == "bool": + output = json.dumps(output) + + if kwargs.get("skip_quote") is True: + output = str(output) + output = output.replace("{", quote("{")).replace("}", quote("}")) + else: + output = quote(str(output), safe="") + except SerializationError as exc: + raise TypeError("{} must be type {}.".format(name, data_type)) from exc + return output + + def query(self, name, data, data_type, **kwargs): + """Serialize data intended for a URL query. + + :param str name: The name of the query parameter. + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str, list + :raises TypeError: if serialization fails. + :raises ValueError: if data is None + :returns: The serialized query parameter + """ + try: + # Treat the list aside, since we don't want to encode the div separator + if data_type.startswith("["): + internal_data_type = data_type[1:-1] + do_quote = not kwargs.get("skip_quote", False) + return self.serialize_iter(data, internal_data_type, do_quote=do_quote, **kwargs) + + # Not a list, regular serialization + output = self.serialize_data(data, data_type, **kwargs) + if data_type == "bool": + output = json.dumps(output) + if kwargs.get("skip_quote") is True: + output = str(output) + else: + output = quote(str(output), safe="") + except SerializationError as exc: + raise TypeError("{} must be type {}.".format(name, data_type)) from exc + return str(output) + + def header(self, name, data, data_type, **kwargs): + """Serialize data intended for a request header. + + :param str name: The name of the header. + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str + :raises TypeError: if serialization fails. + :raises ValueError: if data is None + :returns: The serialized header + """ + try: + if data_type in ["[str]"]: + data = ["" if d is None else d for d in data] + + output = self.serialize_data(data, data_type, **kwargs) + if data_type == "bool": + output = json.dumps(output) + except SerializationError as exc: + raise TypeError("{} must be type {}.".format(name, data_type)) from exc + return str(output) + + def serialize_data(self, data, data_type, **kwargs): + """Serialize generic data according to supplied data type. + + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :raises AttributeError: if required data is None. + :raises ValueError: if data is None + :raises SerializationError: if serialization fails. + :returns: The serialized data. + :rtype: str, int, float, bool, dict, list + """ + if data is None: + raise ValueError("No value for given attribute") + + try: + if data is CoreNull: + return None + if data_type in self.basic_types.values(): + return self.serialize_basic(data, data_type, **kwargs) + + if data_type in self.serialize_type: + return self.serialize_type[data_type](data, **kwargs) + + # If dependencies is empty, try with current data class + # It has to be a subclass of Enum anyway + enum_type = self.dependencies.get(data_type, data.__class__) + if issubclass(enum_type, Enum): + return Serializer.serialize_enum(data, enum_obj=enum_type) + + iter_type = data_type[0] + data_type[-1] + if iter_type in self.serialize_type: + return self.serialize_type[iter_type](data, data_type[1:-1], **kwargs) + + except (ValueError, TypeError) as err: + msg = "Unable to serialize value: {!r} as type: {!r}." + raise SerializationError(msg.format(data, data_type)) from err + return self._serialize(data, **kwargs) + + @classmethod + def _get_custom_serializers(cls, data_type, **kwargs): # pylint: disable=inconsistent-return-statements + custom_serializer = kwargs.get("basic_types_serializers", {}).get(data_type) + if custom_serializer: + return custom_serializer + if kwargs.get("is_xml", False): + return cls._xml_basic_types_serializers.get(data_type) + + @classmethod + def serialize_basic(cls, data, data_type, **kwargs): + """Serialize basic builting data type. + Serializes objects to str, int, float or bool. + + Possible kwargs: + - basic_types_serializers dict[str, callable] : If set, use the callable as serializer + - is_xml bool : If set, use xml_basic_types_serializers + + :param obj data: Object to be serialized. + :param str data_type: Type of object in the iterable. + :rtype: str, int, float, bool + :return: serialized object + """ + custom_serializer = cls._get_custom_serializers(data_type, **kwargs) + if custom_serializer: + return custom_serializer(data) + if data_type == "str": + return cls.serialize_unicode(data) + return eval(data_type)(data) # nosec # pylint: disable=eval-used + + @classmethod + def serialize_unicode(cls, data): + """Special handling for serializing unicode strings in Py2. + Encode to UTF-8 if unicode, otherwise handle as a str. + + :param str data: Object to be serialized. + :rtype: str + :return: serialized object + """ + try: # If I received an enum, return its value + return data.value + except AttributeError: + pass + + try: + if isinstance(data, unicode): # type: ignore + # Don't change it, JSON and XML ElementTree are totally able + # to serialize correctly u'' strings + return data + except NameError: + return str(data) + return str(data) + + def serialize_iter(self, data, iter_type, div=None, **kwargs): + """Serialize iterable. + + Supported kwargs: + - serialization_ctxt dict : The current entry of _attribute_map, or same format. + serialization_ctxt['type'] should be same as data_type. + - is_xml bool : If set, serialize as XML + + :param list data: Object to be serialized. + :param str iter_type: Type of object in the iterable. + :param str div: If set, this str will be used to combine the elements + in the iterable into a combined string. Default is 'None'. + Defaults to False. + :rtype: list, str + :return: serialized iterable + """ + if isinstance(data, str): + raise SerializationError("Refuse str type as a valid iter type.") + + serialization_ctxt = kwargs.get("serialization_ctxt", {}) + is_xml = kwargs.get("is_xml", False) + + serialized = [] + for d in data: + try: + serialized.append(self.serialize_data(d, iter_type, **kwargs)) + except ValueError as err: + if isinstance(err, SerializationError): + raise + serialized.append(None) + + if kwargs.get("do_quote", False): + serialized = ["" if s is None else quote(str(s), safe="") for s in serialized] + + if div: + serialized = ["" if s is None else str(s) for s in serialized] + serialized = div.join(serialized) + + if "xml" in serialization_ctxt or is_xml: + # XML serialization is more complicated + xml_desc = serialization_ctxt.get("xml", {}) + xml_name = xml_desc.get("name") + if not xml_name: + xml_name = serialization_ctxt["key"] + + # Create a wrap node if necessary (use the fact that Element and list have "append") + is_wrapped = xml_desc.get("wrapped", False) + node_name = xml_desc.get("itemsName", xml_name) + if is_wrapped: + final_result = _create_xml_node(xml_name, xml_desc.get("prefix", None), xml_desc.get("ns", None)) + else: + final_result = [] + # All list elements to "local_node" + for el in serialized: + if isinstance(el, ET.Element): + el_node = el + else: + el_node = _create_xml_node(node_name, xml_desc.get("prefix", None), xml_desc.get("ns", None)) + if el is not None: # Otherwise it writes "None" :-p + el_node.text = str(el) + final_result.append(el_node) + return final_result + return serialized + + def serialize_dict(self, attr, dict_type, **kwargs): + """Serialize a dictionary of objects. + + :param dict attr: Object to be serialized. + :param str dict_type: Type of object in the dictionary. + :rtype: dict + :return: serialized dictionary + """ + serialization_ctxt = kwargs.get("serialization_ctxt", {}) + serialized = {} + for key, value in attr.items(): + try: + serialized[self.serialize_unicode(key)] = self.serialize_data(value, dict_type, **kwargs) + except ValueError as err: + if isinstance(err, SerializationError): + raise + serialized[self.serialize_unicode(key)] = None + + if "xml" in serialization_ctxt: + # XML serialization is more complicated + xml_desc = serialization_ctxt["xml"] + xml_name = xml_desc["name"] + + final_result = _create_xml_node(xml_name, xml_desc.get("prefix", None), xml_desc.get("ns", None)) + for key, value in serialized.items(): + ET.SubElement(final_result, key).text = value + return final_result + + return serialized + + def serialize_object(self, attr, **kwargs): # pylint: disable=too-many-return-statements + """Serialize a generic object. + This will be handled as a dictionary. If object passed in is not + a basic type (str, int, float, dict, list) it will simply be + cast to str. + + :param dict attr: Object to be serialized. + :rtype: dict or str + :return: serialized object + """ + if attr is None: + return None + if isinstance(attr, ET.Element): + return attr + obj_type = type(attr) + if obj_type in self.basic_types: + return self.serialize_basic(attr, self.basic_types[obj_type], **kwargs) + if obj_type is _long_type: + return self.serialize_long(attr) + if obj_type is str: + return self.serialize_unicode(attr) + if obj_type is datetime.datetime: + return self.serialize_iso(attr) + if obj_type is datetime.date: + return self.serialize_date(attr) + if obj_type is datetime.time: + return self.serialize_time(attr) + if obj_type is datetime.timedelta: + return self.serialize_duration(attr) + if obj_type is decimal.Decimal: + return self.serialize_decimal(attr) + + # If it's a model or I know this dependency, serialize as a Model + if obj_type in self.dependencies.values() or isinstance(attr, Model): + return self._serialize(attr) + + if obj_type == dict: + serialized = {} + for key, value in attr.items(): + try: + serialized[self.serialize_unicode(key)] = self.serialize_object(value, **kwargs) + except ValueError: + serialized[self.serialize_unicode(key)] = None + return serialized + + if obj_type == list: + serialized = [] + for obj in attr: + try: + serialized.append(self.serialize_object(obj, **kwargs)) + except ValueError: + pass + return serialized + return str(attr) + + @staticmethod + def serialize_enum(attr, enum_obj=None): + try: + result = attr.value + except AttributeError: + result = attr + try: + enum_obj(result) # type: ignore + return result + except ValueError as exc: + for enum_value in enum_obj: # type: ignore + if enum_value.value.lower() == str(attr).lower(): + return enum_value.value + error = "{!r} is not valid value for enum {!r}" + raise SerializationError(error.format(attr, enum_obj)) from exc + + @staticmethod + def serialize_bytearray(attr, **kwargs): # pylint: disable=unused-argument + """Serialize bytearray into base-64 string. + + :param str attr: Object to be serialized. + :rtype: str + :return: serialized base64 + """ + return b64encode(attr).decode() + + @staticmethod + def serialize_base64(attr, **kwargs): # pylint: disable=unused-argument + """Serialize str into base-64 string. + + :param str attr: Object to be serialized. + :rtype: str + :return: serialized base64 + """ + encoded = b64encode(attr).decode("ascii") + return encoded.strip("=").replace("+", "-").replace("/", "_") + + @staticmethod + def serialize_decimal(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Decimal object to float. + + :param decimal attr: Object to be serialized. + :rtype: float + :return: serialized decimal + """ + return float(attr) + + @staticmethod + def serialize_long(attr, **kwargs): # pylint: disable=unused-argument + """Serialize long (Py2) or int (Py3). + + :param int attr: Object to be serialized. + :rtype: int/long + :return: serialized long + """ + return _long_type(attr) + + @staticmethod + def serialize_date(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Date object into ISO-8601 formatted string. + + :param Date attr: Object to be serialized. + :rtype: str + :return: serialized date + """ + if isinstance(attr, str): + attr = isodate.parse_date(attr) + t = "{:04}-{:02}-{:02}".format(attr.year, attr.month, attr.day) + return t + + @staticmethod + def serialize_time(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Time object into ISO-8601 formatted string. + + :param datetime.time attr: Object to be serialized. + :rtype: str + :return: serialized time + """ + if isinstance(attr, str): + attr = isodate.parse_time(attr) + t = "{:02}:{:02}:{:02}".format(attr.hour, attr.minute, attr.second) + if attr.microsecond: + t += ".{:02}".format(attr.microsecond) + return t + + @staticmethod + def serialize_duration(attr, **kwargs): # pylint: disable=unused-argument + """Serialize TimeDelta object into ISO-8601 formatted string. + + :param TimeDelta attr: Object to be serialized. + :rtype: str + :return: serialized duration + """ + if isinstance(attr, str): + attr = isodate.parse_duration(attr) + return isodate.duration_isoformat(attr) + + @staticmethod + def serialize_rfc(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Datetime object into RFC-1123 formatted string. + + :param Datetime attr: Object to be serialized. + :rtype: str + :raises TypeError: if format invalid. + :return: serialized rfc + """ + try: + if not attr.tzinfo: + _LOGGER.warning("Datetime with no tzinfo will be considered UTC.") + utc = attr.utctimetuple() + except AttributeError as exc: + raise TypeError("RFC1123 object must be valid Datetime object.") from exc + + return "{}, {:02} {} {:04} {:02}:{:02}:{:02} GMT".format( + Serializer.days[utc.tm_wday], + utc.tm_mday, + Serializer.months[utc.tm_mon], + utc.tm_year, + utc.tm_hour, + utc.tm_min, + utc.tm_sec, + ) + + @staticmethod + def serialize_iso(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Datetime object into ISO-8601 formatted string. + + :param Datetime attr: Object to be serialized. + :rtype: str + :raises SerializationError: if format invalid. + :return: serialized iso + """ + if isinstance(attr, str): + attr = isodate.parse_datetime(attr) + try: + if not attr.tzinfo: + _LOGGER.warning("Datetime with no tzinfo will be considered UTC.") + utc = attr.utctimetuple() + if utc.tm_year > 9999 or utc.tm_year < 1: + raise OverflowError("Hit max or min date") + + microseconds = str(attr.microsecond).rjust(6, "0").rstrip("0").ljust(3, "0") + if microseconds: + microseconds = "." + microseconds + date = "{:04}-{:02}-{:02}T{:02}:{:02}:{:02}".format( + utc.tm_year, utc.tm_mon, utc.tm_mday, utc.tm_hour, utc.tm_min, utc.tm_sec + ) + return date + microseconds + "Z" + except (ValueError, OverflowError) as err: + msg = "Unable to serialize datetime object." + raise SerializationError(msg) from err + except AttributeError as err: + msg = "ISO-8601 object must be valid Datetime object." + raise TypeError(msg) from err + + @staticmethod + def serialize_unix(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Datetime object into IntTime format. + This is represented as seconds. + + :param Datetime attr: Object to be serialized. + :rtype: int + :raises SerializationError: if format invalid + :return: serialied unix + """ + if isinstance(attr, int): + return attr + try: + if not attr.tzinfo: + _LOGGER.warning("Datetime with no tzinfo will be considered UTC.") + return int(calendar.timegm(attr.utctimetuple())) + except AttributeError as exc: + raise TypeError("Unix time object must be valid Datetime object.") from exc + + +def rest_key_extractor(attr, attr_desc, data): # pylint: disable=unused-argument + key = attr_desc["key"] + working_data = data + + while "." in key: + # Need the cast, as for some reasons "split" is typed as list[str | Any] + dict_keys = cast(List[str], _FLATTEN.split(key)) + if len(dict_keys) == 1: + key = _decode_attribute_map_key(dict_keys[0]) + break + working_key = _decode_attribute_map_key(dict_keys[0]) + working_data = working_data.get(working_key, data) + if working_data is None: + # If at any point while following flatten JSON path see None, it means + # that all properties under are None as well + return None + key = ".".join(dict_keys[1:]) + + return working_data.get(key) + + +def rest_key_case_insensitive_extractor( # pylint: disable=unused-argument, inconsistent-return-statements + attr, attr_desc, data +): + key = attr_desc["key"] + working_data = data + + while "." in key: + dict_keys = _FLATTEN.split(key) + if len(dict_keys) == 1: + key = _decode_attribute_map_key(dict_keys[0]) + break + working_key = _decode_attribute_map_key(dict_keys[0]) + working_data = attribute_key_case_insensitive_extractor(working_key, None, working_data) + if working_data is None: + # If at any point while following flatten JSON path see None, it means + # that all properties under are None as well + return None + key = ".".join(dict_keys[1:]) + + if working_data: + return attribute_key_case_insensitive_extractor(key, None, working_data) + + +def last_rest_key_extractor(attr, attr_desc, data): # pylint: disable=unused-argument + """Extract the attribute in "data" based on the last part of the JSON path key. + + :param str attr: The attribute to extract + :param dict attr_desc: The attribute description + :param dict data: The data to extract from + :rtype: object + :returns: The extracted attribute + """ + key = attr_desc["key"] + dict_keys = _FLATTEN.split(key) + return attribute_key_extractor(dict_keys[-1], None, data) + + +def last_rest_key_case_insensitive_extractor(attr, attr_desc, data): # pylint: disable=unused-argument + """Extract the attribute in "data" based on the last part of the JSON path key. + + This is the case insensitive version of "last_rest_key_extractor" + :param str attr: The attribute to extract + :param dict attr_desc: The attribute description + :param dict data: The data to extract from + :rtype: object + :returns: The extracted attribute + """ + key = attr_desc["key"] + dict_keys = _FLATTEN.split(key) + return attribute_key_case_insensitive_extractor(dict_keys[-1], None, data) + + +def attribute_key_extractor(attr, _, data): + return data.get(attr) + + +def attribute_key_case_insensitive_extractor(attr, _, data): + found_key = None + lower_attr = attr.lower() + for key in data: + if lower_attr == key.lower(): + found_key = key + break + + return data.get(found_key) + + +def _extract_name_from_internal_type(internal_type): + """Given an internal type XML description, extract correct XML name with namespace. + + :param dict internal_type: An model type + :rtype: tuple + :returns: A tuple XML name + namespace dict + """ + internal_type_xml_map = getattr(internal_type, "_xml_map", {}) + xml_name = internal_type_xml_map.get("name", internal_type.__name__) + xml_ns = internal_type_xml_map.get("ns", None) + if xml_ns: + xml_name = "{{{}}}{}".format(xml_ns, xml_name) + return xml_name + + +def xml_key_extractor(attr, attr_desc, data): # pylint: disable=unused-argument,too-many-return-statements + if isinstance(data, dict): + return None + + # Test if this model is XML ready first + if not isinstance(data, ET.Element): + return None + + xml_desc = attr_desc.get("xml", {}) + xml_name = xml_desc.get("name", attr_desc["key"]) + + # Look for a children + is_iter_type = attr_desc["type"].startswith("[") + is_wrapped = xml_desc.get("wrapped", False) + internal_type = attr_desc.get("internalType", None) + internal_type_xml_map = getattr(internal_type, "_xml_map", {}) + + # Integrate namespace if necessary + xml_ns = xml_desc.get("ns", internal_type_xml_map.get("ns", None)) + if xml_ns: + xml_name = "{{{}}}{}".format(xml_ns, xml_name) + + # If it's an attribute, that's simple + if xml_desc.get("attr", False): + return data.get(xml_name) + + # If it's x-ms-text, that's simple too + if xml_desc.get("text", False): + return data.text + + # Scenario where I take the local name: + # - Wrapped node + # - Internal type is an enum (considered basic types) + # - Internal type has no XML/Name node + if is_wrapped or (internal_type and (issubclass(internal_type, Enum) or "name" not in internal_type_xml_map)): + children = data.findall(xml_name) + # If internal type has a local name and it's not a list, I use that name + elif not is_iter_type and internal_type and "name" in internal_type_xml_map: + xml_name = _extract_name_from_internal_type(internal_type) + children = data.findall(xml_name) + # That's an array + else: + if internal_type: # Complex type, ignore itemsName and use the complex type name + items_name = _extract_name_from_internal_type(internal_type) + else: + items_name = xml_desc.get("itemsName", xml_name) + children = data.findall(items_name) + + if len(children) == 0: + if is_iter_type: + if is_wrapped: + return None # is_wrapped no node, we want None + return [] # not wrapped, assume empty list + return None # Assume it's not there, maybe an optional node. + + # If is_iter_type and not wrapped, return all found children + if is_iter_type: + if not is_wrapped: + return children + # Iter and wrapped, should have found one node only (the wrap one) + if len(children) != 1: + raise DeserializationError( + "Tried to deserialize an array not wrapped, and found several nodes '{}'. Maybe you should declare this array as wrapped?".format( + xml_name + ) + ) + return list(children[0]) # Might be empty list and that's ok. + + # Here it's not a itertype, we should have found one element only or empty + if len(children) > 1: + raise DeserializationError("Find several XML '{}' where it was not expected".format(xml_name)) + return children[0] + + +class Deserializer: + """Response object model deserializer. + + :param dict classes: Class type dictionary for deserializing complex types. + :ivar list key_extractors: Ordered list of extractors to be used by this deserializer. + """ + + basic_types = {str: "str", int: "int", bool: "bool", float: "float"} + + valid_date = re.compile(r"\d{4}[-]\d{2}[-]\d{2}T\d{2}:\d{2}:\d{2}\.?\d*Z?[-+]?[\d{2}]?:?[\d{2}]?") + + def __init__(self, classes: Optional[Mapping[str, type]] = None) -> None: + self.deserialize_type = { + "iso-8601": Deserializer.deserialize_iso, + "rfc-1123": Deserializer.deserialize_rfc, + "unix-time": Deserializer.deserialize_unix, + "duration": Deserializer.deserialize_duration, + "date": Deserializer.deserialize_date, + "time": Deserializer.deserialize_time, + "decimal": Deserializer.deserialize_decimal, + "long": Deserializer.deserialize_long, + "bytearray": Deserializer.deserialize_bytearray, + "base64": Deserializer.deserialize_base64, + "object": self.deserialize_object, + "[]": self.deserialize_iter, + "{}": self.deserialize_dict, + } + self.deserialize_expected_types = { + "duration": (isodate.Duration, datetime.timedelta), + "iso-8601": (datetime.datetime), + } + self.dependencies: Dict[str, type] = dict(classes) if classes else {} + self.key_extractors = [rest_key_extractor, xml_key_extractor] + # Additional properties only works if the "rest_key_extractor" is used to + # extract the keys. Making it to work whatever the key extractor is too much + # complicated, with no real scenario for now. + # So adding a flag to disable additional properties detection. This flag should be + # used if your expect the deserialization to NOT come from a JSON REST syntax. + # Otherwise, result are unexpected + self.additional_properties_detection = True + + def __call__(self, target_obj, response_data, content_type=None): + """Call the deserializer to process a REST response. + + :param str target_obj: Target data type to deserialize to. + :param requests.Response response_data: REST response object. + :param str content_type: Swagger "produces" if available. + :raises DeserializationError: if deserialization fails. + :return: Deserialized object. + :rtype: object + """ + data = self._unpack_content(response_data, content_type) + return self._deserialize(target_obj, data) + + def _deserialize(self, target_obj, data): # pylint: disable=inconsistent-return-statements + """Call the deserializer on a model. + + Data needs to be already deserialized as JSON or XML ElementTree + + :param str target_obj: Target data type to deserialize to. + :param object data: Object to deserialize. + :raises DeserializationError: if deserialization fails. + :return: Deserialized object. + :rtype: object + """ + # This is already a model, go recursive just in case + if hasattr(data, "_attribute_map"): + constants = [name for name, config in getattr(data, "_validation", {}).items() if config.get("constant")] + try: + for attr, mapconfig in data._attribute_map.items(): # pylint: disable=protected-access + if attr in constants: + continue + value = getattr(data, attr) + if value is None: + continue + local_type = mapconfig["type"] + internal_data_type = local_type.strip("[]{}") + if internal_data_type not in self.dependencies or isinstance(internal_data_type, Enum): + continue + setattr(data, attr, self._deserialize(local_type, value)) + return data + except AttributeError: + return + + response, class_name = self._classify_target(target_obj, data) + + if isinstance(response, str): + return self.deserialize_data(data, response) + if isinstance(response, type) and issubclass(response, Enum): + return self.deserialize_enum(data, response) + + if data is None or data is CoreNull: + return data + try: + attributes = response._attribute_map # type: ignore # pylint: disable=protected-access + d_attrs = {} + for attr, attr_desc in attributes.items(): + # Check empty string. If it's not empty, someone has a real "additionalProperties"... + if attr == "additional_properties" and attr_desc["key"] == "": + continue + raw_value = None + # Enhance attr_desc with some dynamic data + attr_desc = attr_desc.copy() # Do a copy, do not change the real one + internal_data_type = attr_desc["type"].strip("[]{}") + if internal_data_type in self.dependencies: + attr_desc["internalType"] = self.dependencies[internal_data_type] + + for key_extractor in self.key_extractors: + found_value = key_extractor(attr, attr_desc, data) + if found_value is not None: + if raw_value is not None and raw_value != found_value: + msg = ( + "Ignoring extracted value '%s' from %s for key '%s'" + " (duplicate extraction, follow extractors order)" + ) + _LOGGER.warning(msg, found_value, key_extractor, attr) + continue + raw_value = found_value + + value = self.deserialize_data(raw_value, attr_desc["type"]) + d_attrs[attr] = value + except (AttributeError, TypeError, KeyError) as err: + msg = "Unable to deserialize to object: " + class_name # type: ignore + raise DeserializationError(msg) from err + additional_properties = self._build_additional_properties(attributes, data) + return self._instantiate_model(response, d_attrs, additional_properties) + + def _build_additional_properties(self, attribute_map, data): + if not self.additional_properties_detection: + return None + if "additional_properties" in attribute_map and attribute_map.get("additional_properties", {}).get("key") != "": + # Check empty string. If it's not empty, someone has a real "additionalProperties" + return None + if isinstance(data, ET.Element): + data = {el.tag: el.text for el in data} + + known_keys = { + _decode_attribute_map_key(_FLATTEN.split(desc["key"])[0]) + for desc in attribute_map.values() + if desc["key"] != "" + } + present_keys = set(data.keys()) + missing_keys = present_keys - known_keys + return {key: data[key] for key in missing_keys} + + def _classify_target(self, target, data): + """Check to see whether the deserialization target object can + be classified into a subclass. + Once classification has been determined, initialize object. + + :param str target: The target object type to deserialize to. + :param str/dict data: The response data to deserialize. + :return: The classified target object and its class name. + :rtype: tuple + """ + if target is None: + return None, None + + if isinstance(target, str): + try: + target = self.dependencies[target] + except KeyError: + return target, target + + try: + target = target._classify(data, self.dependencies) # type: ignore # pylint: disable=protected-access + except AttributeError: + pass # Target is not a Model, no classify + return target, target.__class__.__name__ # type: ignore + + def failsafe_deserialize(self, target_obj, data, content_type=None): + """Ignores any errors encountered in deserialization, + and falls back to not deserializing the object. Recommended + for use in error deserialization, as we want to return the + HttpResponseError to users, and not have them deal with + a deserialization error. + + :param str target_obj: The target object type to deserialize to. + :param str/dict data: The response data to deserialize. + :param str content_type: Swagger "produces" if available. + :return: Deserialized object. + :rtype: object + """ + try: + return self(target_obj, data, content_type=content_type) + except: # pylint: disable=bare-except + _LOGGER.debug( + "Ran into a deserialization error. Ignoring since this is failsafe deserialization", exc_info=True + ) + return None + + @staticmethod + def _unpack_content(raw_data, content_type=None): + """Extract the correct structure for deserialization. + + If raw_data is a PipelineResponse, try to extract the result of RawDeserializer. + if we can't, raise. Your Pipeline should have a RawDeserializer. + + If not a pipeline response and raw_data is bytes or string, use content-type + to decode it. If no content-type, try JSON. + + If raw_data is something else, bypass all logic and return it directly. + + :param obj raw_data: Data to be processed. + :param str content_type: How to parse if raw_data is a string/bytes. + :raises JSONDecodeError: If JSON is requested and parsing is impossible. + :raises UnicodeDecodeError: If bytes is not UTF8 + :rtype: object + :return: Unpacked content. + """ + # Assume this is enough to detect a Pipeline Response without importing it + context = getattr(raw_data, "context", {}) + if context: + if RawDeserializer.CONTEXT_NAME in context: + return context[RawDeserializer.CONTEXT_NAME] + raise ValueError("This pipeline didn't have the RawDeserializer policy; can't deserialize") + + # Assume this is enough to recognize universal_http.ClientResponse without importing it + if hasattr(raw_data, "body"): + return RawDeserializer.deserialize_from_http_generics(raw_data.text(), raw_data.headers) + + # Assume this enough to recognize requests.Response without importing it. + if hasattr(raw_data, "_content_consumed"): + return RawDeserializer.deserialize_from_http_generics(raw_data.text, raw_data.headers) + + if isinstance(raw_data, (str, bytes)) or hasattr(raw_data, "read"): + return RawDeserializer.deserialize_from_text(raw_data, content_type) # type: ignore + return raw_data + + def _instantiate_model(self, response, attrs, additional_properties=None): + """Instantiate a response model passing in deserialized args. + + :param Response response: The response model class. + :param dict attrs: The deserialized response attributes. + :param dict additional_properties: Additional properties to be set. + :rtype: Response + :return: The instantiated response model. + """ + if callable(response): + subtype = getattr(response, "_subtype_map", {}) + try: + readonly = [ + k + for k, v in response._validation.items() # pylint: disable=protected-access # type: ignore + if v.get("readonly") + ] + const = [ + k + for k, v in response._validation.items() # pylint: disable=protected-access # type: ignore + if v.get("constant") + ] + kwargs = {k: v for k, v in attrs.items() if k not in subtype and k not in readonly + const} + response_obj = response(**kwargs) + for attr in readonly: + setattr(response_obj, attr, attrs.get(attr)) + if additional_properties: + response_obj.additional_properties = additional_properties # type: ignore + return response_obj + except TypeError as err: + msg = "Unable to deserialize {} into model {}. ".format(kwargs, response) # type: ignore + raise DeserializationError(msg + str(err)) from err + else: + try: + for attr, value in attrs.items(): + setattr(response, attr, value) + return response + except Exception as exp: + msg = "Unable to populate response model. " + msg += "Type: {}, Error: {}".format(type(response), exp) + raise DeserializationError(msg) from exp + + def deserialize_data(self, data, data_type): # pylint: disable=too-many-return-statements + """Process data for deserialization according to data type. + + :param str data: The response string to be deserialized. + :param str data_type: The type to deserialize to. + :raises DeserializationError: if deserialization fails. + :return: Deserialized object. + :rtype: object + """ + if data is None: + return data + + try: + if not data_type: + return data + if data_type in self.basic_types.values(): + return self.deserialize_basic(data, data_type) + if data_type in self.deserialize_type: + if isinstance(data, self.deserialize_expected_types.get(data_type, tuple())): + return data + + is_a_text_parsing_type = lambda x: x not in [ # pylint: disable=unnecessary-lambda-assignment + "object", + "[]", + r"{}", + ] + if isinstance(data, ET.Element) and is_a_text_parsing_type(data_type) and not data.text: + return None + data_val = self.deserialize_type[data_type](data) + return data_val + + iter_type = data_type[0] + data_type[-1] + if iter_type in self.deserialize_type: + return self.deserialize_type[iter_type](data, data_type[1:-1]) + + obj_type = self.dependencies[data_type] + if issubclass(obj_type, Enum): + if isinstance(data, ET.Element): + data = data.text + return self.deserialize_enum(data, obj_type) + + except (ValueError, TypeError, AttributeError) as err: + msg = "Unable to deserialize response data." + msg += " Data: {}, {}".format(data, data_type) + raise DeserializationError(msg) from err + return self._deserialize(obj_type, data) + + def deserialize_iter(self, attr, iter_type): + """Deserialize an iterable. + + :param list attr: Iterable to be deserialized. + :param str iter_type: The type of object in the iterable. + :return: Deserialized iterable. + :rtype: list + """ + if attr is None: + return None + if isinstance(attr, ET.Element): # If I receive an element here, get the children + attr = list(attr) + if not isinstance(attr, (list, set)): + raise DeserializationError("Cannot deserialize as [{}] an object of type {}".format(iter_type, type(attr))) + return [self.deserialize_data(a, iter_type) for a in attr] + + def deserialize_dict(self, attr, dict_type): + """Deserialize a dictionary. + + :param dict/list attr: Dictionary to be deserialized. Also accepts + a list of key, value pairs. + :param str dict_type: The object type of the items in the dictionary. + :return: Deserialized dictionary. + :rtype: dict + """ + if isinstance(attr, list): + return {x["key"]: self.deserialize_data(x["value"], dict_type) for x in attr} + + if isinstance(attr, ET.Element): + # Transform value into {"Key": "value"} + attr = {el.tag: el.text for el in attr} + return {k: self.deserialize_data(v, dict_type) for k, v in attr.items()} + + def deserialize_object(self, attr, **kwargs): # pylint: disable=too-many-return-statements + """Deserialize a generic object. + This will be handled as a dictionary. + + :param dict attr: Dictionary to be deserialized. + :return: Deserialized object. + :rtype: dict + :raises TypeError: if non-builtin datatype encountered. + """ + if attr is None: + return None + if isinstance(attr, ET.Element): + # Do no recurse on XML, just return the tree as-is + return attr + if isinstance(attr, str): + return self.deserialize_basic(attr, "str") + obj_type = type(attr) + if obj_type in self.basic_types: + return self.deserialize_basic(attr, self.basic_types[obj_type]) + if obj_type is _long_type: + return self.deserialize_long(attr) + + if obj_type == dict: + deserialized = {} + for key, value in attr.items(): + try: + deserialized[key] = self.deserialize_object(value, **kwargs) + except ValueError: + deserialized[key] = None + return deserialized + + if obj_type == list: + deserialized = [] + for obj in attr: + try: + deserialized.append(self.deserialize_object(obj, **kwargs)) + except ValueError: + pass + return deserialized + + error = "Cannot deserialize generic object with type: " + raise TypeError(error + str(obj_type)) + + def deserialize_basic(self, attr, data_type): # pylint: disable=too-many-return-statements + """Deserialize basic builtin data type from string. + Will attempt to convert to str, int, float and bool. + This function will also accept '1', '0', 'true' and 'false' as + valid bool values. + + :param str attr: response string to be deserialized. + :param str data_type: deserialization data type. + :return: Deserialized basic type. + :rtype: str, int, float or bool + :raises TypeError: if string format is not valid. + """ + # If we're here, data is supposed to be a basic type. + # If it's still an XML node, take the text + if isinstance(attr, ET.Element): + attr = attr.text + if not attr: + if data_type == "str": + # None or '', node is empty string. + return "" + # None or '', node with a strong type is None. + # Don't try to model "empty bool" or "empty int" + return None + + if data_type == "bool": + if attr in [True, False, 1, 0]: + return bool(attr) + if isinstance(attr, str): + if attr.lower() in ["true", "1"]: + return True + if attr.lower() in ["false", "0"]: + return False + raise TypeError("Invalid boolean value: {}".format(attr)) + + if data_type == "str": + return self.deserialize_unicode(attr) + return eval(data_type)(attr) # nosec # pylint: disable=eval-used + + @staticmethod + def deserialize_unicode(data): + """Preserve unicode objects in Python 2, otherwise return data + as a string. + + :param str data: response string to be deserialized. + :return: Deserialized string. + :rtype: str or unicode + """ + # We might be here because we have an enum modeled as string, + # and we try to deserialize a partial dict with enum inside + if isinstance(data, Enum): + return data + + # Consider this is real string + try: + if isinstance(data, unicode): # type: ignore + return data + except NameError: + return str(data) + return str(data) + + @staticmethod + def deserialize_enum(data, enum_obj): + """Deserialize string into enum object. + + If the string is not a valid enum value it will be returned as-is + and a warning will be logged. + + :param str data: Response string to be deserialized. If this value is + None or invalid it will be returned as-is. + :param Enum enum_obj: Enum object to deserialize to. + :return: Deserialized enum object. + :rtype: Enum + """ + if isinstance(data, enum_obj) or data is None: + return data + if isinstance(data, Enum): + data = data.value + if isinstance(data, int): + # Workaround. We might consider remove it in the future. + try: + return list(enum_obj.__members__.values())[data] + except IndexError as exc: + error = "{!r} is not a valid index for enum {!r}" + raise DeserializationError(error.format(data, enum_obj)) from exc + try: + return enum_obj(str(data)) + except ValueError: + for enum_value in enum_obj: + if enum_value.value.lower() == str(data).lower(): + return enum_value + # We don't fail anymore for unknown value, we deserialize as a string + _LOGGER.warning("Deserializer is not able to find %s as valid enum in %s", data, enum_obj) + return Deserializer.deserialize_unicode(data) + + @staticmethod + def deserialize_bytearray(attr): + """Deserialize string into bytearray. + + :param str attr: response string to be deserialized. + :return: Deserialized bytearray + :rtype: bytearray + :raises TypeError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + return bytearray(b64decode(attr)) # type: ignore + + @staticmethod + def deserialize_base64(attr): + """Deserialize base64 encoded string into string. + + :param str attr: response string to be deserialized. + :return: Deserialized base64 string + :rtype: bytearray + :raises TypeError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + padding = "=" * (3 - (len(attr) + 3) % 4) # type: ignore + attr = attr + padding # type: ignore + encoded = attr.replace("-", "+").replace("_", "/") + return b64decode(encoded) + + @staticmethod + def deserialize_decimal(attr): + """Deserialize string into Decimal object. + + :param str attr: response string to be deserialized. + :return: Deserialized decimal + :raises DeserializationError: if string format invalid. + :rtype: decimal + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + return decimal.Decimal(str(attr)) # type: ignore + except decimal.DecimalException as err: + msg = "Invalid decimal {}".format(attr) + raise DeserializationError(msg) from err + + @staticmethod + def deserialize_long(attr): + """Deserialize string into long (Py2) or int (Py3). + + :param str attr: response string to be deserialized. + :return: Deserialized int + :rtype: long or int + :raises ValueError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + return _long_type(attr) # type: ignore + + @staticmethod + def deserialize_duration(attr): + """Deserialize ISO-8601 formatted string into TimeDelta object. + + :param str attr: response string to be deserialized. + :return: Deserialized duration + :rtype: TimeDelta + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + duration = isodate.parse_duration(attr) + except (ValueError, OverflowError, AttributeError) as err: + msg = "Cannot deserialize duration object." + raise DeserializationError(msg) from err + return duration + + @staticmethod + def deserialize_date(attr): + """Deserialize ISO-8601 formatted string into Date object. + + :param str attr: response string to be deserialized. + :return: Deserialized date + :rtype: Date + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + if re.search(r"[^\W\d_]", attr, re.I + re.U): # type: ignore + raise DeserializationError("Date must have only digits and -. Received: %s" % attr) + # This must NOT use defaultmonth/defaultday. Using None ensure this raises an exception. + return isodate.parse_date(attr, defaultmonth=0, defaultday=0) + + @staticmethod + def deserialize_time(attr): + """Deserialize ISO-8601 formatted string into time object. + + :param str attr: response string to be deserialized. + :return: Deserialized time + :rtype: datetime.time + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + if re.search(r"[^\W\d_]", attr, re.I + re.U): # type: ignore + raise DeserializationError("Date must have only digits and -. Received: %s" % attr) + return isodate.parse_time(attr) + + @staticmethod + def deserialize_rfc(attr): + """Deserialize RFC-1123 formatted string into Datetime object. + + :param str attr: response string to be deserialized. + :return: Deserialized RFC datetime + :rtype: Datetime + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + parsed_date = email.utils.parsedate_tz(attr) # type: ignore + date_obj = datetime.datetime( + *parsed_date[:6], tzinfo=datetime.timezone(datetime.timedelta(minutes=(parsed_date[9] or 0) / 60)) + ) + if not date_obj.tzinfo: + date_obj = date_obj.astimezone(tz=TZ_UTC) + except ValueError as err: + msg = "Cannot deserialize to rfc datetime object." + raise DeserializationError(msg) from err + return date_obj + + @staticmethod + def deserialize_iso(attr): + """Deserialize ISO-8601 formatted string into Datetime object. + + :param str attr: response string to be deserialized. + :return: Deserialized ISO datetime + :rtype: Datetime + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + attr = attr.upper() # type: ignore + match = Deserializer.valid_date.match(attr) + if not match: + raise ValueError("Invalid datetime string: " + attr) + + check_decimal = attr.split(".") + if len(check_decimal) > 1: + decimal_str = "" + for digit in check_decimal[1]: + if digit.isdigit(): + decimal_str += digit + else: + break + if len(decimal_str) > 6: + attr = attr.replace(decimal_str, decimal_str[0:6]) + + date_obj = isodate.parse_datetime(attr) + test_utc = date_obj.utctimetuple() + if test_utc.tm_year > 9999 or test_utc.tm_year < 1: + raise OverflowError("Hit max or min date") + except (ValueError, OverflowError, AttributeError) as err: + msg = "Cannot deserialize datetime object." + raise DeserializationError(msg) from err + return date_obj + + @staticmethod + def deserialize_unix(attr): + """Serialize Datetime object into IntTime format. + This is represented as seconds. + + :param int attr: Object to be serialized. + :return: Deserialized datetime + :rtype: Datetime + :raises DeserializationError: if format invalid + """ + if isinstance(attr, ET.Element): + attr = int(attr.text) # type: ignore + try: + attr = int(attr) + date_obj = datetime.datetime.fromtimestamp(attr, TZ_UTC) + except ValueError as err: + msg = "Cannot deserialize to unix datetime object." + raise DeserializationError(msg) from err + return date_obj diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyIntegerVersionTolerant/bodyintegerversiontolerant/aio/_client.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyIntegerVersionTolerant/bodyintegerversiontolerant/aio/_client.py index 168e7d8e634..d6992a5fdbf 100644 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyIntegerVersionTolerant/bodyintegerversiontolerant/aio/_client.py +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyIntegerVersionTolerant/bodyintegerversiontolerant/aio/_client.py @@ -14,7 +14,7 @@ from azure.core.pipeline import policies from azure.core.rest import AsyncHttpResponse, HttpRequest -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import AutoRestIntegerTestServiceConfiguration from .operations import IntOperations diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyIntegerVersionTolerant/bodyintegerversiontolerant/aio/operations/_operations.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyIntegerVersionTolerant/bodyintegerversiontolerant/aio/operations/_operations.py index 636175d3036..1c79f0406f6 100644 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyIntegerVersionTolerant/bodyintegerversiontolerant/aio/operations/_operations.py +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyIntegerVersionTolerant/bodyintegerversiontolerant/aio/operations/_operations.py @@ -23,7 +23,7 @@ from azure.core.tracing.decorator_async import distributed_trace_async from azure.core.utils import case_insensitive_dict -from ..._serialization import Deserializer, Serializer +from ..._utils.serialization import Deserializer, Serializer from ...operations._operations import ( build_int_operations_get_invalid_request, build_int_operations_get_invalid_unix_time_request, diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyIntegerVersionTolerant/bodyintegerversiontolerant/operations/_operations.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyIntegerVersionTolerant/bodyintegerversiontolerant/operations/_operations.py index f73a30e33f5..d6968ca5391 100644 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyIntegerVersionTolerant/bodyintegerversiontolerant/operations/_operations.py +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyIntegerVersionTolerant/bodyintegerversiontolerant/operations/_operations.py @@ -24,7 +24,7 @@ from azure.core.utils import case_insensitive_dict from .._configuration import AutoRestIntegerTestServiceConfiguration -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyNumberVersionTolerant/bodynumberversiontolerant/_client.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyNumberVersionTolerant/bodynumberversiontolerant/_client.py index 869dd374c6f..2d7ba4bac1d 100644 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyNumberVersionTolerant/bodynumberversiontolerant/_client.py +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyNumberVersionTolerant/bodynumberversiontolerant/_client.py @@ -15,7 +15,7 @@ from azure.core.rest import HttpRequest, HttpResponse from ._configuration import AutoRestNumberTestServiceConfiguration -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer from .operations import NumberOperations diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyNumberVersionTolerant/bodynumberversiontolerant/_utils/__init__.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyNumberVersionTolerant/bodynumberversiontolerant/_utils/__init__.py new file mode 100644 index 00000000000..0af9b28f660 --- /dev/null +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyNumberVersionTolerant/bodynumberversiontolerant/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyNumberVersionTolerant/bodynumberversiontolerant/_utils/serialization.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyNumberVersionTolerant/bodynumberversiontolerant/_utils/serialization.py new file mode 100644 index 00000000000..f5187701d7b --- /dev/null +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyNumberVersionTolerant/bodynumberversiontolerant/_utils/serialization.py @@ -0,0 +1,2032 @@ +# pylint: disable=line-too-long,useless-suppression,too-many-lines +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +# pyright: reportUnnecessaryTypeIgnoreComment=false + +from base64 import b64decode, b64encode +import calendar +import datetime +import decimal +import email +from enum import Enum +import json +import logging +import re +import sys +import codecs +from typing import ( + Dict, + Any, + cast, + Optional, + Union, + AnyStr, + IO, + Mapping, + Callable, + MutableMapping, + List, +) + +try: + from urllib import quote # type: ignore +except ImportError: + from urllib.parse import quote +import xml.etree.ElementTree as ET + +import isodate # type: ignore +from typing_extensions import Self + +from azure.core.exceptions import DeserializationError, SerializationError +from azure.core.serialization import NULL as CoreNull + +_BOM = codecs.BOM_UTF8.decode(encoding="utf-8") + +JSON = MutableMapping[str, Any] + + +class RawDeserializer: + + # Accept "text" because we're open minded people... + JSON_REGEXP = re.compile(r"^(application|text)/([a-z+.]+\+)?json$") + + # Name used in context + CONTEXT_NAME = "deserialized_data" + + @classmethod + def deserialize_from_text(cls, data: Optional[Union[AnyStr, IO]], content_type: Optional[str] = None) -> Any: + """Decode data according to content-type. + + Accept a stream of data as well, but will be load at once in memory for now. + + If no content-type, will return the string version (not bytes, not stream) + + :param data: Input, could be bytes or stream (will be decoded with UTF8) or text + :type data: str or bytes or IO + :param str content_type: The content type. + :return: The deserialized data. + :rtype: object + """ + if hasattr(data, "read"): + # Assume a stream + data = cast(IO, data).read() + + if isinstance(data, bytes): + data_as_str = data.decode(encoding="utf-8-sig") + else: + # Explain to mypy the correct type. + data_as_str = cast(str, data) + + # Remove Byte Order Mark if present in string + data_as_str = data_as_str.lstrip(_BOM) + + if content_type is None: + return data + + if cls.JSON_REGEXP.match(content_type): + try: + return json.loads(data_as_str) + except ValueError as err: + raise DeserializationError("JSON is invalid: {}".format(err), err) from err + elif "xml" in (content_type or []): + try: + + try: + if isinstance(data, unicode): # type: ignore + # If I'm Python 2.7 and unicode XML will scream if I try a "fromstring" on unicode string + data_as_str = data_as_str.encode(encoding="utf-8") # type: ignore + except NameError: + pass + + return ET.fromstring(data_as_str) # nosec + except ET.ParseError as err: + # It might be because the server has an issue, and returned JSON with + # content-type XML.... + # So let's try a JSON load, and if it's still broken + # let's flow the initial exception + def _json_attemp(data): + try: + return True, json.loads(data) + except ValueError: + return False, None # Don't care about this one + + success, json_result = _json_attemp(data) + if success: + return json_result + # If i'm here, it's not JSON, it's not XML, let's scream + # and raise the last context in this block (the XML exception) + # The function hack is because Py2.7 messes up with exception + # context otherwise. + _LOGGER.critical("Wasn't XML not JSON, failing") + raise DeserializationError("XML is invalid") from err + elif content_type.startswith("text/"): + return data_as_str + raise DeserializationError("Cannot deserialize content-type: {}".format(content_type)) + + @classmethod + def deserialize_from_http_generics(cls, body_bytes: Optional[Union[AnyStr, IO]], headers: Mapping) -> Any: + """Deserialize from HTTP response. + + Use bytes and headers to NOT use any requests/aiohttp or whatever + specific implementation. + Headers will tested for "content-type" + + :param bytes body_bytes: The body of the response. + :param dict headers: The headers of the response. + :returns: The deserialized data. + :rtype: object + """ + # Try to use content-type from headers if available + content_type = None + if "content-type" in headers: + content_type = headers["content-type"].split(";")[0].strip().lower() + # Ouch, this server did not declare what it sent... + # Let's guess it's JSON... + # Also, since Autorest was considering that an empty body was a valid JSON, + # need that test as well.... + else: + content_type = "application/json" + + if body_bytes: + return cls.deserialize_from_text(body_bytes, content_type) + return None + + +_LOGGER = logging.getLogger(__name__) + +try: + _long_type = long # type: ignore +except NameError: + _long_type = int + +TZ_UTC = datetime.timezone.utc + +_FLATTEN = re.compile(r"(? None: + self.additional_properties: Optional[Dict[str, Any]] = {} + for k in kwargs: # pylint: disable=consider-using-dict-items + if k not in self._attribute_map: + _LOGGER.warning("%s is not a known attribute of class %s and will be ignored", k, self.__class__) + elif k in self._validation and self._validation[k].get("readonly", False): + _LOGGER.warning("Readonly attribute %s will be ignored in class %s", k, self.__class__) + else: + setattr(self, k, kwargs[k]) + + def __eq__(self, other: Any) -> bool: + """Compare objects by comparing all attributes. + + :param object other: The object to compare + :returns: True if objects are equal + :rtype: bool + """ + if isinstance(other, self.__class__): + return self.__dict__ == other.__dict__ + return False + + def __ne__(self, other: Any) -> bool: + """Compare objects by comparing all attributes. + + :param object other: The object to compare + :returns: True if objects are not equal + :rtype: bool + """ + return not self.__eq__(other) + + def __str__(self) -> str: + return str(self.__dict__) + + @classmethod + def enable_additional_properties_sending(cls) -> None: + cls._attribute_map["additional_properties"] = {"key": "", "type": "{object}"} + + @classmethod + def is_xml_model(cls) -> bool: + try: + cls._xml_map # type: ignore + except AttributeError: + return False + return True + + @classmethod + def _create_xml_node(cls): + """Create XML node. + + :returns: The XML node + :rtype: xml.etree.ElementTree.Element + """ + try: + xml_map = cls._xml_map # type: ignore + except AttributeError: + xml_map = {} + + return _create_xml_node(xml_map.get("name", cls.__name__), xml_map.get("prefix", None), xml_map.get("ns", None)) + + def serialize(self, keep_readonly: bool = False, **kwargs: Any) -> JSON: + """Return the JSON that would be sent to server from this model. + + This is an alias to `as_dict(full_restapi_key_transformer, keep_readonly=False)`. + + If you want XML serialization, you can pass the kwargs is_xml=True. + + :param bool keep_readonly: If you want to serialize the readonly attributes + :returns: A dict JSON compatible object + :rtype: dict + """ + serializer = Serializer(self._infer_class_models()) + return serializer._serialize( # type: ignore # pylint: disable=protected-access + self, keep_readonly=keep_readonly, **kwargs + ) + + def as_dict( + self, + keep_readonly: bool = True, + key_transformer: Callable[[str, Dict[str, Any], Any], Any] = attribute_transformer, + **kwargs: Any + ) -> JSON: + """Return a dict that can be serialized using json.dump. + + Advanced usage might optionally use a callback as parameter: + + .. code::python + + def my_key_transformer(key, attr_desc, value): + return key + + Key is the attribute name used in Python. Attr_desc + is a dict of metadata. Currently contains 'type' with the + msrest type and 'key' with the RestAPI encoded key. + Value is the current value in this object. + + The string returned will be used to serialize the key. + If the return type is a list, this is considered hierarchical + result dict. + + See the three examples in this file: + + - attribute_transformer + - full_restapi_key_transformer + - last_restapi_key_transformer + + If you want XML serialization, you can pass the kwargs is_xml=True. + + :param bool keep_readonly: If you want to serialize the readonly attributes + :param function key_transformer: A key transformer function. + :returns: A dict JSON compatible object + :rtype: dict + """ + serializer = Serializer(self._infer_class_models()) + return serializer._serialize( # type: ignore # pylint: disable=protected-access + self, key_transformer=key_transformer, keep_readonly=keep_readonly, **kwargs + ) + + @classmethod + def _infer_class_models(cls): + try: + str_models = cls.__module__.rsplit(".", 1)[0] + models = sys.modules[str_models] + client_models = {k: v for k, v in models.__dict__.items() if isinstance(v, type)} + if cls.__name__ not in client_models: + raise ValueError("Not Autorest generated code") + except Exception: # pylint: disable=broad-exception-caught + # Assume it's not Autorest generated (tests?). Add ourselves as dependencies. + client_models = {cls.__name__: cls} + return client_models + + @classmethod + def deserialize(cls, data: Any, content_type: Optional[str] = None) -> Self: + """Parse a str using the RestAPI syntax and return a model. + + :param str data: A str using RestAPI structure. JSON by default. + :param str content_type: JSON by default, set application/xml if XML. + :returns: An instance of this model + :raises DeserializationError: if something went wrong + :rtype: Self + """ + deserializer = Deserializer(cls._infer_class_models()) + return deserializer(cls.__name__, data, content_type=content_type) # type: ignore + + @classmethod + def from_dict( + cls, + data: Any, + key_extractors: Optional[Callable[[str, Dict[str, Any], Any], Any]] = None, + content_type: Optional[str] = None, + ) -> Self: + """Parse a dict using given key extractor return a model. + + By default consider key + extractors (rest_key_case_insensitive_extractor, attribute_key_case_insensitive_extractor + and last_rest_key_case_insensitive_extractor) + + :param dict data: A dict using RestAPI structure + :param function key_extractors: A key extractor function. + :param str content_type: JSON by default, set application/xml if XML. + :returns: An instance of this model + :raises DeserializationError: if something went wrong + :rtype: Self + """ + deserializer = Deserializer(cls._infer_class_models()) + deserializer.key_extractors = ( # type: ignore + [ # type: ignore + attribute_key_case_insensitive_extractor, + rest_key_case_insensitive_extractor, + last_rest_key_case_insensitive_extractor, + ] + if key_extractors is None + else key_extractors + ) + return deserializer(cls.__name__, data, content_type=content_type) # type: ignore + + @classmethod + def _flatten_subtype(cls, key, objects): + if "_subtype_map" not in cls.__dict__: + return {} + result = dict(cls._subtype_map[key]) + for valuetype in cls._subtype_map[key].values(): + result.update(objects[valuetype]._flatten_subtype(key, objects)) # pylint: disable=protected-access + return result + + @classmethod + def _classify(cls, response, objects): + """Check the class _subtype_map for any child classes. + We want to ignore any inherited _subtype_maps. + + :param dict response: The initial data + :param dict objects: The class objects + :returns: The class to be used + :rtype: class + """ + for subtype_key in cls.__dict__.get("_subtype_map", {}).keys(): + subtype_value = None + + if not isinstance(response, ET.Element): + rest_api_response_key = cls._get_rest_key_parts(subtype_key)[-1] + subtype_value = response.get(rest_api_response_key, None) or response.get(subtype_key, None) + else: + subtype_value = xml_key_extractor(subtype_key, cls._attribute_map[subtype_key], response) + if subtype_value: + # Try to match base class. Can be class name only + # (bug to fix in Autorest to support x-ms-discriminator-name) + if cls.__name__ == subtype_value: + return cls + flatten_mapping_type = cls._flatten_subtype(subtype_key, objects) + try: + return objects[flatten_mapping_type[subtype_value]] # type: ignore + except KeyError: + _LOGGER.warning( + "Subtype value %s has no mapping, use base class %s.", + subtype_value, + cls.__name__, + ) + break + else: + _LOGGER.warning("Discriminator %s is absent or null, use base class %s.", subtype_key, cls.__name__) + break + return cls + + @classmethod + def _get_rest_key_parts(cls, attr_key): + """Get the RestAPI key of this attr, split it and decode part + :param str attr_key: Attribute key must be in attribute_map. + :returns: A list of RestAPI part + :rtype: list + """ + rest_split_key = _FLATTEN.split(cls._attribute_map[attr_key]["key"]) + return [_decode_attribute_map_key(key_part) for key_part in rest_split_key] + + +def _decode_attribute_map_key(key): + """This decode a key in an _attribute_map to the actual key we want to look at + inside the received data. + + :param str key: A key string from the generated code + :returns: The decoded key + :rtype: str + """ + return key.replace("\\.", ".") + + +class Serializer: # pylint: disable=too-many-public-methods + """Request object model serializer.""" + + basic_types = {str: "str", int: "int", bool: "bool", float: "float"} + + _xml_basic_types_serializers = {"bool": lambda x: str(x).lower()} + days = {0: "Mon", 1: "Tue", 2: "Wed", 3: "Thu", 4: "Fri", 5: "Sat", 6: "Sun"} + months = { + 1: "Jan", + 2: "Feb", + 3: "Mar", + 4: "Apr", + 5: "May", + 6: "Jun", + 7: "Jul", + 8: "Aug", + 9: "Sep", + 10: "Oct", + 11: "Nov", + 12: "Dec", + } + validation = { + "min_length": lambda x, y: len(x) < y, + "max_length": lambda x, y: len(x) > y, + "minimum": lambda x, y: x < y, + "maximum": lambda x, y: x > y, + "minimum_ex": lambda x, y: x <= y, + "maximum_ex": lambda x, y: x >= y, + "min_items": lambda x, y: len(x) < y, + "max_items": lambda x, y: len(x) > y, + "pattern": lambda x, y: not re.match(y, x, re.UNICODE), + "unique": lambda x, y: len(x) != len(set(x)), + "multiple": lambda x, y: x % y != 0, + } + + def __init__(self, classes: Optional[Mapping[str, type]] = None) -> None: + self.serialize_type = { + "iso-8601": Serializer.serialize_iso, + "rfc-1123": Serializer.serialize_rfc, + "unix-time": Serializer.serialize_unix, + "duration": Serializer.serialize_duration, + "date": Serializer.serialize_date, + "time": Serializer.serialize_time, + "decimal": Serializer.serialize_decimal, + "long": Serializer.serialize_long, + "bytearray": Serializer.serialize_bytearray, + "base64": Serializer.serialize_base64, + "object": self.serialize_object, + "[]": self.serialize_iter, + "{}": self.serialize_dict, + } + self.dependencies: Dict[str, type] = dict(classes) if classes else {} + self.key_transformer = full_restapi_key_transformer + self.client_side_validation = True + + def _serialize( # pylint: disable=too-many-nested-blocks, too-many-branches, too-many-statements, too-many-locals + self, target_obj, data_type=None, **kwargs + ): + """Serialize data into a string according to type. + + :param object target_obj: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str, dict + :raises SerializationError: if serialization fails. + :returns: The serialized data. + """ + key_transformer = kwargs.get("key_transformer", self.key_transformer) + keep_readonly = kwargs.get("keep_readonly", False) + if target_obj is None: + return None + + attr_name = None + class_name = target_obj.__class__.__name__ + + if data_type: + return self.serialize_data(target_obj, data_type, **kwargs) + + if not hasattr(target_obj, "_attribute_map"): + data_type = type(target_obj).__name__ + if data_type in self.basic_types.values(): + return self.serialize_data(target_obj, data_type, **kwargs) + + # Force "is_xml" kwargs if we detect a XML model + try: + is_xml_model_serialization = kwargs["is_xml"] + except KeyError: + is_xml_model_serialization = kwargs.setdefault("is_xml", target_obj.is_xml_model()) + + serialized = {} + if is_xml_model_serialization: + serialized = target_obj._create_xml_node() # pylint: disable=protected-access + try: + attributes = target_obj._attribute_map # pylint: disable=protected-access + for attr, attr_desc in attributes.items(): + attr_name = attr + if not keep_readonly and target_obj._validation.get( # pylint: disable=protected-access + attr_name, {} + ).get("readonly", False): + continue + + if attr_name == "additional_properties" and attr_desc["key"] == "": + if target_obj.additional_properties is not None: + serialized.update(target_obj.additional_properties) + continue + try: + + orig_attr = getattr(target_obj, attr) + if is_xml_model_serialization: + pass # Don't provide "transformer" for XML for now. Keep "orig_attr" + else: # JSON + keys, orig_attr = key_transformer(attr, attr_desc.copy(), orig_attr) + keys = keys if isinstance(keys, list) else [keys] + + kwargs["serialization_ctxt"] = attr_desc + new_attr = self.serialize_data(orig_attr, attr_desc["type"], **kwargs) + + if is_xml_model_serialization: + xml_desc = attr_desc.get("xml", {}) + xml_name = xml_desc.get("name", attr_desc["key"]) + xml_prefix = xml_desc.get("prefix", None) + xml_ns = xml_desc.get("ns", None) + if xml_desc.get("attr", False): + if xml_ns: + ET.register_namespace(xml_prefix, xml_ns) + xml_name = "{{{}}}{}".format(xml_ns, xml_name) + serialized.set(xml_name, new_attr) # type: ignore + continue + if xml_desc.get("text", False): + serialized.text = new_attr # type: ignore + continue + if isinstance(new_attr, list): + serialized.extend(new_attr) # type: ignore + elif isinstance(new_attr, ET.Element): + # If the down XML has no XML/Name, + # we MUST replace the tag with the local tag. But keeping the namespaces. + if "name" not in getattr(orig_attr, "_xml_map", {}): + splitted_tag = new_attr.tag.split("}") + if len(splitted_tag) == 2: # Namespace + new_attr.tag = "}".join([splitted_tag[0], xml_name]) + else: + new_attr.tag = xml_name + serialized.append(new_attr) # type: ignore + else: # That's a basic type + # Integrate namespace if necessary + local_node = _create_xml_node(xml_name, xml_prefix, xml_ns) + local_node.text = str(new_attr) + serialized.append(local_node) # type: ignore + else: # JSON + for k in reversed(keys): # type: ignore + new_attr = {k: new_attr} + + _new_attr = new_attr + _serialized = serialized + for k in keys: # type: ignore + if k not in _serialized: + _serialized.update(_new_attr) # type: ignore + _new_attr = _new_attr[k] # type: ignore + _serialized = _serialized[k] + except ValueError as err: + if isinstance(err, SerializationError): + raise + + except (AttributeError, KeyError, TypeError) as err: + msg = "Attribute {} in object {} cannot be serialized.\n{}".format(attr_name, class_name, str(target_obj)) + raise SerializationError(msg) from err + return serialized + + def body(self, data, data_type, **kwargs): + """Serialize data intended for a request body. + + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: dict + :raises SerializationError: if serialization fails. + :raises ValueError: if data is None + :returns: The serialized request body + """ + + # Just in case this is a dict + internal_data_type_str = data_type.strip("[]{}") + internal_data_type = self.dependencies.get(internal_data_type_str, None) + try: + is_xml_model_serialization = kwargs["is_xml"] + except KeyError: + if internal_data_type and issubclass(internal_data_type, Model): + is_xml_model_serialization = kwargs.setdefault("is_xml", internal_data_type.is_xml_model()) + else: + is_xml_model_serialization = False + if internal_data_type and not isinstance(internal_data_type, Enum): + try: + deserializer = Deserializer(self.dependencies) + # Since it's on serialization, it's almost sure that format is not JSON REST + # We're not able to deal with additional properties for now. + deserializer.additional_properties_detection = False + if is_xml_model_serialization: + deserializer.key_extractors = [ # type: ignore + attribute_key_case_insensitive_extractor, + ] + else: + deserializer.key_extractors = [ + rest_key_case_insensitive_extractor, + attribute_key_case_insensitive_extractor, + last_rest_key_case_insensitive_extractor, + ] + data = deserializer._deserialize(data_type, data) # pylint: disable=protected-access + except DeserializationError as err: + raise SerializationError("Unable to build a model: " + str(err)) from err + + return self._serialize(data, data_type, **kwargs) + + def url(self, name, data, data_type, **kwargs): + """Serialize data intended for a URL path. + + :param str name: The name of the URL path parameter. + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str + :returns: The serialized URL path + :raises TypeError: if serialization fails. + :raises ValueError: if data is None + """ + try: + output = self.serialize_data(data, data_type, **kwargs) + if data_type == "bool": + output = json.dumps(output) + + if kwargs.get("skip_quote") is True: + output = str(output) + output = output.replace("{", quote("{")).replace("}", quote("}")) + else: + output = quote(str(output), safe="") + except SerializationError as exc: + raise TypeError("{} must be type {}.".format(name, data_type)) from exc + return output + + def query(self, name, data, data_type, **kwargs): + """Serialize data intended for a URL query. + + :param str name: The name of the query parameter. + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str, list + :raises TypeError: if serialization fails. + :raises ValueError: if data is None + :returns: The serialized query parameter + """ + try: + # Treat the list aside, since we don't want to encode the div separator + if data_type.startswith("["): + internal_data_type = data_type[1:-1] + do_quote = not kwargs.get("skip_quote", False) + return self.serialize_iter(data, internal_data_type, do_quote=do_quote, **kwargs) + + # Not a list, regular serialization + output = self.serialize_data(data, data_type, **kwargs) + if data_type == "bool": + output = json.dumps(output) + if kwargs.get("skip_quote") is True: + output = str(output) + else: + output = quote(str(output), safe="") + except SerializationError as exc: + raise TypeError("{} must be type {}.".format(name, data_type)) from exc + return str(output) + + def header(self, name, data, data_type, **kwargs): + """Serialize data intended for a request header. + + :param str name: The name of the header. + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str + :raises TypeError: if serialization fails. + :raises ValueError: if data is None + :returns: The serialized header + """ + try: + if data_type in ["[str]"]: + data = ["" if d is None else d for d in data] + + output = self.serialize_data(data, data_type, **kwargs) + if data_type == "bool": + output = json.dumps(output) + except SerializationError as exc: + raise TypeError("{} must be type {}.".format(name, data_type)) from exc + return str(output) + + def serialize_data(self, data, data_type, **kwargs): + """Serialize generic data according to supplied data type. + + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :raises AttributeError: if required data is None. + :raises ValueError: if data is None + :raises SerializationError: if serialization fails. + :returns: The serialized data. + :rtype: str, int, float, bool, dict, list + """ + if data is None: + raise ValueError("No value for given attribute") + + try: + if data is CoreNull: + return None + if data_type in self.basic_types.values(): + return self.serialize_basic(data, data_type, **kwargs) + + if data_type in self.serialize_type: + return self.serialize_type[data_type](data, **kwargs) + + # If dependencies is empty, try with current data class + # It has to be a subclass of Enum anyway + enum_type = self.dependencies.get(data_type, data.__class__) + if issubclass(enum_type, Enum): + return Serializer.serialize_enum(data, enum_obj=enum_type) + + iter_type = data_type[0] + data_type[-1] + if iter_type in self.serialize_type: + return self.serialize_type[iter_type](data, data_type[1:-1], **kwargs) + + except (ValueError, TypeError) as err: + msg = "Unable to serialize value: {!r} as type: {!r}." + raise SerializationError(msg.format(data, data_type)) from err + return self._serialize(data, **kwargs) + + @classmethod + def _get_custom_serializers(cls, data_type, **kwargs): # pylint: disable=inconsistent-return-statements + custom_serializer = kwargs.get("basic_types_serializers", {}).get(data_type) + if custom_serializer: + return custom_serializer + if kwargs.get("is_xml", False): + return cls._xml_basic_types_serializers.get(data_type) + + @classmethod + def serialize_basic(cls, data, data_type, **kwargs): + """Serialize basic builting data type. + Serializes objects to str, int, float or bool. + + Possible kwargs: + - basic_types_serializers dict[str, callable] : If set, use the callable as serializer + - is_xml bool : If set, use xml_basic_types_serializers + + :param obj data: Object to be serialized. + :param str data_type: Type of object in the iterable. + :rtype: str, int, float, bool + :return: serialized object + """ + custom_serializer = cls._get_custom_serializers(data_type, **kwargs) + if custom_serializer: + return custom_serializer(data) + if data_type == "str": + return cls.serialize_unicode(data) + return eval(data_type)(data) # nosec # pylint: disable=eval-used + + @classmethod + def serialize_unicode(cls, data): + """Special handling for serializing unicode strings in Py2. + Encode to UTF-8 if unicode, otherwise handle as a str. + + :param str data: Object to be serialized. + :rtype: str + :return: serialized object + """ + try: # If I received an enum, return its value + return data.value + except AttributeError: + pass + + try: + if isinstance(data, unicode): # type: ignore + # Don't change it, JSON and XML ElementTree are totally able + # to serialize correctly u'' strings + return data + except NameError: + return str(data) + return str(data) + + def serialize_iter(self, data, iter_type, div=None, **kwargs): + """Serialize iterable. + + Supported kwargs: + - serialization_ctxt dict : The current entry of _attribute_map, or same format. + serialization_ctxt['type'] should be same as data_type. + - is_xml bool : If set, serialize as XML + + :param list data: Object to be serialized. + :param str iter_type: Type of object in the iterable. + :param str div: If set, this str will be used to combine the elements + in the iterable into a combined string. Default is 'None'. + Defaults to False. + :rtype: list, str + :return: serialized iterable + """ + if isinstance(data, str): + raise SerializationError("Refuse str type as a valid iter type.") + + serialization_ctxt = kwargs.get("serialization_ctxt", {}) + is_xml = kwargs.get("is_xml", False) + + serialized = [] + for d in data: + try: + serialized.append(self.serialize_data(d, iter_type, **kwargs)) + except ValueError as err: + if isinstance(err, SerializationError): + raise + serialized.append(None) + + if kwargs.get("do_quote", False): + serialized = ["" if s is None else quote(str(s), safe="") for s in serialized] + + if div: + serialized = ["" if s is None else str(s) for s in serialized] + serialized = div.join(serialized) + + if "xml" in serialization_ctxt or is_xml: + # XML serialization is more complicated + xml_desc = serialization_ctxt.get("xml", {}) + xml_name = xml_desc.get("name") + if not xml_name: + xml_name = serialization_ctxt["key"] + + # Create a wrap node if necessary (use the fact that Element and list have "append") + is_wrapped = xml_desc.get("wrapped", False) + node_name = xml_desc.get("itemsName", xml_name) + if is_wrapped: + final_result = _create_xml_node(xml_name, xml_desc.get("prefix", None), xml_desc.get("ns", None)) + else: + final_result = [] + # All list elements to "local_node" + for el in serialized: + if isinstance(el, ET.Element): + el_node = el + else: + el_node = _create_xml_node(node_name, xml_desc.get("prefix", None), xml_desc.get("ns", None)) + if el is not None: # Otherwise it writes "None" :-p + el_node.text = str(el) + final_result.append(el_node) + return final_result + return serialized + + def serialize_dict(self, attr, dict_type, **kwargs): + """Serialize a dictionary of objects. + + :param dict attr: Object to be serialized. + :param str dict_type: Type of object in the dictionary. + :rtype: dict + :return: serialized dictionary + """ + serialization_ctxt = kwargs.get("serialization_ctxt", {}) + serialized = {} + for key, value in attr.items(): + try: + serialized[self.serialize_unicode(key)] = self.serialize_data(value, dict_type, **kwargs) + except ValueError as err: + if isinstance(err, SerializationError): + raise + serialized[self.serialize_unicode(key)] = None + + if "xml" in serialization_ctxt: + # XML serialization is more complicated + xml_desc = serialization_ctxt["xml"] + xml_name = xml_desc["name"] + + final_result = _create_xml_node(xml_name, xml_desc.get("prefix", None), xml_desc.get("ns", None)) + for key, value in serialized.items(): + ET.SubElement(final_result, key).text = value + return final_result + + return serialized + + def serialize_object(self, attr, **kwargs): # pylint: disable=too-many-return-statements + """Serialize a generic object. + This will be handled as a dictionary. If object passed in is not + a basic type (str, int, float, dict, list) it will simply be + cast to str. + + :param dict attr: Object to be serialized. + :rtype: dict or str + :return: serialized object + """ + if attr is None: + return None + if isinstance(attr, ET.Element): + return attr + obj_type = type(attr) + if obj_type in self.basic_types: + return self.serialize_basic(attr, self.basic_types[obj_type], **kwargs) + if obj_type is _long_type: + return self.serialize_long(attr) + if obj_type is str: + return self.serialize_unicode(attr) + if obj_type is datetime.datetime: + return self.serialize_iso(attr) + if obj_type is datetime.date: + return self.serialize_date(attr) + if obj_type is datetime.time: + return self.serialize_time(attr) + if obj_type is datetime.timedelta: + return self.serialize_duration(attr) + if obj_type is decimal.Decimal: + return self.serialize_decimal(attr) + + # If it's a model or I know this dependency, serialize as a Model + if obj_type in self.dependencies.values() or isinstance(attr, Model): + return self._serialize(attr) + + if obj_type == dict: + serialized = {} + for key, value in attr.items(): + try: + serialized[self.serialize_unicode(key)] = self.serialize_object(value, **kwargs) + except ValueError: + serialized[self.serialize_unicode(key)] = None + return serialized + + if obj_type == list: + serialized = [] + for obj in attr: + try: + serialized.append(self.serialize_object(obj, **kwargs)) + except ValueError: + pass + return serialized + return str(attr) + + @staticmethod + def serialize_enum(attr, enum_obj=None): + try: + result = attr.value + except AttributeError: + result = attr + try: + enum_obj(result) # type: ignore + return result + except ValueError as exc: + for enum_value in enum_obj: # type: ignore + if enum_value.value.lower() == str(attr).lower(): + return enum_value.value + error = "{!r} is not valid value for enum {!r}" + raise SerializationError(error.format(attr, enum_obj)) from exc + + @staticmethod + def serialize_bytearray(attr, **kwargs): # pylint: disable=unused-argument + """Serialize bytearray into base-64 string. + + :param str attr: Object to be serialized. + :rtype: str + :return: serialized base64 + """ + return b64encode(attr).decode() + + @staticmethod + def serialize_base64(attr, **kwargs): # pylint: disable=unused-argument + """Serialize str into base-64 string. + + :param str attr: Object to be serialized. + :rtype: str + :return: serialized base64 + """ + encoded = b64encode(attr).decode("ascii") + return encoded.strip("=").replace("+", "-").replace("/", "_") + + @staticmethod + def serialize_decimal(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Decimal object to float. + + :param decimal attr: Object to be serialized. + :rtype: float + :return: serialized decimal + """ + return float(attr) + + @staticmethod + def serialize_long(attr, **kwargs): # pylint: disable=unused-argument + """Serialize long (Py2) or int (Py3). + + :param int attr: Object to be serialized. + :rtype: int/long + :return: serialized long + """ + return _long_type(attr) + + @staticmethod + def serialize_date(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Date object into ISO-8601 formatted string. + + :param Date attr: Object to be serialized. + :rtype: str + :return: serialized date + """ + if isinstance(attr, str): + attr = isodate.parse_date(attr) + t = "{:04}-{:02}-{:02}".format(attr.year, attr.month, attr.day) + return t + + @staticmethod + def serialize_time(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Time object into ISO-8601 formatted string. + + :param datetime.time attr: Object to be serialized. + :rtype: str + :return: serialized time + """ + if isinstance(attr, str): + attr = isodate.parse_time(attr) + t = "{:02}:{:02}:{:02}".format(attr.hour, attr.minute, attr.second) + if attr.microsecond: + t += ".{:02}".format(attr.microsecond) + return t + + @staticmethod + def serialize_duration(attr, **kwargs): # pylint: disable=unused-argument + """Serialize TimeDelta object into ISO-8601 formatted string. + + :param TimeDelta attr: Object to be serialized. + :rtype: str + :return: serialized duration + """ + if isinstance(attr, str): + attr = isodate.parse_duration(attr) + return isodate.duration_isoformat(attr) + + @staticmethod + def serialize_rfc(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Datetime object into RFC-1123 formatted string. + + :param Datetime attr: Object to be serialized. + :rtype: str + :raises TypeError: if format invalid. + :return: serialized rfc + """ + try: + if not attr.tzinfo: + _LOGGER.warning("Datetime with no tzinfo will be considered UTC.") + utc = attr.utctimetuple() + except AttributeError as exc: + raise TypeError("RFC1123 object must be valid Datetime object.") from exc + + return "{}, {:02} {} {:04} {:02}:{:02}:{:02} GMT".format( + Serializer.days[utc.tm_wday], + utc.tm_mday, + Serializer.months[utc.tm_mon], + utc.tm_year, + utc.tm_hour, + utc.tm_min, + utc.tm_sec, + ) + + @staticmethod + def serialize_iso(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Datetime object into ISO-8601 formatted string. + + :param Datetime attr: Object to be serialized. + :rtype: str + :raises SerializationError: if format invalid. + :return: serialized iso + """ + if isinstance(attr, str): + attr = isodate.parse_datetime(attr) + try: + if not attr.tzinfo: + _LOGGER.warning("Datetime with no tzinfo will be considered UTC.") + utc = attr.utctimetuple() + if utc.tm_year > 9999 or utc.tm_year < 1: + raise OverflowError("Hit max or min date") + + microseconds = str(attr.microsecond).rjust(6, "0").rstrip("0").ljust(3, "0") + if microseconds: + microseconds = "." + microseconds + date = "{:04}-{:02}-{:02}T{:02}:{:02}:{:02}".format( + utc.tm_year, utc.tm_mon, utc.tm_mday, utc.tm_hour, utc.tm_min, utc.tm_sec + ) + return date + microseconds + "Z" + except (ValueError, OverflowError) as err: + msg = "Unable to serialize datetime object." + raise SerializationError(msg) from err + except AttributeError as err: + msg = "ISO-8601 object must be valid Datetime object." + raise TypeError(msg) from err + + @staticmethod + def serialize_unix(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Datetime object into IntTime format. + This is represented as seconds. + + :param Datetime attr: Object to be serialized. + :rtype: int + :raises SerializationError: if format invalid + :return: serialied unix + """ + if isinstance(attr, int): + return attr + try: + if not attr.tzinfo: + _LOGGER.warning("Datetime with no tzinfo will be considered UTC.") + return int(calendar.timegm(attr.utctimetuple())) + except AttributeError as exc: + raise TypeError("Unix time object must be valid Datetime object.") from exc + + +def rest_key_extractor(attr, attr_desc, data): # pylint: disable=unused-argument + key = attr_desc["key"] + working_data = data + + while "." in key: + # Need the cast, as for some reasons "split" is typed as list[str | Any] + dict_keys = cast(List[str], _FLATTEN.split(key)) + if len(dict_keys) == 1: + key = _decode_attribute_map_key(dict_keys[0]) + break + working_key = _decode_attribute_map_key(dict_keys[0]) + working_data = working_data.get(working_key, data) + if working_data is None: + # If at any point while following flatten JSON path see None, it means + # that all properties under are None as well + return None + key = ".".join(dict_keys[1:]) + + return working_data.get(key) + + +def rest_key_case_insensitive_extractor( # pylint: disable=unused-argument, inconsistent-return-statements + attr, attr_desc, data +): + key = attr_desc["key"] + working_data = data + + while "." in key: + dict_keys = _FLATTEN.split(key) + if len(dict_keys) == 1: + key = _decode_attribute_map_key(dict_keys[0]) + break + working_key = _decode_attribute_map_key(dict_keys[0]) + working_data = attribute_key_case_insensitive_extractor(working_key, None, working_data) + if working_data is None: + # If at any point while following flatten JSON path see None, it means + # that all properties under are None as well + return None + key = ".".join(dict_keys[1:]) + + if working_data: + return attribute_key_case_insensitive_extractor(key, None, working_data) + + +def last_rest_key_extractor(attr, attr_desc, data): # pylint: disable=unused-argument + """Extract the attribute in "data" based on the last part of the JSON path key. + + :param str attr: The attribute to extract + :param dict attr_desc: The attribute description + :param dict data: The data to extract from + :rtype: object + :returns: The extracted attribute + """ + key = attr_desc["key"] + dict_keys = _FLATTEN.split(key) + return attribute_key_extractor(dict_keys[-1], None, data) + + +def last_rest_key_case_insensitive_extractor(attr, attr_desc, data): # pylint: disable=unused-argument + """Extract the attribute in "data" based on the last part of the JSON path key. + + This is the case insensitive version of "last_rest_key_extractor" + :param str attr: The attribute to extract + :param dict attr_desc: The attribute description + :param dict data: The data to extract from + :rtype: object + :returns: The extracted attribute + """ + key = attr_desc["key"] + dict_keys = _FLATTEN.split(key) + return attribute_key_case_insensitive_extractor(dict_keys[-1], None, data) + + +def attribute_key_extractor(attr, _, data): + return data.get(attr) + + +def attribute_key_case_insensitive_extractor(attr, _, data): + found_key = None + lower_attr = attr.lower() + for key in data: + if lower_attr == key.lower(): + found_key = key + break + + return data.get(found_key) + + +def _extract_name_from_internal_type(internal_type): + """Given an internal type XML description, extract correct XML name with namespace. + + :param dict internal_type: An model type + :rtype: tuple + :returns: A tuple XML name + namespace dict + """ + internal_type_xml_map = getattr(internal_type, "_xml_map", {}) + xml_name = internal_type_xml_map.get("name", internal_type.__name__) + xml_ns = internal_type_xml_map.get("ns", None) + if xml_ns: + xml_name = "{{{}}}{}".format(xml_ns, xml_name) + return xml_name + + +def xml_key_extractor(attr, attr_desc, data): # pylint: disable=unused-argument,too-many-return-statements + if isinstance(data, dict): + return None + + # Test if this model is XML ready first + if not isinstance(data, ET.Element): + return None + + xml_desc = attr_desc.get("xml", {}) + xml_name = xml_desc.get("name", attr_desc["key"]) + + # Look for a children + is_iter_type = attr_desc["type"].startswith("[") + is_wrapped = xml_desc.get("wrapped", False) + internal_type = attr_desc.get("internalType", None) + internal_type_xml_map = getattr(internal_type, "_xml_map", {}) + + # Integrate namespace if necessary + xml_ns = xml_desc.get("ns", internal_type_xml_map.get("ns", None)) + if xml_ns: + xml_name = "{{{}}}{}".format(xml_ns, xml_name) + + # If it's an attribute, that's simple + if xml_desc.get("attr", False): + return data.get(xml_name) + + # If it's x-ms-text, that's simple too + if xml_desc.get("text", False): + return data.text + + # Scenario where I take the local name: + # - Wrapped node + # - Internal type is an enum (considered basic types) + # - Internal type has no XML/Name node + if is_wrapped or (internal_type and (issubclass(internal_type, Enum) or "name" not in internal_type_xml_map)): + children = data.findall(xml_name) + # If internal type has a local name and it's not a list, I use that name + elif not is_iter_type and internal_type and "name" in internal_type_xml_map: + xml_name = _extract_name_from_internal_type(internal_type) + children = data.findall(xml_name) + # That's an array + else: + if internal_type: # Complex type, ignore itemsName and use the complex type name + items_name = _extract_name_from_internal_type(internal_type) + else: + items_name = xml_desc.get("itemsName", xml_name) + children = data.findall(items_name) + + if len(children) == 0: + if is_iter_type: + if is_wrapped: + return None # is_wrapped no node, we want None + return [] # not wrapped, assume empty list + return None # Assume it's not there, maybe an optional node. + + # If is_iter_type and not wrapped, return all found children + if is_iter_type: + if not is_wrapped: + return children + # Iter and wrapped, should have found one node only (the wrap one) + if len(children) != 1: + raise DeserializationError( + "Tried to deserialize an array not wrapped, and found several nodes '{}'. Maybe you should declare this array as wrapped?".format( + xml_name + ) + ) + return list(children[0]) # Might be empty list and that's ok. + + # Here it's not a itertype, we should have found one element only or empty + if len(children) > 1: + raise DeserializationError("Find several XML '{}' where it was not expected".format(xml_name)) + return children[0] + + +class Deserializer: + """Response object model deserializer. + + :param dict classes: Class type dictionary for deserializing complex types. + :ivar list key_extractors: Ordered list of extractors to be used by this deserializer. + """ + + basic_types = {str: "str", int: "int", bool: "bool", float: "float"} + + valid_date = re.compile(r"\d{4}[-]\d{2}[-]\d{2}T\d{2}:\d{2}:\d{2}\.?\d*Z?[-+]?[\d{2}]?:?[\d{2}]?") + + def __init__(self, classes: Optional[Mapping[str, type]] = None) -> None: + self.deserialize_type = { + "iso-8601": Deserializer.deserialize_iso, + "rfc-1123": Deserializer.deserialize_rfc, + "unix-time": Deserializer.deserialize_unix, + "duration": Deserializer.deserialize_duration, + "date": Deserializer.deserialize_date, + "time": Deserializer.deserialize_time, + "decimal": Deserializer.deserialize_decimal, + "long": Deserializer.deserialize_long, + "bytearray": Deserializer.deserialize_bytearray, + "base64": Deserializer.deserialize_base64, + "object": self.deserialize_object, + "[]": self.deserialize_iter, + "{}": self.deserialize_dict, + } + self.deserialize_expected_types = { + "duration": (isodate.Duration, datetime.timedelta), + "iso-8601": (datetime.datetime), + } + self.dependencies: Dict[str, type] = dict(classes) if classes else {} + self.key_extractors = [rest_key_extractor, xml_key_extractor] + # Additional properties only works if the "rest_key_extractor" is used to + # extract the keys. Making it to work whatever the key extractor is too much + # complicated, with no real scenario for now. + # So adding a flag to disable additional properties detection. This flag should be + # used if your expect the deserialization to NOT come from a JSON REST syntax. + # Otherwise, result are unexpected + self.additional_properties_detection = True + + def __call__(self, target_obj, response_data, content_type=None): + """Call the deserializer to process a REST response. + + :param str target_obj: Target data type to deserialize to. + :param requests.Response response_data: REST response object. + :param str content_type: Swagger "produces" if available. + :raises DeserializationError: if deserialization fails. + :return: Deserialized object. + :rtype: object + """ + data = self._unpack_content(response_data, content_type) + return self._deserialize(target_obj, data) + + def _deserialize(self, target_obj, data): # pylint: disable=inconsistent-return-statements + """Call the deserializer on a model. + + Data needs to be already deserialized as JSON or XML ElementTree + + :param str target_obj: Target data type to deserialize to. + :param object data: Object to deserialize. + :raises DeserializationError: if deserialization fails. + :return: Deserialized object. + :rtype: object + """ + # This is already a model, go recursive just in case + if hasattr(data, "_attribute_map"): + constants = [name for name, config in getattr(data, "_validation", {}).items() if config.get("constant")] + try: + for attr, mapconfig in data._attribute_map.items(): # pylint: disable=protected-access + if attr in constants: + continue + value = getattr(data, attr) + if value is None: + continue + local_type = mapconfig["type"] + internal_data_type = local_type.strip("[]{}") + if internal_data_type not in self.dependencies or isinstance(internal_data_type, Enum): + continue + setattr(data, attr, self._deserialize(local_type, value)) + return data + except AttributeError: + return + + response, class_name = self._classify_target(target_obj, data) + + if isinstance(response, str): + return self.deserialize_data(data, response) + if isinstance(response, type) and issubclass(response, Enum): + return self.deserialize_enum(data, response) + + if data is None or data is CoreNull: + return data + try: + attributes = response._attribute_map # type: ignore # pylint: disable=protected-access + d_attrs = {} + for attr, attr_desc in attributes.items(): + # Check empty string. If it's not empty, someone has a real "additionalProperties"... + if attr == "additional_properties" and attr_desc["key"] == "": + continue + raw_value = None + # Enhance attr_desc with some dynamic data + attr_desc = attr_desc.copy() # Do a copy, do not change the real one + internal_data_type = attr_desc["type"].strip("[]{}") + if internal_data_type in self.dependencies: + attr_desc["internalType"] = self.dependencies[internal_data_type] + + for key_extractor in self.key_extractors: + found_value = key_extractor(attr, attr_desc, data) + if found_value is not None: + if raw_value is not None and raw_value != found_value: + msg = ( + "Ignoring extracted value '%s' from %s for key '%s'" + " (duplicate extraction, follow extractors order)" + ) + _LOGGER.warning(msg, found_value, key_extractor, attr) + continue + raw_value = found_value + + value = self.deserialize_data(raw_value, attr_desc["type"]) + d_attrs[attr] = value + except (AttributeError, TypeError, KeyError) as err: + msg = "Unable to deserialize to object: " + class_name # type: ignore + raise DeserializationError(msg) from err + additional_properties = self._build_additional_properties(attributes, data) + return self._instantiate_model(response, d_attrs, additional_properties) + + def _build_additional_properties(self, attribute_map, data): + if not self.additional_properties_detection: + return None + if "additional_properties" in attribute_map and attribute_map.get("additional_properties", {}).get("key") != "": + # Check empty string. If it's not empty, someone has a real "additionalProperties" + return None + if isinstance(data, ET.Element): + data = {el.tag: el.text for el in data} + + known_keys = { + _decode_attribute_map_key(_FLATTEN.split(desc["key"])[0]) + for desc in attribute_map.values() + if desc["key"] != "" + } + present_keys = set(data.keys()) + missing_keys = present_keys - known_keys + return {key: data[key] for key in missing_keys} + + def _classify_target(self, target, data): + """Check to see whether the deserialization target object can + be classified into a subclass. + Once classification has been determined, initialize object. + + :param str target: The target object type to deserialize to. + :param str/dict data: The response data to deserialize. + :return: The classified target object and its class name. + :rtype: tuple + """ + if target is None: + return None, None + + if isinstance(target, str): + try: + target = self.dependencies[target] + except KeyError: + return target, target + + try: + target = target._classify(data, self.dependencies) # type: ignore # pylint: disable=protected-access + except AttributeError: + pass # Target is not a Model, no classify + return target, target.__class__.__name__ # type: ignore + + def failsafe_deserialize(self, target_obj, data, content_type=None): + """Ignores any errors encountered in deserialization, + and falls back to not deserializing the object. Recommended + for use in error deserialization, as we want to return the + HttpResponseError to users, and not have them deal with + a deserialization error. + + :param str target_obj: The target object type to deserialize to. + :param str/dict data: The response data to deserialize. + :param str content_type: Swagger "produces" if available. + :return: Deserialized object. + :rtype: object + """ + try: + return self(target_obj, data, content_type=content_type) + except: # pylint: disable=bare-except + _LOGGER.debug( + "Ran into a deserialization error. Ignoring since this is failsafe deserialization", exc_info=True + ) + return None + + @staticmethod + def _unpack_content(raw_data, content_type=None): + """Extract the correct structure for deserialization. + + If raw_data is a PipelineResponse, try to extract the result of RawDeserializer. + if we can't, raise. Your Pipeline should have a RawDeserializer. + + If not a pipeline response and raw_data is bytes or string, use content-type + to decode it. If no content-type, try JSON. + + If raw_data is something else, bypass all logic and return it directly. + + :param obj raw_data: Data to be processed. + :param str content_type: How to parse if raw_data is a string/bytes. + :raises JSONDecodeError: If JSON is requested and parsing is impossible. + :raises UnicodeDecodeError: If bytes is not UTF8 + :rtype: object + :return: Unpacked content. + """ + # Assume this is enough to detect a Pipeline Response without importing it + context = getattr(raw_data, "context", {}) + if context: + if RawDeserializer.CONTEXT_NAME in context: + return context[RawDeserializer.CONTEXT_NAME] + raise ValueError("This pipeline didn't have the RawDeserializer policy; can't deserialize") + + # Assume this is enough to recognize universal_http.ClientResponse without importing it + if hasattr(raw_data, "body"): + return RawDeserializer.deserialize_from_http_generics(raw_data.text(), raw_data.headers) + + # Assume this enough to recognize requests.Response without importing it. + if hasattr(raw_data, "_content_consumed"): + return RawDeserializer.deserialize_from_http_generics(raw_data.text, raw_data.headers) + + if isinstance(raw_data, (str, bytes)) or hasattr(raw_data, "read"): + return RawDeserializer.deserialize_from_text(raw_data, content_type) # type: ignore + return raw_data + + def _instantiate_model(self, response, attrs, additional_properties=None): + """Instantiate a response model passing in deserialized args. + + :param Response response: The response model class. + :param dict attrs: The deserialized response attributes. + :param dict additional_properties: Additional properties to be set. + :rtype: Response + :return: The instantiated response model. + """ + if callable(response): + subtype = getattr(response, "_subtype_map", {}) + try: + readonly = [ + k + for k, v in response._validation.items() # pylint: disable=protected-access # type: ignore + if v.get("readonly") + ] + const = [ + k + for k, v in response._validation.items() # pylint: disable=protected-access # type: ignore + if v.get("constant") + ] + kwargs = {k: v for k, v in attrs.items() if k not in subtype and k not in readonly + const} + response_obj = response(**kwargs) + for attr in readonly: + setattr(response_obj, attr, attrs.get(attr)) + if additional_properties: + response_obj.additional_properties = additional_properties # type: ignore + return response_obj + except TypeError as err: + msg = "Unable to deserialize {} into model {}. ".format(kwargs, response) # type: ignore + raise DeserializationError(msg + str(err)) from err + else: + try: + for attr, value in attrs.items(): + setattr(response, attr, value) + return response + except Exception as exp: + msg = "Unable to populate response model. " + msg += "Type: {}, Error: {}".format(type(response), exp) + raise DeserializationError(msg) from exp + + def deserialize_data(self, data, data_type): # pylint: disable=too-many-return-statements + """Process data for deserialization according to data type. + + :param str data: The response string to be deserialized. + :param str data_type: The type to deserialize to. + :raises DeserializationError: if deserialization fails. + :return: Deserialized object. + :rtype: object + """ + if data is None: + return data + + try: + if not data_type: + return data + if data_type in self.basic_types.values(): + return self.deserialize_basic(data, data_type) + if data_type in self.deserialize_type: + if isinstance(data, self.deserialize_expected_types.get(data_type, tuple())): + return data + + is_a_text_parsing_type = lambda x: x not in [ # pylint: disable=unnecessary-lambda-assignment + "object", + "[]", + r"{}", + ] + if isinstance(data, ET.Element) and is_a_text_parsing_type(data_type) and not data.text: + return None + data_val = self.deserialize_type[data_type](data) + return data_val + + iter_type = data_type[0] + data_type[-1] + if iter_type in self.deserialize_type: + return self.deserialize_type[iter_type](data, data_type[1:-1]) + + obj_type = self.dependencies[data_type] + if issubclass(obj_type, Enum): + if isinstance(data, ET.Element): + data = data.text + return self.deserialize_enum(data, obj_type) + + except (ValueError, TypeError, AttributeError) as err: + msg = "Unable to deserialize response data." + msg += " Data: {}, {}".format(data, data_type) + raise DeserializationError(msg) from err + return self._deserialize(obj_type, data) + + def deserialize_iter(self, attr, iter_type): + """Deserialize an iterable. + + :param list attr: Iterable to be deserialized. + :param str iter_type: The type of object in the iterable. + :return: Deserialized iterable. + :rtype: list + """ + if attr is None: + return None + if isinstance(attr, ET.Element): # If I receive an element here, get the children + attr = list(attr) + if not isinstance(attr, (list, set)): + raise DeserializationError("Cannot deserialize as [{}] an object of type {}".format(iter_type, type(attr))) + return [self.deserialize_data(a, iter_type) for a in attr] + + def deserialize_dict(self, attr, dict_type): + """Deserialize a dictionary. + + :param dict/list attr: Dictionary to be deserialized. Also accepts + a list of key, value pairs. + :param str dict_type: The object type of the items in the dictionary. + :return: Deserialized dictionary. + :rtype: dict + """ + if isinstance(attr, list): + return {x["key"]: self.deserialize_data(x["value"], dict_type) for x in attr} + + if isinstance(attr, ET.Element): + # Transform value into {"Key": "value"} + attr = {el.tag: el.text for el in attr} + return {k: self.deserialize_data(v, dict_type) for k, v in attr.items()} + + def deserialize_object(self, attr, **kwargs): # pylint: disable=too-many-return-statements + """Deserialize a generic object. + This will be handled as a dictionary. + + :param dict attr: Dictionary to be deserialized. + :return: Deserialized object. + :rtype: dict + :raises TypeError: if non-builtin datatype encountered. + """ + if attr is None: + return None + if isinstance(attr, ET.Element): + # Do no recurse on XML, just return the tree as-is + return attr + if isinstance(attr, str): + return self.deserialize_basic(attr, "str") + obj_type = type(attr) + if obj_type in self.basic_types: + return self.deserialize_basic(attr, self.basic_types[obj_type]) + if obj_type is _long_type: + return self.deserialize_long(attr) + + if obj_type == dict: + deserialized = {} + for key, value in attr.items(): + try: + deserialized[key] = self.deserialize_object(value, **kwargs) + except ValueError: + deserialized[key] = None + return deserialized + + if obj_type == list: + deserialized = [] + for obj in attr: + try: + deserialized.append(self.deserialize_object(obj, **kwargs)) + except ValueError: + pass + return deserialized + + error = "Cannot deserialize generic object with type: " + raise TypeError(error + str(obj_type)) + + def deserialize_basic(self, attr, data_type): # pylint: disable=too-many-return-statements + """Deserialize basic builtin data type from string. + Will attempt to convert to str, int, float and bool. + This function will also accept '1', '0', 'true' and 'false' as + valid bool values. + + :param str attr: response string to be deserialized. + :param str data_type: deserialization data type. + :return: Deserialized basic type. + :rtype: str, int, float or bool + :raises TypeError: if string format is not valid. + """ + # If we're here, data is supposed to be a basic type. + # If it's still an XML node, take the text + if isinstance(attr, ET.Element): + attr = attr.text + if not attr: + if data_type == "str": + # None or '', node is empty string. + return "" + # None or '', node with a strong type is None. + # Don't try to model "empty bool" or "empty int" + return None + + if data_type == "bool": + if attr in [True, False, 1, 0]: + return bool(attr) + if isinstance(attr, str): + if attr.lower() in ["true", "1"]: + return True + if attr.lower() in ["false", "0"]: + return False + raise TypeError("Invalid boolean value: {}".format(attr)) + + if data_type == "str": + return self.deserialize_unicode(attr) + return eval(data_type)(attr) # nosec # pylint: disable=eval-used + + @staticmethod + def deserialize_unicode(data): + """Preserve unicode objects in Python 2, otherwise return data + as a string. + + :param str data: response string to be deserialized. + :return: Deserialized string. + :rtype: str or unicode + """ + # We might be here because we have an enum modeled as string, + # and we try to deserialize a partial dict with enum inside + if isinstance(data, Enum): + return data + + # Consider this is real string + try: + if isinstance(data, unicode): # type: ignore + return data + except NameError: + return str(data) + return str(data) + + @staticmethod + def deserialize_enum(data, enum_obj): + """Deserialize string into enum object. + + If the string is not a valid enum value it will be returned as-is + and a warning will be logged. + + :param str data: Response string to be deserialized. If this value is + None or invalid it will be returned as-is. + :param Enum enum_obj: Enum object to deserialize to. + :return: Deserialized enum object. + :rtype: Enum + """ + if isinstance(data, enum_obj) or data is None: + return data + if isinstance(data, Enum): + data = data.value + if isinstance(data, int): + # Workaround. We might consider remove it in the future. + try: + return list(enum_obj.__members__.values())[data] + except IndexError as exc: + error = "{!r} is not a valid index for enum {!r}" + raise DeserializationError(error.format(data, enum_obj)) from exc + try: + return enum_obj(str(data)) + except ValueError: + for enum_value in enum_obj: + if enum_value.value.lower() == str(data).lower(): + return enum_value + # We don't fail anymore for unknown value, we deserialize as a string + _LOGGER.warning("Deserializer is not able to find %s as valid enum in %s", data, enum_obj) + return Deserializer.deserialize_unicode(data) + + @staticmethod + def deserialize_bytearray(attr): + """Deserialize string into bytearray. + + :param str attr: response string to be deserialized. + :return: Deserialized bytearray + :rtype: bytearray + :raises TypeError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + return bytearray(b64decode(attr)) # type: ignore + + @staticmethod + def deserialize_base64(attr): + """Deserialize base64 encoded string into string. + + :param str attr: response string to be deserialized. + :return: Deserialized base64 string + :rtype: bytearray + :raises TypeError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + padding = "=" * (3 - (len(attr) + 3) % 4) # type: ignore + attr = attr + padding # type: ignore + encoded = attr.replace("-", "+").replace("_", "/") + return b64decode(encoded) + + @staticmethod + def deserialize_decimal(attr): + """Deserialize string into Decimal object. + + :param str attr: response string to be deserialized. + :return: Deserialized decimal + :raises DeserializationError: if string format invalid. + :rtype: decimal + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + return decimal.Decimal(str(attr)) # type: ignore + except decimal.DecimalException as err: + msg = "Invalid decimal {}".format(attr) + raise DeserializationError(msg) from err + + @staticmethod + def deserialize_long(attr): + """Deserialize string into long (Py2) or int (Py3). + + :param str attr: response string to be deserialized. + :return: Deserialized int + :rtype: long or int + :raises ValueError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + return _long_type(attr) # type: ignore + + @staticmethod + def deserialize_duration(attr): + """Deserialize ISO-8601 formatted string into TimeDelta object. + + :param str attr: response string to be deserialized. + :return: Deserialized duration + :rtype: TimeDelta + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + duration = isodate.parse_duration(attr) + except (ValueError, OverflowError, AttributeError) as err: + msg = "Cannot deserialize duration object." + raise DeserializationError(msg) from err + return duration + + @staticmethod + def deserialize_date(attr): + """Deserialize ISO-8601 formatted string into Date object. + + :param str attr: response string to be deserialized. + :return: Deserialized date + :rtype: Date + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + if re.search(r"[^\W\d_]", attr, re.I + re.U): # type: ignore + raise DeserializationError("Date must have only digits and -. Received: %s" % attr) + # This must NOT use defaultmonth/defaultday. Using None ensure this raises an exception. + return isodate.parse_date(attr, defaultmonth=0, defaultday=0) + + @staticmethod + def deserialize_time(attr): + """Deserialize ISO-8601 formatted string into time object. + + :param str attr: response string to be deserialized. + :return: Deserialized time + :rtype: datetime.time + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + if re.search(r"[^\W\d_]", attr, re.I + re.U): # type: ignore + raise DeserializationError("Date must have only digits and -. Received: %s" % attr) + return isodate.parse_time(attr) + + @staticmethod + def deserialize_rfc(attr): + """Deserialize RFC-1123 formatted string into Datetime object. + + :param str attr: response string to be deserialized. + :return: Deserialized RFC datetime + :rtype: Datetime + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + parsed_date = email.utils.parsedate_tz(attr) # type: ignore + date_obj = datetime.datetime( + *parsed_date[:6], tzinfo=datetime.timezone(datetime.timedelta(minutes=(parsed_date[9] or 0) / 60)) + ) + if not date_obj.tzinfo: + date_obj = date_obj.astimezone(tz=TZ_UTC) + except ValueError as err: + msg = "Cannot deserialize to rfc datetime object." + raise DeserializationError(msg) from err + return date_obj + + @staticmethod + def deserialize_iso(attr): + """Deserialize ISO-8601 formatted string into Datetime object. + + :param str attr: response string to be deserialized. + :return: Deserialized ISO datetime + :rtype: Datetime + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + attr = attr.upper() # type: ignore + match = Deserializer.valid_date.match(attr) + if not match: + raise ValueError("Invalid datetime string: " + attr) + + check_decimal = attr.split(".") + if len(check_decimal) > 1: + decimal_str = "" + for digit in check_decimal[1]: + if digit.isdigit(): + decimal_str += digit + else: + break + if len(decimal_str) > 6: + attr = attr.replace(decimal_str, decimal_str[0:6]) + + date_obj = isodate.parse_datetime(attr) + test_utc = date_obj.utctimetuple() + if test_utc.tm_year > 9999 or test_utc.tm_year < 1: + raise OverflowError("Hit max or min date") + except (ValueError, OverflowError, AttributeError) as err: + msg = "Cannot deserialize datetime object." + raise DeserializationError(msg) from err + return date_obj + + @staticmethod + def deserialize_unix(attr): + """Serialize Datetime object into IntTime format. + This is represented as seconds. + + :param int attr: Object to be serialized. + :return: Deserialized datetime + :rtype: Datetime + :raises DeserializationError: if format invalid + """ + if isinstance(attr, ET.Element): + attr = int(attr.text) # type: ignore + try: + attr = int(attr) + date_obj = datetime.datetime.fromtimestamp(attr, TZ_UTC) + except ValueError as err: + msg = "Cannot deserialize to unix datetime object." + raise DeserializationError(msg) from err + return date_obj diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyNumberVersionTolerant/bodynumberversiontolerant/aio/_client.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyNumberVersionTolerant/bodynumberversiontolerant/aio/_client.py index 271c8322cf6..d9f1b8e19fb 100644 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyNumberVersionTolerant/bodynumberversiontolerant/aio/_client.py +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyNumberVersionTolerant/bodynumberversiontolerant/aio/_client.py @@ -14,7 +14,7 @@ from azure.core.pipeline import policies from azure.core.rest import AsyncHttpResponse, HttpRequest -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import AutoRestNumberTestServiceConfiguration from .operations import NumberOperations diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyNumberVersionTolerant/bodynumberversiontolerant/aio/operations/_operations.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyNumberVersionTolerant/bodynumberversiontolerant/aio/operations/_operations.py index c7766a88b9e..4b759965006 100644 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyNumberVersionTolerant/bodynumberversiontolerant/aio/operations/_operations.py +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyNumberVersionTolerant/bodynumberversiontolerant/aio/operations/_operations.py @@ -23,7 +23,7 @@ from azure.core.tracing.decorator_async import distributed_trace_async from azure.core.utils import case_insensitive_dict -from ..._serialization import Deserializer, Serializer +from ..._utils.serialization import Deserializer, Serializer from ...operations._operations import ( build_number_get_big_decimal_negative_decimal_request, build_number_get_big_decimal_positive_decimal_request, diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyNumberVersionTolerant/bodynumberversiontolerant/operations/_operations.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyNumberVersionTolerant/bodynumberversiontolerant/operations/_operations.py index aa90eccc7df..5fac0cc2d3f 100644 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyNumberVersionTolerant/bodynumberversiontolerant/operations/_operations.py +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyNumberVersionTolerant/bodynumberversiontolerant/operations/_operations.py @@ -24,7 +24,7 @@ from azure.core.utils import case_insensitive_dict from .._configuration import AutoRestNumberTestServiceConfiguration -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyStringVersionTolerant/bodystringversiontolerant/_client.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyStringVersionTolerant/bodystringversiontolerant/_client.py index 94ec048ec89..2c5711417a3 100644 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyStringVersionTolerant/bodystringversiontolerant/_client.py +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyStringVersionTolerant/bodystringversiontolerant/_client.py @@ -15,7 +15,7 @@ from azure.core.rest import HttpRequest, HttpResponse from ._configuration import AutoRestSwaggerBATServiceConfiguration -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer from .operations import EnumOperations, StringOperations diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyStringVersionTolerant/bodystringversiontolerant/_utils/__init__.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyStringVersionTolerant/bodystringversiontolerant/_utils/__init__.py new file mode 100644 index 00000000000..0af9b28f660 --- /dev/null +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyStringVersionTolerant/bodystringversiontolerant/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyStringVersionTolerant/bodystringversiontolerant/_utils/serialization.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyStringVersionTolerant/bodystringversiontolerant/_utils/serialization.py new file mode 100644 index 00000000000..f5187701d7b --- /dev/null +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyStringVersionTolerant/bodystringversiontolerant/_utils/serialization.py @@ -0,0 +1,2032 @@ +# pylint: disable=line-too-long,useless-suppression,too-many-lines +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +# pyright: reportUnnecessaryTypeIgnoreComment=false + +from base64 import b64decode, b64encode +import calendar +import datetime +import decimal +import email +from enum import Enum +import json +import logging +import re +import sys +import codecs +from typing import ( + Dict, + Any, + cast, + Optional, + Union, + AnyStr, + IO, + Mapping, + Callable, + MutableMapping, + List, +) + +try: + from urllib import quote # type: ignore +except ImportError: + from urllib.parse import quote +import xml.etree.ElementTree as ET + +import isodate # type: ignore +from typing_extensions import Self + +from azure.core.exceptions import DeserializationError, SerializationError +from azure.core.serialization import NULL as CoreNull + +_BOM = codecs.BOM_UTF8.decode(encoding="utf-8") + +JSON = MutableMapping[str, Any] + + +class RawDeserializer: + + # Accept "text" because we're open minded people... + JSON_REGEXP = re.compile(r"^(application|text)/([a-z+.]+\+)?json$") + + # Name used in context + CONTEXT_NAME = "deserialized_data" + + @classmethod + def deserialize_from_text(cls, data: Optional[Union[AnyStr, IO]], content_type: Optional[str] = None) -> Any: + """Decode data according to content-type. + + Accept a stream of data as well, but will be load at once in memory for now. + + If no content-type, will return the string version (not bytes, not stream) + + :param data: Input, could be bytes or stream (will be decoded with UTF8) or text + :type data: str or bytes or IO + :param str content_type: The content type. + :return: The deserialized data. + :rtype: object + """ + if hasattr(data, "read"): + # Assume a stream + data = cast(IO, data).read() + + if isinstance(data, bytes): + data_as_str = data.decode(encoding="utf-8-sig") + else: + # Explain to mypy the correct type. + data_as_str = cast(str, data) + + # Remove Byte Order Mark if present in string + data_as_str = data_as_str.lstrip(_BOM) + + if content_type is None: + return data + + if cls.JSON_REGEXP.match(content_type): + try: + return json.loads(data_as_str) + except ValueError as err: + raise DeserializationError("JSON is invalid: {}".format(err), err) from err + elif "xml" in (content_type or []): + try: + + try: + if isinstance(data, unicode): # type: ignore + # If I'm Python 2.7 and unicode XML will scream if I try a "fromstring" on unicode string + data_as_str = data_as_str.encode(encoding="utf-8") # type: ignore + except NameError: + pass + + return ET.fromstring(data_as_str) # nosec + except ET.ParseError as err: + # It might be because the server has an issue, and returned JSON with + # content-type XML.... + # So let's try a JSON load, and if it's still broken + # let's flow the initial exception + def _json_attemp(data): + try: + return True, json.loads(data) + except ValueError: + return False, None # Don't care about this one + + success, json_result = _json_attemp(data) + if success: + return json_result + # If i'm here, it's not JSON, it's not XML, let's scream + # and raise the last context in this block (the XML exception) + # The function hack is because Py2.7 messes up with exception + # context otherwise. + _LOGGER.critical("Wasn't XML not JSON, failing") + raise DeserializationError("XML is invalid") from err + elif content_type.startswith("text/"): + return data_as_str + raise DeserializationError("Cannot deserialize content-type: {}".format(content_type)) + + @classmethod + def deserialize_from_http_generics(cls, body_bytes: Optional[Union[AnyStr, IO]], headers: Mapping) -> Any: + """Deserialize from HTTP response. + + Use bytes and headers to NOT use any requests/aiohttp or whatever + specific implementation. + Headers will tested for "content-type" + + :param bytes body_bytes: The body of the response. + :param dict headers: The headers of the response. + :returns: The deserialized data. + :rtype: object + """ + # Try to use content-type from headers if available + content_type = None + if "content-type" in headers: + content_type = headers["content-type"].split(";")[0].strip().lower() + # Ouch, this server did not declare what it sent... + # Let's guess it's JSON... + # Also, since Autorest was considering that an empty body was a valid JSON, + # need that test as well.... + else: + content_type = "application/json" + + if body_bytes: + return cls.deserialize_from_text(body_bytes, content_type) + return None + + +_LOGGER = logging.getLogger(__name__) + +try: + _long_type = long # type: ignore +except NameError: + _long_type = int + +TZ_UTC = datetime.timezone.utc + +_FLATTEN = re.compile(r"(? None: + self.additional_properties: Optional[Dict[str, Any]] = {} + for k in kwargs: # pylint: disable=consider-using-dict-items + if k not in self._attribute_map: + _LOGGER.warning("%s is not a known attribute of class %s and will be ignored", k, self.__class__) + elif k in self._validation and self._validation[k].get("readonly", False): + _LOGGER.warning("Readonly attribute %s will be ignored in class %s", k, self.__class__) + else: + setattr(self, k, kwargs[k]) + + def __eq__(self, other: Any) -> bool: + """Compare objects by comparing all attributes. + + :param object other: The object to compare + :returns: True if objects are equal + :rtype: bool + """ + if isinstance(other, self.__class__): + return self.__dict__ == other.__dict__ + return False + + def __ne__(self, other: Any) -> bool: + """Compare objects by comparing all attributes. + + :param object other: The object to compare + :returns: True if objects are not equal + :rtype: bool + """ + return not self.__eq__(other) + + def __str__(self) -> str: + return str(self.__dict__) + + @classmethod + def enable_additional_properties_sending(cls) -> None: + cls._attribute_map["additional_properties"] = {"key": "", "type": "{object}"} + + @classmethod + def is_xml_model(cls) -> bool: + try: + cls._xml_map # type: ignore + except AttributeError: + return False + return True + + @classmethod + def _create_xml_node(cls): + """Create XML node. + + :returns: The XML node + :rtype: xml.etree.ElementTree.Element + """ + try: + xml_map = cls._xml_map # type: ignore + except AttributeError: + xml_map = {} + + return _create_xml_node(xml_map.get("name", cls.__name__), xml_map.get("prefix", None), xml_map.get("ns", None)) + + def serialize(self, keep_readonly: bool = False, **kwargs: Any) -> JSON: + """Return the JSON that would be sent to server from this model. + + This is an alias to `as_dict(full_restapi_key_transformer, keep_readonly=False)`. + + If you want XML serialization, you can pass the kwargs is_xml=True. + + :param bool keep_readonly: If you want to serialize the readonly attributes + :returns: A dict JSON compatible object + :rtype: dict + """ + serializer = Serializer(self._infer_class_models()) + return serializer._serialize( # type: ignore # pylint: disable=protected-access + self, keep_readonly=keep_readonly, **kwargs + ) + + def as_dict( + self, + keep_readonly: bool = True, + key_transformer: Callable[[str, Dict[str, Any], Any], Any] = attribute_transformer, + **kwargs: Any + ) -> JSON: + """Return a dict that can be serialized using json.dump. + + Advanced usage might optionally use a callback as parameter: + + .. code::python + + def my_key_transformer(key, attr_desc, value): + return key + + Key is the attribute name used in Python. Attr_desc + is a dict of metadata. Currently contains 'type' with the + msrest type and 'key' with the RestAPI encoded key. + Value is the current value in this object. + + The string returned will be used to serialize the key. + If the return type is a list, this is considered hierarchical + result dict. + + See the three examples in this file: + + - attribute_transformer + - full_restapi_key_transformer + - last_restapi_key_transformer + + If you want XML serialization, you can pass the kwargs is_xml=True. + + :param bool keep_readonly: If you want to serialize the readonly attributes + :param function key_transformer: A key transformer function. + :returns: A dict JSON compatible object + :rtype: dict + """ + serializer = Serializer(self._infer_class_models()) + return serializer._serialize( # type: ignore # pylint: disable=protected-access + self, key_transformer=key_transformer, keep_readonly=keep_readonly, **kwargs + ) + + @classmethod + def _infer_class_models(cls): + try: + str_models = cls.__module__.rsplit(".", 1)[0] + models = sys.modules[str_models] + client_models = {k: v for k, v in models.__dict__.items() if isinstance(v, type)} + if cls.__name__ not in client_models: + raise ValueError("Not Autorest generated code") + except Exception: # pylint: disable=broad-exception-caught + # Assume it's not Autorest generated (tests?). Add ourselves as dependencies. + client_models = {cls.__name__: cls} + return client_models + + @classmethod + def deserialize(cls, data: Any, content_type: Optional[str] = None) -> Self: + """Parse a str using the RestAPI syntax and return a model. + + :param str data: A str using RestAPI structure. JSON by default. + :param str content_type: JSON by default, set application/xml if XML. + :returns: An instance of this model + :raises DeserializationError: if something went wrong + :rtype: Self + """ + deserializer = Deserializer(cls._infer_class_models()) + return deserializer(cls.__name__, data, content_type=content_type) # type: ignore + + @classmethod + def from_dict( + cls, + data: Any, + key_extractors: Optional[Callable[[str, Dict[str, Any], Any], Any]] = None, + content_type: Optional[str] = None, + ) -> Self: + """Parse a dict using given key extractor return a model. + + By default consider key + extractors (rest_key_case_insensitive_extractor, attribute_key_case_insensitive_extractor + and last_rest_key_case_insensitive_extractor) + + :param dict data: A dict using RestAPI structure + :param function key_extractors: A key extractor function. + :param str content_type: JSON by default, set application/xml if XML. + :returns: An instance of this model + :raises DeserializationError: if something went wrong + :rtype: Self + """ + deserializer = Deserializer(cls._infer_class_models()) + deserializer.key_extractors = ( # type: ignore + [ # type: ignore + attribute_key_case_insensitive_extractor, + rest_key_case_insensitive_extractor, + last_rest_key_case_insensitive_extractor, + ] + if key_extractors is None + else key_extractors + ) + return deserializer(cls.__name__, data, content_type=content_type) # type: ignore + + @classmethod + def _flatten_subtype(cls, key, objects): + if "_subtype_map" not in cls.__dict__: + return {} + result = dict(cls._subtype_map[key]) + for valuetype in cls._subtype_map[key].values(): + result.update(objects[valuetype]._flatten_subtype(key, objects)) # pylint: disable=protected-access + return result + + @classmethod + def _classify(cls, response, objects): + """Check the class _subtype_map for any child classes. + We want to ignore any inherited _subtype_maps. + + :param dict response: The initial data + :param dict objects: The class objects + :returns: The class to be used + :rtype: class + """ + for subtype_key in cls.__dict__.get("_subtype_map", {}).keys(): + subtype_value = None + + if not isinstance(response, ET.Element): + rest_api_response_key = cls._get_rest_key_parts(subtype_key)[-1] + subtype_value = response.get(rest_api_response_key, None) or response.get(subtype_key, None) + else: + subtype_value = xml_key_extractor(subtype_key, cls._attribute_map[subtype_key], response) + if subtype_value: + # Try to match base class. Can be class name only + # (bug to fix in Autorest to support x-ms-discriminator-name) + if cls.__name__ == subtype_value: + return cls + flatten_mapping_type = cls._flatten_subtype(subtype_key, objects) + try: + return objects[flatten_mapping_type[subtype_value]] # type: ignore + except KeyError: + _LOGGER.warning( + "Subtype value %s has no mapping, use base class %s.", + subtype_value, + cls.__name__, + ) + break + else: + _LOGGER.warning("Discriminator %s is absent or null, use base class %s.", subtype_key, cls.__name__) + break + return cls + + @classmethod + def _get_rest_key_parts(cls, attr_key): + """Get the RestAPI key of this attr, split it and decode part + :param str attr_key: Attribute key must be in attribute_map. + :returns: A list of RestAPI part + :rtype: list + """ + rest_split_key = _FLATTEN.split(cls._attribute_map[attr_key]["key"]) + return [_decode_attribute_map_key(key_part) for key_part in rest_split_key] + + +def _decode_attribute_map_key(key): + """This decode a key in an _attribute_map to the actual key we want to look at + inside the received data. + + :param str key: A key string from the generated code + :returns: The decoded key + :rtype: str + """ + return key.replace("\\.", ".") + + +class Serializer: # pylint: disable=too-many-public-methods + """Request object model serializer.""" + + basic_types = {str: "str", int: "int", bool: "bool", float: "float"} + + _xml_basic_types_serializers = {"bool": lambda x: str(x).lower()} + days = {0: "Mon", 1: "Tue", 2: "Wed", 3: "Thu", 4: "Fri", 5: "Sat", 6: "Sun"} + months = { + 1: "Jan", + 2: "Feb", + 3: "Mar", + 4: "Apr", + 5: "May", + 6: "Jun", + 7: "Jul", + 8: "Aug", + 9: "Sep", + 10: "Oct", + 11: "Nov", + 12: "Dec", + } + validation = { + "min_length": lambda x, y: len(x) < y, + "max_length": lambda x, y: len(x) > y, + "minimum": lambda x, y: x < y, + "maximum": lambda x, y: x > y, + "minimum_ex": lambda x, y: x <= y, + "maximum_ex": lambda x, y: x >= y, + "min_items": lambda x, y: len(x) < y, + "max_items": lambda x, y: len(x) > y, + "pattern": lambda x, y: not re.match(y, x, re.UNICODE), + "unique": lambda x, y: len(x) != len(set(x)), + "multiple": lambda x, y: x % y != 0, + } + + def __init__(self, classes: Optional[Mapping[str, type]] = None) -> None: + self.serialize_type = { + "iso-8601": Serializer.serialize_iso, + "rfc-1123": Serializer.serialize_rfc, + "unix-time": Serializer.serialize_unix, + "duration": Serializer.serialize_duration, + "date": Serializer.serialize_date, + "time": Serializer.serialize_time, + "decimal": Serializer.serialize_decimal, + "long": Serializer.serialize_long, + "bytearray": Serializer.serialize_bytearray, + "base64": Serializer.serialize_base64, + "object": self.serialize_object, + "[]": self.serialize_iter, + "{}": self.serialize_dict, + } + self.dependencies: Dict[str, type] = dict(classes) if classes else {} + self.key_transformer = full_restapi_key_transformer + self.client_side_validation = True + + def _serialize( # pylint: disable=too-many-nested-blocks, too-many-branches, too-many-statements, too-many-locals + self, target_obj, data_type=None, **kwargs + ): + """Serialize data into a string according to type. + + :param object target_obj: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str, dict + :raises SerializationError: if serialization fails. + :returns: The serialized data. + """ + key_transformer = kwargs.get("key_transformer", self.key_transformer) + keep_readonly = kwargs.get("keep_readonly", False) + if target_obj is None: + return None + + attr_name = None + class_name = target_obj.__class__.__name__ + + if data_type: + return self.serialize_data(target_obj, data_type, **kwargs) + + if not hasattr(target_obj, "_attribute_map"): + data_type = type(target_obj).__name__ + if data_type in self.basic_types.values(): + return self.serialize_data(target_obj, data_type, **kwargs) + + # Force "is_xml" kwargs if we detect a XML model + try: + is_xml_model_serialization = kwargs["is_xml"] + except KeyError: + is_xml_model_serialization = kwargs.setdefault("is_xml", target_obj.is_xml_model()) + + serialized = {} + if is_xml_model_serialization: + serialized = target_obj._create_xml_node() # pylint: disable=protected-access + try: + attributes = target_obj._attribute_map # pylint: disable=protected-access + for attr, attr_desc in attributes.items(): + attr_name = attr + if not keep_readonly and target_obj._validation.get( # pylint: disable=protected-access + attr_name, {} + ).get("readonly", False): + continue + + if attr_name == "additional_properties" and attr_desc["key"] == "": + if target_obj.additional_properties is not None: + serialized.update(target_obj.additional_properties) + continue + try: + + orig_attr = getattr(target_obj, attr) + if is_xml_model_serialization: + pass # Don't provide "transformer" for XML for now. Keep "orig_attr" + else: # JSON + keys, orig_attr = key_transformer(attr, attr_desc.copy(), orig_attr) + keys = keys if isinstance(keys, list) else [keys] + + kwargs["serialization_ctxt"] = attr_desc + new_attr = self.serialize_data(orig_attr, attr_desc["type"], **kwargs) + + if is_xml_model_serialization: + xml_desc = attr_desc.get("xml", {}) + xml_name = xml_desc.get("name", attr_desc["key"]) + xml_prefix = xml_desc.get("prefix", None) + xml_ns = xml_desc.get("ns", None) + if xml_desc.get("attr", False): + if xml_ns: + ET.register_namespace(xml_prefix, xml_ns) + xml_name = "{{{}}}{}".format(xml_ns, xml_name) + serialized.set(xml_name, new_attr) # type: ignore + continue + if xml_desc.get("text", False): + serialized.text = new_attr # type: ignore + continue + if isinstance(new_attr, list): + serialized.extend(new_attr) # type: ignore + elif isinstance(new_attr, ET.Element): + # If the down XML has no XML/Name, + # we MUST replace the tag with the local tag. But keeping the namespaces. + if "name" not in getattr(orig_attr, "_xml_map", {}): + splitted_tag = new_attr.tag.split("}") + if len(splitted_tag) == 2: # Namespace + new_attr.tag = "}".join([splitted_tag[0], xml_name]) + else: + new_attr.tag = xml_name + serialized.append(new_attr) # type: ignore + else: # That's a basic type + # Integrate namespace if necessary + local_node = _create_xml_node(xml_name, xml_prefix, xml_ns) + local_node.text = str(new_attr) + serialized.append(local_node) # type: ignore + else: # JSON + for k in reversed(keys): # type: ignore + new_attr = {k: new_attr} + + _new_attr = new_attr + _serialized = serialized + for k in keys: # type: ignore + if k not in _serialized: + _serialized.update(_new_attr) # type: ignore + _new_attr = _new_attr[k] # type: ignore + _serialized = _serialized[k] + except ValueError as err: + if isinstance(err, SerializationError): + raise + + except (AttributeError, KeyError, TypeError) as err: + msg = "Attribute {} in object {} cannot be serialized.\n{}".format(attr_name, class_name, str(target_obj)) + raise SerializationError(msg) from err + return serialized + + def body(self, data, data_type, **kwargs): + """Serialize data intended for a request body. + + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: dict + :raises SerializationError: if serialization fails. + :raises ValueError: if data is None + :returns: The serialized request body + """ + + # Just in case this is a dict + internal_data_type_str = data_type.strip("[]{}") + internal_data_type = self.dependencies.get(internal_data_type_str, None) + try: + is_xml_model_serialization = kwargs["is_xml"] + except KeyError: + if internal_data_type and issubclass(internal_data_type, Model): + is_xml_model_serialization = kwargs.setdefault("is_xml", internal_data_type.is_xml_model()) + else: + is_xml_model_serialization = False + if internal_data_type and not isinstance(internal_data_type, Enum): + try: + deserializer = Deserializer(self.dependencies) + # Since it's on serialization, it's almost sure that format is not JSON REST + # We're not able to deal with additional properties for now. + deserializer.additional_properties_detection = False + if is_xml_model_serialization: + deserializer.key_extractors = [ # type: ignore + attribute_key_case_insensitive_extractor, + ] + else: + deserializer.key_extractors = [ + rest_key_case_insensitive_extractor, + attribute_key_case_insensitive_extractor, + last_rest_key_case_insensitive_extractor, + ] + data = deserializer._deserialize(data_type, data) # pylint: disable=protected-access + except DeserializationError as err: + raise SerializationError("Unable to build a model: " + str(err)) from err + + return self._serialize(data, data_type, **kwargs) + + def url(self, name, data, data_type, **kwargs): + """Serialize data intended for a URL path. + + :param str name: The name of the URL path parameter. + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str + :returns: The serialized URL path + :raises TypeError: if serialization fails. + :raises ValueError: if data is None + """ + try: + output = self.serialize_data(data, data_type, **kwargs) + if data_type == "bool": + output = json.dumps(output) + + if kwargs.get("skip_quote") is True: + output = str(output) + output = output.replace("{", quote("{")).replace("}", quote("}")) + else: + output = quote(str(output), safe="") + except SerializationError as exc: + raise TypeError("{} must be type {}.".format(name, data_type)) from exc + return output + + def query(self, name, data, data_type, **kwargs): + """Serialize data intended for a URL query. + + :param str name: The name of the query parameter. + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str, list + :raises TypeError: if serialization fails. + :raises ValueError: if data is None + :returns: The serialized query parameter + """ + try: + # Treat the list aside, since we don't want to encode the div separator + if data_type.startswith("["): + internal_data_type = data_type[1:-1] + do_quote = not kwargs.get("skip_quote", False) + return self.serialize_iter(data, internal_data_type, do_quote=do_quote, **kwargs) + + # Not a list, regular serialization + output = self.serialize_data(data, data_type, **kwargs) + if data_type == "bool": + output = json.dumps(output) + if kwargs.get("skip_quote") is True: + output = str(output) + else: + output = quote(str(output), safe="") + except SerializationError as exc: + raise TypeError("{} must be type {}.".format(name, data_type)) from exc + return str(output) + + def header(self, name, data, data_type, **kwargs): + """Serialize data intended for a request header. + + :param str name: The name of the header. + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str + :raises TypeError: if serialization fails. + :raises ValueError: if data is None + :returns: The serialized header + """ + try: + if data_type in ["[str]"]: + data = ["" if d is None else d for d in data] + + output = self.serialize_data(data, data_type, **kwargs) + if data_type == "bool": + output = json.dumps(output) + except SerializationError as exc: + raise TypeError("{} must be type {}.".format(name, data_type)) from exc + return str(output) + + def serialize_data(self, data, data_type, **kwargs): + """Serialize generic data according to supplied data type. + + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :raises AttributeError: if required data is None. + :raises ValueError: if data is None + :raises SerializationError: if serialization fails. + :returns: The serialized data. + :rtype: str, int, float, bool, dict, list + """ + if data is None: + raise ValueError("No value for given attribute") + + try: + if data is CoreNull: + return None + if data_type in self.basic_types.values(): + return self.serialize_basic(data, data_type, **kwargs) + + if data_type in self.serialize_type: + return self.serialize_type[data_type](data, **kwargs) + + # If dependencies is empty, try with current data class + # It has to be a subclass of Enum anyway + enum_type = self.dependencies.get(data_type, data.__class__) + if issubclass(enum_type, Enum): + return Serializer.serialize_enum(data, enum_obj=enum_type) + + iter_type = data_type[0] + data_type[-1] + if iter_type in self.serialize_type: + return self.serialize_type[iter_type](data, data_type[1:-1], **kwargs) + + except (ValueError, TypeError) as err: + msg = "Unable to serialize value: {!r} as type: {!r}." + raise SerializationError(msg.format(data, data_type)) from err + return self._serialize(data, **kwargs) + + @classmethod + def _get_custom_serializers(cls, data_type, **kwargs): # pylint: disable=inconsistent-return-statements + custom_serializer = kwargs.get("basic_types_serializers", {}).get(data_type) + if custom_serializer: + return custom_serializer + if kwargs.get("is_xml", False): + return cls._xml_basic_types_serializers.get(data_type) + + @classmethod + def serialize_basic(cls, data, data_type, **kwargs): + """Serialize basic builting data type. + Serializes objects to str, int, float or bool. + + Possible kwargs: + - basic_types_serializers dict[str, callable] : If set, use the callable as serializer + - is_xml bool : If set, use xml_basic_types_serializers + + :param obj data: Object to be serialized. + :param str data_type: Type of object in the iterable. + :rtype: str, int, float, bool + :return: serialized object + """ + custom_serializer = cls._get_custom_serializers(data_type, **kwargs) + if custom_serializer: + return custom_serializer(data) + if data_type == "str": + return cls.serialize_unicode(data) + return eval(data_type)(data) # nosec # pylint: disable=eval-used + + @classmethod + def serialize_unicode(cls, data): + """Special handling for serializing unicode strings in Py2. + Encode to UTF-8 if unicode, otherwise handle as a str. + + :param str data: Object to be serialized. + :rtype: str + :return: serialized object + """ + try: # If I received an enum, return its value + return data.value + except AttributeError: + pass + + try: + if isinstance(data, unicode): # type: ignore + # Don't change it, JSON and XML ElementTree are totally able + # to serialize correctly u'' strings + return data + except NameError: + return str(data) + return str(data) + + def serialize_iter(self, data, iter_type, div=None, **kwargs): + """Serialize iterable. + + Supported kwargs: + - serialization_ctxt dict : The current entry of _attribute_map, or same format. + serialization_ctxt['type'] should be same as data_type. + - is_xml bool : If set, serialize as XML + + :param list data: Object to be serialized. + :param str iter_type: Type of object in the iterable. + :param str div: If set, this str will be used to combine the elements + in the iterable into a combined string. Default is 'None'. + Defaults to False. + :rtype: list, str + :return: serialized iterable + """ + if isinstance(data, str): + raise SerializationError("Refuse str type as a valid iter type.") + + serialization_ctxt = kwargs.get("serialization_ctxt", {}) + is_xml = kwargs.get("is_xml", False) + + serialized = [] + for d in data: + try: + serialized.append(self.serialize_data(d, iter_type, **kwargs)) + except ValueError as err: + if isinstance(err, SerializationError): + raise + serialized.append(None) + + if kwargs.get("do_quote", False): + serialized = ["" if s is None else quote(str(s), safe="") for s in serialized] + + if div: + serialized = ["" if s is None else str(s) for s in serialized] + serialized = div.join(serialized) + + if "xml" in serialization_ctxt or is_xml: + # XML serialization is more complicated + xml_desc = serialization_ctxt.get("xml", {}) + xml_name = xml_desc.get("name") + if not xml_name: + xml_name = serialization_ctxt["key"] + + # Create a wrap node if necessary (use the fact that Element and list have "append") + is_wrapped = xml_desc.get("wrapped", False) + node_name = xml_desc.get("itemsName", xml_name) + if is_wrapped: + final_result = _create_xml_node(xml_name, xml_desc.get("prefix", None), xml_desc.get("ns", None)) + else: + final_result = [] + # All list elements to "local_node" + for el in serialized: + if isinstance(el, ET.Element): + el_node = el + else: + el_node = _create_xml_node(node_name, xml_desc.get("prefix", None), xml_desc.get("ns", None)) + if el is not None: # Otherwise it writes "None" :-p + el_node.text = str(el) + final_result.append(el_node) + return final_result + return serialized + + def serialize_dict(self, attr, dict_type, **kwargs): + """Serialize a dictionary of objects. + + :param dict attr: Object to be serialized. + :param str dict_type: Type of object in the dictionary. + :rtype: dict + :return: serialized dictionary + """ + serialization_ctxt = kwargs.get("serialization_ctxt", {}) + serialized = {} + for key, value in attr.items(): + try: + serialized[self.serialize_unicode(key)] = self.serialize_data(value, dict_type, **kwargs) + except ValueError as err: + if isinstance(err, SerializationError): + raise + serialized[self.serialize_unicode(key)] = None + + if "xml" in serialization_ctxt: + # XML serialization is more complicated + xml_desc = serialization_ctxt["xml"] + xml_name = xml_desc["name"] + + final_result = _create_xml_node(xml_name, xml_desc.get("prefix", None), xml_desc.get("ns", None)) + for key, value in serialized.items(): + ET.SubElement(final_result, key).text = value + return final_result + + return serialized + + def serialize_object(self, attr, **kwargs): # pylint: disable=too-many-return-statements + """Serialize a generic object. + This will be handled as a dictionary. If object passed in is not + a basic type (str, int, float, dict, list) it will simply be + cast to str. + + :param dict attr: Object to be serialized. + :rtype: dict or str + :return: serialized object + """ + if attr is None: + return None + if isinstance(attr, ET.Element): + return attr + obj_type = type(attr) + if obj_type in self.basic_types: + return self.serialize_basic(attr, self.basic_types[obj_type], **kwargs) + if obj_type is _long_type: + return self.serialize_long(attr) + if obj_type is str: + return self.serialize_unicode(attr) + if obj_type is datetime.datetime: + return self.serialize_iso(attr) + if obj_type is datetime.date: + return self.serialize_date(attr) + if obj_type is datetime.time: + return self.serialize_time(attr) + if obj_type is datetime.timedelta: + return self.serialize_duration(attr) + if obj_type is decimal.Decimal: + return self.serialize_decimal(attr) + + # If it's a model or I know this dependency, serialize as a Model + if obj_type in self.dependencies.values() or isinstance(attr, Model): + return self._serialize(attr) + + if obj_type == dict: + serialized = {} + for key, value in attr.items(): + try: + serialized[self.serialize_unicode(key)] = self.serialize_object(value, **kwargs) + except ValueError: + serialized[self.serialize_unicode(key)] = None + return serialized + + if obj_type == list: + serialized = [] + for obj in attr: + try: + serialized.append(self.serialize_object(obj, **kwargs)) + except ValueError: + pass + return serialized + return str(attr) + + @staticmethod + def serialize_enum(attr, enum_obj=None): + try: + result = attr.value + except AttributeError: + result = attr + try: + enum_obj(result) # type: ignore + return result + except ValueError as exc: + for enum_value in enum_obj: # type: ignore + if enum_value.value.lower() == str(attr).lower(): + return enum_value.value + error = "{!r} is not valid value for enum {!r}" + raise SerializationError(error.format(attr, enum_obj)) from exc + + @staticmethod + def serialize_bytearray(attr, **kwargs): # pylint: disable=unused-argument + """Serialize bytearray into base-64 string. + + :param str attr: Object to be serialized. + :rtype: str + :return: serialized base64 + """ + return b64encode(attr).decode() + + @staticmethod + def serialize_base64(attr, **kwargs): # pylint: disable=unused-argument + """Serialize str into base-64 string. + + :param str attr: Object to be serialized. + :rtype: str + :return: serialized base64 + """ + encoded = b64encode(attr).decode("ascii") + return encoded.strip("=").replace("+", "-").replace("/", "_") + + @staticmethod + def serialize_decimal(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Decimal object to float. + + :param decimal attr: Object to be serialized. + :rtype: float + :return: serialized decimal + """ + return float(attr) + + @staticmethod + def serialize_long(attr, **kwargs): # pylint: disable=unused-argument + """Serialize long (Py2) or int (Py3). + + :param int attr: Object to be serialized. + :rtype: int/long + :return: serialized long + """ + return _long_type(attr) + + @staticmethod + def serialize_date(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Date object into ISO-8601 formatted string. + + :param Date attr: Object to be serialized. + :rtype: str + :return: serialized date + """ + if isinstance(attr, str): + attr = isodate.parse_date(attr) + t = "{:04}-{:02}-{:02}".format(attr.year, attr.month, attr.day) + return t + + @staticmethod + def serialize_time(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Time object into ISO-8601 formatted string. + + :param datetime.time attr: Object to be serialized. + :rtype: str + :return: serialized time + """ + if isinstance(attr, str): + attr = isodate.parse_time(attr) + t = "{:02}:{:02}:{:02}".format(attr.hour, attr.minute, attr.second) + if attr.microsecond: + t += ".{:02}".format(attr.microsecond) + return t + + @staticmethod + def serialize_duration(attr, **kwargs): # pylint: disable=unused-argument + """Serialize TimeDelta object into ISO-8601 formatted string. + + :param TimeDelta attr: Object to be serialized. + :rtype: str + :return: serialized duration + """ + if isinstance(attr, str): + attr = isodate.parse_duration(attr) + return isodate.duration_isoformat(attr) + + @staticmethod + def serialize_rfc(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Datetime object into RFC-1123 formatted string. + + :param Datetime attr: Object to be serialized. + :rtype: str + :raises TypeError: if format invalid. + :return: serialized rfc + """ + try: + if not attr.tzinfo: + _LOGGER.warning("Datetime with no tzinfo will be considered UTC.") + utc = attr.utctimetuple() + except AttributeError as exc: + raise TypeError("RFC1123 object must be valid Datetime object.") from exc + + return "{}, {:02} {} {:04} {:02}:{:02}:{:02} GMT".format( + Serializer.days[utc.tm_wday], + utc.tm_mday, + Serializer.months[utc.tm_mon], + utc.tm_year, + utc.tm_hour, + utc.tm_min, + utc.tm_sec, + ) + + @staticmethod + def serialize_iso(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Datetime object into ISO-8601 formatted string. + + :param Datetime attr: Object to be serialized. + :rtype: str + :raises SerializationError: if format invalid. + :return: serialized iso + """ + if isinstance(attr, str): + attr = isodate.parse_datetime(attr) + try: + if not attr.tzinfo: + _LOGGER.warning("Datetime with no tzinfo will be considered UTC.") + utc = attr.utctimetuple() + if utc.tm_year > 9999 or utc.tm_year < 1: + raise OverflowError("Hit max or min date") + + microseconds = str(attr.microsecond).rjust(6, "0").rstrip("0").ljust(3, "0") + if microseconds: + microseconds = "." + microseconds + date = "{:04}-{:02}-{:02}T{:02}:{:02}:{:02}".format( + utc.tm_year, utc.tm_mon, utc.tm_mday, utc.tm_hour, utc.tm_min, utc.tm_sec + ) + return date + microseconds + "Z" + except (ValueError, OverflowError) as err: + msg = "Unable to serialize datetime object." + raise SerializationError(msg) from err + except AttributeError as err: + msg = "ISO-8601 object must be valid Datetime object." + raise TypeError(msg) from err + + @staticmethod + def serialize_unix(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Datetime object into IntTime format. + This is represented as seconds. + + :param Datetime attr: Object to be serialized. + :rtype: int + :raises SerializationError: if format invalid + :return: serialied unix + """ + if isinstance(attr, int): + return attr + try: + if not attr.tzinfo: + _LOGGER.warning("Datetime with no tzinfo will be considered UTC.") + return int(calendar.timegm(attr.utctimetuple())) + except AttributeError as exc: + raise TypeError("Unix time object must be valid Datetime object.") from exc + + +def rest_key_extractor(attr, attr_desc, data): # pylint: disable=unused-argument + key = attr_desc["key"] + working_data = data + + while "." in key: + # Need the cast, as for some reasons "split" is typed as list[str | Any] + dict_keys = cast(List[str], _FLATTEN.split(key)) + if len(dict_keys) == 1: + key = _decode_attribute_map_key(dict_keys[0]) + break + working_key = _decode_attribute_map_key(dict_keys[0]) + working_data = working_data.get(working_key, data) + if working_data is None: + # If at any point while following flatten JSON path see None, it means + # that all properties under are None as well + return None + key = ".".join(dict_keys[1:]) + + return working_data.get(key) + + +def rest_key_case_insensitive_extractor( # pylint: disable=unused-argument, inconsistent-return-statements + attr, attr_desc, data +): + key = attr_desc["key"] + working_data = data + + while "." in key: + dict_keys = _FLATTEN.split(key) + if len(dict_keys) == 1: + key = _decode_attribute_map_key(dict_keys[0]) + break + working_key = _decode_attribute_map_key(dict_keys[0]) + working_data = attribute_key_case_insensitive_extractor(working_key, None, working_data) + if working_data is None: + # If at any point while following flatten JSON path see None, it means + # that all properties under are None as well + return None + key = ".".join(dict_keys[1:]) + + if working_data: + return attribute_key_case_insensitive_extractor(key, None, working_data) + + +def last_rest_key_extractor(attr, attr_desc, data): # pylint: disable=unused-argument + """Extract the attribute in "data" based on the last part of the JSON path key. + + :param str attr: The attribute to extract + :param dict attr_desc: The attribute description + :param dict data: The data to extract from + :rtype: object + :returns: The extracted attribute + """ + key = attr_desc["key"] + dict_keys = _FLATTEN.split(key) + return attribute_key_extractor(dict_keys[-1], None, data) + + +def last_rest_key_case_insensitive_extractor(attr, attr_desc, data): # pylint: disable=unused-argument + """Extract the attribute in "data" based on the last part of the JSON path key. + + This is the case insensitive version of "last_rest_key_extractor" + :param str attr: The attribute to extract + :param dict attr_desc: The attribute description + :param dict data: The data to extract from + :rtype: object + :returns: The extracted attribute + """ + key = attr_desc["key"] + dict_keys = _FLATTEN.split(key) + return attribute_key_case_insensitive_extractor(dict_keys[-1], None, data) + + +def attribute_key_extractor(attr, _, data): + return data.get(attr) + + +def attribute_key_case_insensitive_extractor(attr, _, data): + found_key = None + lower_attr = attr.lower() + for key in data: + if lower_attr == key.lower(): + found_key = key + break + + return data.get(found_key) + + +def _extract_name_from_internal_type(internal_type): + """Given an internal type XML description, extract correct XML name with namespace. + + :param dict internal_type: An model type + :rtype: tuple + :returns: A tuple XML name + namespace dict + """ + internal_type_xml_map = getattr(internal_type, "_xml_map", {}) + xml_name = internal_type_xml_map.get("name", internal_type.__name__) + xml_ns = internal_type_xml_map.get("ns", None) + if xml_ns: + xml_name = "{{{}}}{}".format(xml_ns, xml_name) + return xml_name + + +def xml_key_extractor(attr, attr_desc, data): # pylint: disable=unused-argument,too-many-return-statements + if isinstance(data, dict): + return None + + # Test if this model is XML ready first + if not isinstance(data, ET.Element): + return None + + xml_desc = attr_desc.get("xml", {}) + xml_name = xml_desc.get("name", attr_desc["key"]) + + # Look for a children + is_iter_type = attr_desc["type"].startswith("[") + is_wrapped = xml_desc.get("wrapped", False) + internal_type = attr_desc.get("internalType", None) + internal_type_xml_map = getattr(internal_type, "_xml_map", {}) + + # Integrate namespace if necessary + xml_ns = xml_desc.get("ns", internal_type_xml_map.get("ns", None)) + if xml_ns: + xml_name = "{{{}}}{}".format(xml_ns, xml_name) + + # If it's an attribute, that's simple + if xml_desc.get("attr", False): + return data.get(xml_name) + + # If it's x-ms-text, that's simple too + if xml_desc.get("text", False): + return data.text + + # Scenario where I take the local name: + # - Wrapped node + # - Internal type is an enum (considered basic types) + # - Internal type has no XML/Name node + if is_wrapped or (internal_type and (issubclass(internal_type, Enum) or "name" not in internal_type_xml_map)): + children = data.findall(xml_name) + # If internal type has a local name and it's not a list, I use that name + elif not is_iter_type and internal_type and "name" in internal_type_xml_map: + xml_name = _extract_name_from_internal_type(internal_type) + children = data.findall(xml_name) + # That's an array + else: + if internal_type: # Complex type, ignore itemsName and use the complex type name + items_name = _extract_name_from_internal_type(internal_type) + else: + items_name = xml_desc.get("itemsName", xml_name) + children = data.findall(items_name) + + if len(children) == 0: + if is_iter_type: + if is_wrapped: + return None # is_wrapped no node, we want None + return [] # not wrapped, assume empty list + return None # Assume it's not there, maybe an optional node. + + # If is_iter_type and not wrapped, return all found children + if is_iter_type: + if not is_wrapped: + return children + # Iter and wrapped, should have found one node only (the wrap one) + if len(children) != 1: + raise DeserializationError( + "Tried to deserialize an array not wrapped, and found several nodes '{}'. Maybe you should declare this array as wrapped?".format( + xml_name + ) + ) + return list(children[0]) # Might be empty list and that's ok. + + # Here it's not a itertype, we should have found one element only or empty + if len(children) > 1: + raise DeserializationError("Find several XML '{}' where it was not expected".format(xml_name)) + return children[0] + + +class Deserializer: + """Response object model deserializer. + + :param dict classes: Class type dictionary for deserializing complex types. + :ivar list key_extractors: Ordered list of extractors to be used by this deserializer. + """ + + basic_types = {str: "str", int: "int", bool: "bool", float: "float"} + + valid_date = re.compile(r"\d{4}[-]\d{2}[-]\d{2}T\d{2}:\d{2}:\d{2}\.?\d*Z?[-+]?[\d{2}]?:?[\d{2}]?") + + def __init__(self, classes: Optional[Mapping[str, type]] = None) -> None: + self.deserialize_type = { + "iso-8601": Deserializer.deserialize_iso, + "rfc-1123": Deserializer.deserialize_rfc, + "unix-time": Deserializer.deserialize_unix, + "duration": Deserializer.deserialize_duration, + "date": Deserializer.deserialize_date, + "time": Deserializer.deserialize_time, + "decimal": Deserializer.deserialize_decimal, + "long": Deserializer.deserialize_long, + "bytearray": Deserializer.deserialize_bytearray, + "base64": Deserializer.deserialize_base64, + "object": self.deserialize_object, + "[]": self.deserialize_iter, + "{}": self.deserialize_dict, + } + self.deserialize_expected_types = { + "duration": (isodate.Duration, datetime.timedelta), + "iso-8601": (datetime.datetime), + } + self.dependencies: Dict[str, type] = dict(classes) if classes else {} + self.key_extractors = [rest_key_extractor, xml_key_extractor] + # Additional properties only works if the "rest_key_extractor" is used to + # extract the keys. Making it to work whatever the key extractor is too much + # complicated, with no real scenario for now. + # So adding a flag to disable additional properties detection. This flag should be + # used if your expect the deserialization to NOT come from a JSON REST syntax. + # Otherwise, result are unexpected + self.additional_properties_detection = True + + def __call__(self, target_obj, response_data, content_type=None): + """Call the deserializer to process a REST response. + + :param str target_obj: Target data type to deserialize to. + :param requests.Response response_data: REST response object. + :param str content_type: Swagger "produces" if available. + :raises DeserializationError: if deserialization fails. + :return: Deserialized object. + :rtype: object + """ + data = self._unpack_content(response_data, content_type) + return self._deserialize(target_obj, data) + + def _deserialize(self, target_obj, data): # pylint: disable=inconsistent-return-statements + """Call the deserializer on a model. + + Data needs to be already deserialized as JSON or XML ElementTree + + :param str target_obj: Target data type to deserialize to. + :param object data: Object to deserialize. + :raises DeserializationError: if deserialization fails. + :return: Deserialized object. + :rtype: object + """ + # This is already a model, go recursive just in case + if hasattr(data, "_attribute_map"): + constants = [name for name, config in getattr(data, "_validation", {}).items() if config.get("constant")] + try: + for attr, mapconfig in data._attribute_map.items(): # pylint: disable=protected-access + if attr in constants: + continue + value = getattr(data, attr) + if value is None: + continue + local_type = mapconfig["type"] + internal_data_type = local_type.strip("[]{}") + if internal_data_type not in self.dependencies or isinstance(internal_data_type, Enum): + continue + setattr(data, attr, self._deserialize(local_type, value)) + return data + except AttributeError: + return + + response, class_name = self._classify_target(target_obj, data) + + if isinstance(response, str): + return self.deserialize_data(data, response) + if isinstance(response, type) and issubclass(response, Enum): + return self.deserialize_enum(data, response) + + if data is None or data is CoreNull: + return data + try: + attributes = response._attribute_map # type: ignore # pylint: disable=protected-access + d_attrs = {} + for attr, attr_desc in attributes.items(): + # Check empty string. If it's not empty, someone has a real "additionalProperties"... + if attr == "additional_properties" and attr_desc["key"] == "": + continue + raw_value = None + # Enhance attr_desc with some dynamic data + attr_desc = attr_desc.copy() # Do a copy, do not change the real one + internal_data_type = attr_desc["type"].strip("[]{}") + if internal_data_type in self.dependencies: + attr_desc["internalType"] = self.dependencies[internal_data_type] + + for key_extractor in self.key_extractors: + found_value = key_extractor(attr, attr_desc, data) + if found_value is not None: + if raw_value is not None and raw_value != found_value: + msg = ( + "Ignoring extracted value '%s' from %s for key '%s'" + " (duplicate extraction, follow extractors order)" + ) + _LOGGER.warning(msg, found_value, key_extractor, attr) + continue + raw_value = found_value + + value = self.deserialize_data(raw_value, attr_desc["type"]) + d_attrs[attr] = value + except (AttributeError, TypeError, KeyError) as err: + msg = "Unable to deserialize to object: " + class_name # type: ignore + raise DeserializationError(msg) from err + additional_properties = self._build_additional_properties(attributes, data) + return self._instantiate_model(response, d_attrs, additional_properties) + + def _build_additional_properties(self, attribute_map, data): + if not self.additional_properties_detection: + return None + if "additional_properties" in attribute_map and attribute_map.get("additional_properties", {}).get("key") != "": + # Check empty string. If it's not empty, someone has a real "additionalProperties" + return None + if isinstance(data, ET.Element): + data = {el.tag: el.text for el in data} + + known_keys = { + _decode_attribute_map_key(_FLATTEN.split(desc["key"])[0]) + for desc in attribute_map.values() + if desc["key"] != "" + } + present_keys = set(data.keys()) + missing_keys = present_keys - known_keys + return {key: data[key] for key in missing_keys} + + def _classify_target(self, target, data): + """Check to see whether the deserialization target object can + be classified into a subclass. + Once classification has been determined, initialize object. + + :param str target: The target object type to deserialize to. + :param str/dict data: The response data to deserialize. + :return: The classified target object and its class name. + :rtype: tuple + """ + if target is None: + return None, None + + if isinstance(target, str): + try: + target = self.dependencies[target] + except KeyError: + return target, target + + try: + target = target._classify(data, self.dependencies) # type: ignore # pylint: disable=protected-access + except AttributeError: + pass # Target is not a Model, no classify + return target, target.__class__.__name__ # type: ignore + + def failsafe_deserialize(self, target_obj, data, content_type=None): + """Ignores any errors encountered in deserialization, + and falls back to not deserializing the object. Recommended + for use in error deserialization, as we want to return the + HttpResponseError to users, and not have them deal with + a deserialization error. + + :param str target_obj: The target object type to deserialize to. + :param str/dict data: The response data to deserialize. + :param str content_type: Swagger "produces" if available. + :return: Deserialized object. + :rtype: object + """ + try: + return self(target_obj, data, content_type=content_type) + except: # pylint: disable=bare-except + _LOGGER.debug( + "Ran into a deserialization error. Ignoring since this is failsafe deserialization", exc_info=True + ) + return None + + @staticmethod + def _unpack_content(raw_data, content_type=None): + """Extract the correct structure for deserialization. + + If raw_data is a PipelineResponse, try to extract the result of RawDeserializer. + if we can't, raise. Your Pipeline should have a RawDeserializer. + + If not a pipeline response and raw_data is bytes or string, use content-type + to decode it. If no content-type, try JSON. + + If raw_data is something else, bypass all logic and return it directly. + + :param obj raw_data: Data to be processed. + :param str content_type: How to parse if raw_data is a string/bytes. + :raises JSONDecodeError: If JSON is requested and parsing is impossible. + :raises UnicodeDecodeError: If bytes is not UTF8 + :rtype: object + :return: Unpacked content. + """ + # Assume this is enough to detect a Pipeline Response without importing it + context = getattr(raw_data, "context", {}) + if context: + if RawDeserializer.CONTEXT_NAME in context: + return context[RawDeserializer.CONTEXT_NAME] + raise ValueError("This pipeline didn't have the RawDeserializer policy; can't deserialize") + + # Assume this is enough to recognize universal_http.ClientResponse without importing it + if hasattr(raw_data, "body"): + return RawDeserializer.deserialize_from_http_generics(raw_data.text(), raw_data.headers) + + # Assume this enough to recognize requests.Response without importing it. + if hasattr(raw_data, "_content_consumed"): + return RawDeserializer.deserialize_from_http_generics(raw_data.text, raw_data.headers) + + if isinstance(raw_data, (str, bytes)) or hasattr(raw_data, "read"): + return RawDeserializer.deserialize_from_text(raw_data, content_type) # type: ignore + return raw_data + + def _instantiate_model(self, response, attrs, additional_properties=None): + """Instantiate a response model passing in deserialized args. + + :param Response response: The response model class. + :param dict attrs: The deserialized response attributes. + :param dict additional_properties: Additional properties to be set. + :rtype: Response + :return: The instantiated response model. + """ + if callable(response): + subtype = getattr(response, "_subtype_map", {}) + try: + readonly = [ + k + for k, v in response._validation.items() # pylint: disable=protected-access # type: ignore + if v.get("readonly") + ] + const = [ + k + for k, v in response._validation.items() # pylint: disable=protected-access # type: ignore + if v.get("constant") + ] + kwargs = {k: v for k, v in attrs.items() if k not in subtype and k not in readonly + const} + response_obj = response(**kwargs) + for attr in readonly: + setattr(response_obj, attr, attrs.get(attr)) + if additional_properties: + response_obj.additional_properties = additional_properties # type: ignore + return response_obj + except TypeError as err: + msg = "Unable to deserialize {} into model {}. ".format(kwargs, response) # type: ignore + raise DeserializationError(msg + str(err)) from err + else: + try: + for attr, value in attrs.items(): + setattr(response, attr, value) + return response + except Exception as exp: + msg = "Unable to populate response model. " + msg += "Type: {}, Error: {}".format(type(response), exp) + raise DeserializationError(msg) from exp + + def deserialize_data(self, data, data_type): # pylint: disable=too-many-return-statements + """Process data for deserialization according to data type. + + :param str data: The response string to be deserialized. + :param str data_type: The type to deserialize to. + :raises DeserializationError: if deserialization fails. + :return: Deserialized object. + :rtype: object + """ + if data is None: + return data + + try: + if not data_type: + return data + if data_type in self.basic_types.values(): + return self.deserialize_basic(data, data_type) + if data_type in self.deserialize_type: + if isinstance(data, self.deserialize_expected_types.get(data_type, tuple())): + return data + + is_a_text_parsing_type = lambda x: x not in [ # pylint: disable=unnecessary-lambda-assignment + "object", + "[]", + r"{}", + ] + if isinstance(data, ET.Element) and is_a_text_parsing_type(data_type) and not data.text: + return None + data_val = self.deserialize_type[data_type](data) + return data_val + + iter_type = data_type[0] + data_type[-1] + if iter_type in self.deserialize_type: + return self.deserialize_type[iter_type](data, data_type[1:-1]) + + obj_type = self.dependencies[data_type] + if issubclass(obj_type, Enum): + if isinstance(data, ET.Element): + data = data.text + return self.deserialize_enum(data, obj_type) + + except (ValueError, TypeError, AttributeError) as err: + msg = "Unable to deserialize response data." + msg += " Data: {}, {}".format(data, data_type) + raise DeserializationError(msg) from err + return self._deserialize(obj_type, data) + + def deserialize_iter(self, attr, iter_type): + """Deserialize an iterable. + + :param list attr: Iterable to be deserialized. + :param str iter_type: The type of object in the iterable. + :return: Deserialized iterable. + :rtype: list + """ + if attr is None: + return None + if isinstance(attr, ET.Element): # If I receive an element here, get the children + attr = list(attr) + if not isinstance(attr, (list, set)): + raise DeserializationError("Cannot deserialize as [{}] an object of type {}".format(iter_type, type(attr))) + return [self.deserialize_data(a, iter_type) for a in attr] + + def deserialize_dict(self, attr, dict_type): + """Deserialize a dictionary. + + :param dict/list attr: Dictionary to be deserialized. Also accepts + a list of key, value pairs. + :param str dict_type: The object type of the items in the dictionary. + :return: Deserialized dictionary. + :rtype: dict + """ + if isinstance(attr, list): + return {x["key"]: self.deserialize_data(x["value"], dict_type) for x in attr} + + if isinstance(attr, ET.Element): + # Transform value into {"Key": "value"} + attr = {el.tag: el.text for el in attr} + return {k: self.deserialize_data(v, dict_type) for k, v in attr.items()} + + def deserialize_object(self, attr, **kwargs): # pylint: disable=too-many-return-statements + """Deserialize a generic object. + This will be handled as a dictionary. + + :param dict attr: Dictionary to be deserialized. + :return: Deserialized object. + :rtype: dict + :raises TypeError: if non-builtin datatype encountered. + """ + if attr is None: + return None + if isinstance(attr, ET.Element): + # Do no recurse on XML, just return the tree as-is + return attr + if isinstance(attr, str): + return self.deserialize_basic(attr, "str") + obj_type = type(attr) + if obj_type in self.basic_types: + return self.deserialize_basic(attr, self.basic_types[obj_type]) + if obj_type is _long_type: + return self.deserialize_long(attr) + + if obj_type == dict: + deserialized = {} + for key, value in attr.items(): + try: + deserialized[key] = self.deserialize_object(value, **kwargs) + except ValueError: + deserialized[key] = None + return deserialized + + if obj_type == list: + deserialized = [] + for obj in attr: + try: + deserialized.append(self.deserialize_object(obj, **kwargs)) + except ValueError: + pass + return deserialized + + error = "Cannot deserialize generic object with type: " + raise TypeError(error + str(obj_type)) + + def deserialize_basic(self, attr, data_type): # pylint: disable=too-many-return-statements + """Deserialize basic builtin data type from string. + Will attempt to convert to str, int, float and bool. + This function will also accept '1', '0', 'true' and 'false' as + valid bool values. + + :param str attr: response string to be deserialized. + :param str data_type: deserialization data type. + :return: Deserialized basic type. + :rtype: str, int, float or bool + :raises TypeError: if string format is not valid. + """ + # If we're here, data is supposed to be a basic type. + # If it's still an XML node, take the text + if isinstance(attr, ET.Element): + attr = attr.text + if not attr: + if data_type == "str": + # None or '', node is empty string. + return "" + # None or '', node with a strong type is None. + # Don't try to model "empty bool" or "empty int" + return None + + if data_type == "bool": + if attr in [True, False, 1, 0]: + return bool(attr) + if isinstance(attr, str): + if attr.lower() in ["true", "1"]: + return True + if attr.lower() in ["false", "0"]: + return False + raise TypeError("Invalid boolean value: {}".format(attr)) + + if data_type == "str": + return self.deserialize_unicode(attr) + return eval(data_type)(attr) # nosec # pylint: disable=eval-used + + @staticmethod + def deserialize_unicode(data): + """Preserve unicode objects in Python 2, otherwise return data + as a string. + + :param str data: response string to be deserialized. + :return: Deserialized string. + :rtype: str or unicode + """ + # We might be here because we have an enum modeled as string, + # and we try to deserialize a partial dict with enum inside + if isinstance(data, Enum): + return data + + # Consider this is real string + try: + if isinstance(data, unicode): # type: ignore + return data + except NameError: + return str(data) + return str(data) + + @staticmethod + def deserialize_enum(data, enum_obj): + """Deserialize string into enum object. + + If the string is not a valid enum value it will be returned as-is + and a warning will be logged. + + :param str data: Response string to be deserialized. If this value is + None or invalid it will be returned as-is. + :param Enum enum_obj: Enum object to deserialize to. + :return: Deserialized enum object. + :rtype: Enum + """ + if isinstance(data, enum_obj) or data is None: + return data + if isinstance(data, Enum): + data = data.value + if isinstance(data, int): + # Workaround. We might consider remove it in the future. + try: + return list(enum_obj.__members__.values())[data] + except IndexError as exc: + error = "{!r} is not a valid index for enum {!r}" + raise DeserializationError(error.format(data, enum_obj)) from exc + try: + return enum_obj(str(data)) + except ValueError: + for enum_value in enum_obj: + if enum_value.value.lower() == str(data).lower(): + return enum_value + # We don't fail anymore for unknown value, we deserialize as a string + _LOGGER.warning("Deserializer is not able to find %s as valid enum in %s", data, enum_obj) + return Deserializer.deserialize_unicode(data) + + @staticmethod + def deserialize_bytearray(attr): + """Deserialize string into bytearray. + + :param str attr: response string to be deserialized. + :return: Deserialized bytearray + :rtype: bytearray + :raises TypeError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + return bytearray(b64decode(attr)) # type: ignore + + @staticmethod + def deserialize_base64(attr): + """Deserialize base64 encoded string into string. + + :param str attr: response string to be deserialized. + :return: Deserialized base64 string + :rtype: bytearray + :raises TypeError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + padding = "=" * (3 - (len(attr) + 3) % 4) # type: ignore + attr = attr + padding # type: ignore + encoded = attr.replace("-", "+").replace("_", "/") + return b64decode(encoded) + + @staticmethod + def deserialize_decimal(attr): + """Deserialize string into Decimal object. + + :param str attr: response string to be deserialized. + :return: Deserialized decimal + :raises DeserializationError: if string format invalid. + :rtype: decimal + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + return decimal.Decimal(str(attr)) # type: ignore + except decimal.DecimalException as err: + msg = "Invalid decimal {}".format(attr) + raise DeserializationError(msg) from err + + @staticmethod + def deserialize_long(attr): + """Deserialize string into long (Py2) or int (Py3). + + :param str attr: response string to be deserialized. + :return: Deserialized int + :rtype: long or int + :raises ValueError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + return _long_type(attr) # type: ignore + + @staticmethod + def deserialize_duration(attr): + """Deserialize ISO-8601 formatted string into TimeDelta object. + + :param str attr: response string to be deserialized. + :return: Deserialized duration + :rtype: TimeDelta + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + duration = isodate.parse_duration(attr) + except (ValueError, OverflowError, AttributeError) as err: + msg = "Cannot deserialize duration object." + raise DeserializationError(msg) from err + return duration + + @staticmethod + def deserialize_date(attr): + """Deserialize ISO-8601 formatted string into Date object. + + :param str attr: response string to be deserialized. + :return: Deserialized date + :rtype: Date + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + if re.search(r"[^\W\d_]", attr, re.I + re.U): # type: ignore + raise DeserializationError("Date must have only digits and -. Received: %s" % attr) + # This must NOT use defaultmonth/defaultday. Using None ensure this raises an exception. + return isodate.parse_date(attr, defaultmonth=0, defaultday=0) + + @staticmethod + def deserialize_time(attr): + """Deserialize ISO-8601 formatted string into time object. + + :param str attr: response string to be deserialized. + :return: Deserialized time + :rtype: datetime.time + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + if re.search(r"[^\W\d_]", attr, re.I + re.U): # type: ignore + raise DeserializationError("Date must have only digits and -. Received: %s" % attr) + return isodate.parse_time(attr) + + @staticmethod + def deserialize_rfc(attr): + """Deserialize RFC-1123 formatted string into Datetime object. + + :param str attr: response string to be deserialized. + :return: Deserialized RFC datetime + :rtype: Datetime + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + parsed_date = email.utils.parsedate_tz(attr) # type: ignore + date_obj = datetime.datetime( + *parsed_date[:6], tzinfo=datetime.timezone(datetime.timedelta(minutes=(parsed_date[9] or 0) / 60)) + ) + if not date_obj.tzinfo: + date_obj = date_obj.astimezone(tz=TZ_UTC) + except ValueError as err: + msg = "Cannot deserialize to rfc datetime object." + raise DeserializationError(msg) from err + return date_obj + + @staticmethod + def deserialize_iso(attr): + """Deserialize ISO-8601 formatted string into Datetime object. + + :param str attr: response string to be deserialized. + :return: Deserialized ISO datetime + :rtype: Datetime + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + attr = attr.upper() # type: ignore + match = Deserializer.valid_date.match(attr) + if not match: + raise ValueError("Invalid datetime string: " + attr) + + check_decimal = attr.split(".") + if len(check_decimal) > 1: + decimal_str = "" + for digit in check_decimal[1]: + if digit.isdigit(): + decimal_str += digit + else: + break + if len(decimal_str) > 6: + attr = attr.replace(decimal_str, decimal_str[0:6]) + + date_obj = isodate.parse_datetime(attr) + test_utc = date_obj.utctimetuple() + if test_utc.tm_year > 9999 or test_utc.tm_year < 1: + raise OverflowError("Hit max or min date") + except (ValueError, OverflowError, AttributeError) as err: + msg = "Cannot deserialize datetime object." + raise DeserializationError(msg) from err + return date_obj + + @staticmethod + def deserialize_unix(attr): + """Serialize Datetime object into IntTime format. + This is represented as seconds. + + :param int attr: Object to be serialized. + :return: Deserialized datetime + :rtype: Datetime + :raises DeserializationError: if format invalid + """ + if isinstance(attr, ET.Element): + attr = int(attr.text) # type: ignore + try: + attr = int(attr) + date_obj = datetime.datetime.fromtimestamp(attr, TZ_UTC) + except ValueError as err: + msg = "Cannot deserialize to unix datetime object." + raise DeserializationError(msg) from err + return date_obj diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyStringVersionTolerant/bodystringversiontolerant/aio/_client.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyStringVersionTolerant/bodystringversiontolerant/aio/_client.py index d5abfba2c69..11f1b670453 100644 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyStringVersionTolerant/bodystringversiontolerant/aio/_client.py +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyStringVersionTolerant/bodystringversiontolerant/aio/_client.py @@ -14,7 +14,7 @@ from azure.core.pipeline import policies from azure.core.rest import AsyncHttpResponse, HttpRequest -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import AutoRestSwaggerBATServiceConfiguration from .operations import EnumOperations, StringOperations diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyStringVersionTolerant/bodystringversiontolerant/aio/operations/_operations.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyStringVersionTolerant/bodystringversiontolerant/aio/operations/_operations.py index 986870db36c..640112131a0 100644 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyStringVersionTolerant/bodystringversiontolerant/aio/operations/_operations.py +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyStringVersionTolerant/bodystringversiontolerant/aio/operations/_operations.py @@ -24,7 +24,7 @@ from azure.core.tracing.decorator_async import distributed_trace_async from azure.core.utils import case_insensitive_dict -from ..._serialization import Deserializer, Serializer +from ..._utils.serialization import Deserializer, Serializer from ...operations._operations import ( build_enum_get_not_expandable_request, build_enum_get_referenced_constant_request, diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyStringVersionTolerant/bodystringversiontolerant/operations/_operations.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyStringVersionTolerant/bodystringversiontolerant/operations/_operations.py index 54fd3f23bcd..6ca57a67516 100644 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyStringVersionTolerant/bodystringversiontolerant/operations/_operations.py +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyStringVersionTolerant/bodystringversiontolerant/operations/_operations.py @@ -25,7 +25,7 @@ from azure.core.utils import case_insensitive_dict from .._configuration import AutoRestSwaggerBATServiceConfiguration -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyTimeVersionTolerant/bodytimeversiontolerant/_client.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyTimeVersionTolerant/bodytimeversiontolerant/_client.py index 1309d129ee6..7b1a478ea0c 100644 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyTimeVersionTolerant/bodytimeversiontolerant/_client.py +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyTimeVersionTolerant/bodytimeversiontolerant/_client.py @@ -15,7 +15,7 @@ from azure.core.rest import HttpRequest, HttpResponse from ._configuration import AutoRestTimeTestServiceConfiguration -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer from .operations import TimeOperations diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyTimeVersionTolerant/bodytimeversiontolerant/_utils/__init__.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyTimeVersionTolerant/bodytimeversiontolerant/_utils/__init__.py new file mode 100644 index 00000000000..0af9b28f660 --- /dev/null +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyTimeVersionTolerant/bodytimeversiontolerant/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyTimeVersionTolerant/bodytimeversiontolerant/_utils/serialization.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyTimeVersionTolerant/bodytimeversiontolerant/_utils/serialization.py new file mode 100644 index 00000000000..f5187701d7b --- /dev/null +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyTimeVersionTolerant/bodytimeversiontolerant/_utils/serialization.py @@ -0,0 +1,2032 @@ +# pylint: disable=line-too-long,useless-suppression,too-many-lines +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +# pyright: reportUnnecessaryTypeIgnoreComment=false + +from base64 import b64decode, b64encode +import calendar +import datetime +import decimal +import email +from enum import Enum +import json +import logging +import re +import sys +import codecs +from typing import ( + Dict, + Any, + cast, + Optional, + Union, + AnyStr, + IO, + Mapping, + Callable, + MutableMapping, + List, +) + +try: + from urllib import quote # type: ignore +except ImportError: + from urllib.parse import quote +import xml.etree.ElementTree as ET + +import isodate # type: ignore +from typing_extensions import Self + +from azure.core.exceptions import DeserializationError, SerializationError +from azure.core.serialization import NULL as CoreNull + +_BOM = codecs.BOM_UTF8.decode(encoding="utf-8") + +JSON = MutableMapping[str, Any] + + +class RawDeserializer: + + # Accept "text" because we're open minded people... + JSON_REGEXP = re.compile(r"^(application|text)/([a-z+.]+\+)?json$") + + # Name used in context + CONTEXT_NAME = "deserialized_data" + + @classmethod + def deserialize_from_text(cls, data: Optional[Union[AnyStr, IO]], content_type: Optional[str] = None) -> Any: + """Decode data according to content-type. + + Accept a stream of data as well, but will be load at once in memory for now. + + If no content-type, will return the string version (not bytes, not stream) + + :param data: Input, could be bytes or stream (will be decoded with UTF8) or text + :type data: str or bytes or IO + :param str content_type: The content type. + :return: The deserialized data. + :rtype: object + """ + if hasattr(data, "read"): + # Assume a stream + data = cast(IO, data).read() + + if isinstance(data, bytes): + data_as_str = data.decode(encoding="utf-8-sig") + else: + # Explain to mypy the correct type. + data_as_str = cast(str, data) + + # Remove Byte Order Mark if present in string + data_as_str = data_as_str.lstrip(_BOM) + + if content_type is None: + return data + + if cls.JSON_REGEXP.match(content_type): + try: + return json.loads(data_as_str) + except ValueError as err: + raise DeserializationError("JSON is invalid: {}".format(err), err) from err + elif "xml" in (content_type or []): + try: + + try: + if isinstance(data, unicode): # type: ignore + # If I'm Python 2.7 and unicode XML will scream if I try a "fromstring" on unicode string + data_as_str = data_as_str.encode(encoding="utf-8") # type: ignore + except NameError: + pass + + return ET.fromstring(data_as_str) # nosec + except ET.ParseError as err: + # It might be because the server has an issue, and returned JSON with + # content-type XML.... + # So let's try a JSON load, and if it's still broken + # let's flow the initial exception + def _json_attemp(data): + try: + return True, json.loads(data) + except ValueError: + return False, None # Don't care about this one + + success, json_result = _json_attemp(data) + if success: + return json_result + # If i'm here, it's not JSON, it's not XML, let's scream + # and raise the last context in this block (the XML exception) + # The function hack is because Py2.7 messes up with exception + # context otherwise. + _LOGGER.critical("Wasn't XML not JSON, failing") + raise DeserializationError("XML is invalid") from err + elif content_type.startswith("text/"): + return data_as_str + raise DeserializationError("Cannot deserialize content-type: {}".format(content_type)) + + @classmethod + def deserialize_from_http_generics(cls, body_bytes: Optional[Union[AnyStr, IO]], headers: Mapping) -> Any: + """Deserialize from HTTP response. + + Use bytes and headers to NOT use any requests/aiohttp or whatever + specific implementation. + Headers will tested for "content-type" + + :param bytes body_bytes: The body of the response. + :param dict headers: The headers of the response. + :returns: The deserialized data. + :rtype: object + """ + # Try to use content-type from headers if available + content_type = None + if "content-type" in headers: + content_type = headers["content-type"].split(";")[0].strip().lower() + # Ouch, this server did not declare what it sent... + # Let's guess it's JSON... + # Also, since Autorest was considering that an empty body was a valid JSON, + # need that test as well.... + else: + content_type = "application/json" + + if body_bytes: + return cls.deserialize_from_text(body_bytes, content_type) + return None + + +_LOGGER = logging.getLogger(__name__) + +try: + _long_type = long # type: ignore +except NameError: + _long_type = int + +TZ_UTC = datetime.timezone.utc + +_FLATTEN = re.compile(r"(? None: + self.additional_properties: Optional[Dict[str, Any]] = {} + for k in kwargs: # pylint: disable=consider-using-dict-items + if k not in self._attribute_map: + _LOGGER.warning("%s is not a known attribute of class %s and will be ignored", k, self.__class__) + elif k in self._validation and self._validation[k].get("readonly", False): + _LOGGER.warning("Readonly attribute %s will be ignored in class %s", k, self.__class__) + else: + setattr(self, k, kwargs[k]) + + def __eq__(self, other: Any) -> bool: + """Compare objects by comparing all attributes. + + :param object other: The object to compare + :returns: True if objects are equal + :rtype: bool + """ + if isinstance(other, self.__class__): + return self.__dict__ == other.__dict__ + return False + + def __ne__(self, other: Any) -> bool: + """Compare objects by comparing all attributes. + + :param object other: The object to compare + :returns: True if objects are not equal + :rtype: bool + """ + return not self.__eq__(other) + + def __str__(self) -> str: + return str(self.__dict__) + + @classmethod + def enable_additional_properties_sending(cls) -> None: + cls._attribute_map["additional_properties"] = {"key": "", "type": "{object}"} + + @classmethod + def is_xml_model(cls) -> bool: + try: + cls._xml_map # type: ignore + except AttributeError: + return False + return True + + @classmethod + def _create_xml_node(cls): + """Create XML node. + + :returns: The XML node + :rtype: xml.etree.ElementTree.Element + """ + try: + xml_map = cls._xml_map # type: ignore + except AttributeError: + xml_map = {} + + return _create_xml_node(xml_map.get("name", cls.__name__), xml_map.get("prefix", None), xml_map.get("ns", None)) + + def serialize(self, keep_readonly: bool = False, **kwargs: Any) -> JSON: + """Return the JSON that would be sent to server from this model. + + This is an alias to `as_dict(full_restapi_key_transformer, keep_readonly=False)`. + + If you want XML serialization, you can pass the kwargs is_xml=True. + + :param bool keep_readonly: If you want to serialize the readonly attributes + :returns: A dict JSON compatible object + :rtype: dict + """ + serializer = Serializer(self._infer_class_models()) + return serializer._serialize( # type: ignore # pylint: disable=protected-access + self, keep_readonly=keep_readonly, **kwargs + ) + + def as_dict( + self, + keep_readonly: bool = True, + key_transformer: Callable[[str, Dict[str, Any], Any], Any] = attribute_transformer, + **kwargs: Any + ) -> JSON: + """Return a dict that can be serialized using json.dump. + + Advanced usage might optionally use a callback as parameter: + + .. code::python + + def my_key_transformer(key, attr_desc, value): + return key + + Key is the attribute name used in Python. Attr_desc + is a dict of metadata. Currently contains 'type' with the + msrest type and 'key' with the RestAPI encoded key. + Value is the current value in this object. + + The string returned will be used to serialize the key. + If the return type is a list, this is considered hierarchical + result dict. + + See the three examples in this file: + + - attribute_transformer + - full_restapi_key_transformer + - last_restapi_key_transformer + + If you want XML serialization, you can pass the kwargs is_xml=True. + + :param bool keep_readonly: If you want to serialize the readonly attributes + :param function key_transformer: A key transformer function. + :returns: A dict JSON compatible object + :rtype: dict + """ + serializer = Serializer(self._infer_class_models()) + return serializer._serialize( # type: ignore # pylint: disable=protected-access + self, key_transformer=key_transformer, keep_readonly=keep_readonly, **kwargs + ) + + @classmethod + def _infer_class_models(cls): + try: + str_models = cls.__module__.rsplit(".", 1)[0] + models = sys.modules[str_models] + client_models = {k: v for k, v in models.__dict__.items() if isinstance(v, type)} + if cls.__name__ not in client_models: + raise ValueError("Not Autorest generated code") + except Exception: # pylint: disable=broad-exception-caught + # Assume it's not Autorest generated (tests?). Add ourselves as dependencies. + client_models = {cls.__name__: cls} + return client_models + + @classmethod + def deserialize(cls, data: Any, content_type: Optional[str] = None) -> Self: + """Parse a str using the RestAPI syntax and return a model. + + :param str data: A str using RestAPI structure. JSON by default. + :param str content_type: JSON by default, set application/xml if XML. + :returns: An instance of this model + :raises DeserializationError: if something went wrong + :rtype: Self + """ + deserializer = Deserializer(cls._infer_class_models()) + return deserializer(cls.__name__, data, content_type=content_type) # type: ignore + + @classmethod + def from_dict( + cls, + data: Any, + key_extractors: Optional[Callable[[str, Dict[str, Any], Any], Any]] = None, + content_type: Optional[str] = None, + ) -> Self: + """Parse a dict using given key extractor return a model. + + By default consider key + extractors (rest_key_case_insensitive_extractor, attribute_key_case_insensitive_extractor + and last_rest_key_case_insensitive_extractor) + + :param dict data: A dict using RestAPI structure + :param function key_extractors: A key extractor function. + :param str content_type: JSON by default, set application/xml if XML. + :returns: An instance of this model + :raises DeserializationError: if something went wrong + :rtype: Self + """ + deserializer = Deserializer(cls._infer_class_models()) + deserializer.key_extractors = ( # type: ignore + [ # type: ignore + attribute_key_case_insensitive_extractor, + rest_key_case_insensitive_extractor, + last_rest_key_case_insensitive_extractor, + ] + if key_extractors is None + else key_extractors + ) + return deserializer(cls.__name__, data, content_type=content_type) # type: ignore + + @classmethod + def _flatten_subtype(cls, key, objects): + if "_subtype_map" not in cls.__dict__: + return {} + result = dict(cls._subtype_map[key]) + for valuetype in cls._subtype_map[key].values(): + result.update(objects[valuetype]._flatten_subtype(key, objects)) # pylint: disable=protected-access + return result + + @classmethod + def _classify(cls, response, objects): + """Check the class _subtype_map for any child classes. + We want to ignore any inherited _subtype_maps. + + :param dict response: The initial data + :param dict objects: The class objects + :returns: The class to be used + :rtype: class + """ + for subtype_key in cls.__dict__.get("_subtype_map", {}).keys(): + subtype_value = None + + if not isinstance(response, ET.Element): + rest_api_response_key = cls._get_rest_key_parts(subtype_key)[-1] + subtype_value = response.get(rest_api_response_key, None) or response.get(subtype_key, None) + else: + subtype_value = xml_key_extractor(subtype_key, cls._attribute_map[subtype_key], response) + if subtype_value: + # Try to match base class. Can be class name only + # (bug to fix in Autorest to support x-ms-discriminator-name) + if cls.__name__ == subtype_value: + return cls + flatten_mapping_type = cls._flatten_subtype(subtype_key, objects) + try: + return objects[flatten_mapping_type[subtype_value]] # type: ignore + except KeyError: + _LOGGER.warning( + "Subtype value %s has no mapping, use base class %s.", + subtype_value, + cls.__name__, + ) + break + else: + _LOGGER.warning("Discriminator %s is absent or null, use base class %s.", subtype_key, cls.__name__) + break + return cls + + @classmethod + def _get_rest_key_parts(cls, attr_key): + """Get the RestAPI key of this attr, split it and decode part + :param str attr_key: Attribute key must be in attribute_map. + :returns: A list of RestAPI part + :rtype: list + """ + rest_split_key = _FLATTEN.split(cls._attribute_map[attr_key]["key"]) + return [_decode_attribute_map_key(key_part) for key_part in rest_split_key] + + +def _decode_attribute_map_key(key): + """This decode a key in an _attribute_map to the actual key we want to look at + inside the received data. + + :param str key: A key string from the generated code + :returns: The decoded key + :rtype: str + """ + return key.replace("\\.", ".") + + +class Serializer: # pylint: disable=too-many-public-methods + """Request object model serializer.""" + + basic_types = {str: "str", int: "int", bool: "bool", float: "float"} + + _xml_basic_types_serializers = {"bool": lambda x: str(x).lower()} + days = {0: "Mon", 1: "Tue", 2: "Wed", 3: "Thu", 4: "Fri", 5: "Sat", 6: "Sun"} + months = { + 1: "Jan", + 2: "Feb", + 3: "Mar", + 4: "Apr", + 5: "May", + 6: "Jun", + 7: "Jul", + 8: "Aug", + 9: "Sep", + 10: "Oct", + 11: "Nov", + 12: "Dec", + } + validation = { + "min_length": lambda x, y: len(x) < y, + "max_length": lambda x, y: len(x) > y, + "minimum": lambda x, y: x < y, + "maximum": lambda x, y: x > y, + "minimum_ex": lambda x, y: x <= y, + "maximum_ex": lambda x, y: x >= y, + "min_items": lambda x, y: len(x) < y, + "max_items": lambda x, y: len(x) > y, + "pattern": lambda x, y: not re.match(y, x, re.UNICODE), + "unique": lambda x, y: len(x) != len(set(x)), + "multiple": lambda x, y: x % y != 0, + } + + def __init__(self, classes: Optional[Mapping[str, type]] = None) -> None: + self.serialize_type = { + "iso-8601": Serializer.serialize_iso, + "rfc-1123": Serializer.serialize_rfc, + "unix-time": Serializer.serialize_unix, + "duration": Serializer.serialize_duration, + "date": Serializer.serialize_date, + "time": Serializer.serialize_time, + "decimal": Serializer.serialize_decimal, + "long": Serializer.serialize_long, + "bytearray": Serializer.serialize_bytearray, + "base64": Serializer.serialize_base64, + "object": self.serialize_object, + "[]": self.serialize_iter, + "{}": self.serialize_dict, + } + self.dependencies: Dict[str, type] = dict(classes) if classes else {} + self.key_transformer = full_restapi_key_transformer + self.client_side_validation = True + + def _serialize( # pylint: disable=too-many-nested-blocks, too-many-branches, too-many-statements, too-many-locals + self, target_obj, data_type=None, **kwargs + ): + """Serialize data into a string according to type. + + :param object target_obj: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str, dict + :raises SerializationError: if serialization fails. + :returns: The serialized data. + """ + key_transformer = kwargs.get("key_transformer", self.key_transformer) + keep_readonly = kwargs.get("keep_readonly", False) + if target_obj is None: + return None + + attr_name = None + class_name = target_obj.__class__.__name__ + + if data_type: + return self.serialize_data(target_obj, data_type, **kwargs) + + if not hasattr(target_obj, "_attribute_map"): + data_type = type(target_obj).__name__ + if data_type in self.basic_types.values(): + return self.serialize_data(target_obj, data_type, **kwargs) + + # Force "is_xml" kwargs if we detect a XML model + try: + is_xml_model_serialization = kwargs["is_xml"] + except KeyError: + is_xml_model_serialization = kwargs.setdefault("is_xml", target_obj.is_xml_model()) + + serialized = {} + if is_xml_model_serialization: + serialized = target_obj._create_xml_node() # pylint: disable=protected-access + try: + attributes = target_obj._attribute_map # pylint: disable=protected-access + for attr, attr_desc in attributes.items(): + attr_name = attr + if not keep_readonly and target_obj._validation.get( # pylint: disable=protected-access + attr_name, {} + ).get("readonly", False): + continue + + if attr_name == "additional_properties" and attr_desc["key"] == "": + if target_obj.additional_properties is not None: + serialized.update(target_obj.additional_properties) + continue + try: + + orig_attr = getattr(target_obj, attr) + if is_xml_model_serialization: + pass # Don't provide "transformer" for XML for now. Keep "orig_attr" + else: # JSON + keys, orig_attr = key_transformer(attr, attr_desc.copy(), orig_attr) + keys = keys if isinstance(keys, list) else [keys] + + kwargs["serialization_ctxt"] = attr_desc + new_attr = self.serialize_data(orig_attr, attr_desc["type"], **kwargs) + + if is_xml_model_serialization: + xml_desc = attr_desc.get("xml", {}) + xml_name = xml_desc.get("name", attr_desc["key"]) + xml_prefix = xml_desc.get("prefix", None) + xml_ns = xml_desc.get("ns", None) + if xml_desc.get("attr", False): + if xml_ns: + ET.register_namespace(xml_prefix, xml_ns) + xml_name = "{{{}}}{}".format(xml_ns, xml_name) + serialized.set(xml_name, new_attr) # type: ignore + continue + if xml_desc.get("text", False): + serialized.text = new_attr # type: ignore + continue + if isinstance(new_attr, list): + serialized.extend(new_attr) # type: ignore + elif isinstance(new_attr, ET.Element): + # If the down XML has no XML/Name, + # we MUST replace the tag with the local tag. But keeping the namespaces. + if "name" not in getattr(orig_attr, "_xml_map", {}): + splitted_tag = new_attr.tag.split("}") + if len(splitted_tag) == 2: # Namespace + new_attr.tag = "}".join([splitted_tag[0], xml_name]) + else: + new_attr.tag = xml_name + serialized.append(new_attr) # type: ignore + else: # That's a basic type + # Integrate namespace if necessary + local_node = _create_xml_node(xml_name, xml_prefix, xml_ns) + local_node.text = str(new_attr) + serialized.append(local_node) # type: ignore + else: # JSON + for k in reversed(keys): # type: ignore + new_attr = {k: new_attr} + + _new_attr = new_attr + _serialized = serialized + for k in keys: # type: ignore + if k not in _serialized: + _serialized.update(_new_attr) # type: ignore + _new_attr = _new_attr[k] # type: ignore + _serialized = _serialized[k] + except ValueError as err: + if isinstance(err, SerializationError): + raise + + except (AttributeError, KeyError, TypeError) as err: + msg = "Attribute {} in object {} cannot be serialized.\n{}".format(attr_name, class_name, str(target_obj)) + raise SerializationError(msg) from err + return serialized + + def body(self, data, data_type, **kwargs): + """Serialize data intended for a request body. + + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: dict + :raises SerializationError: if serialization fails. + :raises ValueError: if data is None + :returns: The serialized request body + """ + + # Just in case this is a dict + internal_data_type_str = data_type.strip("[]{}") + internal_data_type = self.dependencies.get(internal_data_type_str, None) + try: + is_xml_model_serialization = kwargs["is_xml"] + except KeyError: + if internal_data_type and issubclass(internal_data_type, Model): + is_xml_model_serialization = kwargs.setdefault("is_xml", internal_data_type.is_xml_model()) + else: + is_xml_model_serialization = False + if internal_data_type and not isinstance(internal_data_type, Enum): + try: + deserializer = Deserializer(self.dependencies) + # Since it's on serialization, it's almost sure that format is not JSON REST + # We're not able to deal with additional properties for now. + deserializer.additional_properties_detection = False + if is_xml_model_serialization: + deserializer.key_extractors = [ # type: ignore + attribute_key_case_insensitive_extractor, + ] + else: + deserializer.key_extractors = [ + rest_key_case_insensitive_extractor, + attribute_key_case_insensitive_extractor, + last_rest_key_case_insensitive_extractor, + ] + data = deserializer._deserialize(data_type, data) # pylint: disable=protected-access + except DeserializationError as err: + raise SerializationError("Unable to build a model: " + str(err)) from err + + return self._serialize(data, data_type, **kwargs) + + def url(self, name, data, data_type, **kwargs): + """Serialize data intended for a URL path. + + :param str name: The name of the URL path parameter. + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str + :returns: The serialized URL path + :raises TypeError: if serialization fails. + :raises ValueError: if data is None + """ + try: + output = self.serialize_data(data, data_type, **kwargs) + if data_type == "bool": + output = json.dumps(output) + + if kwargs.get("skip_quote") is True: + output = str(output) + output = output.replace("{", quote("{")).replace("}", quote("}")) + else: + output = quote(str(output), safe="") + except SerializationError as exc: + raise TypeError("{} must be type {}.".format(name, data_type)) from exc + return output + + def query(self, name, data, data_type, **kwargs): + """Serialize data intended for a URL query. + + :param str name: The name of the query parameter. + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str, list + :raises TypeError: if serialization fails. + :raises ValueError: if data is None + :returns: The serialized query parameter + """ + try: + # Treat the list aside, since we don't want to encode the div separator + if data_type.startswith("["): + internal_data_type = data_type[1:-1] + do_quote = not kwargs.get("skip_quote", False) + return self.serialize_iter(data, internal_data_type, do_quote=do_quote, **kwargs) + + # Not a list, regular serialization + output = self.serialize_data(data, data_type, **kwargs) + if data_type == "bool": + output = json.dumps(output) + if kwargs.get("skip_quote") is True: + output = str(output) + else: + output = quote(str(output), safe="") + except SerializationError as exc: + raise TypeError("{} must be type {}.".format(name, data_type)) from exc + return str(output) + + def header(self, name, data, data_type, **kwargs): + """Serialize data intended for a request header. + + :param str name: The name of the header. + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str + :raises TypeError: if serialization fails. + :raises ValueError: if data is None + :returns: The serialized header + """ + try: + if data_type in ["[str]"]: + data = ["" if d is None else d for d in data] + + output = self.serialize_data(data, data_type, **kwargs) + if data_type == "bool": + output = json.dumps(output) + except SerializationError as exc: + raise TypeError("{} must be type {}.".format(name, data_type)) from exc + return str(output) + + def serialize_data(self, data, data_type, **kwargs): + """Serialize generic data according to supplied data type. + + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :raises AttributeError: if required data is None. + :raises ValueError: if data is None + :raises SerializationError: if serialization fails. + :returns: The serialized data. + :rtype: str, int, float, bool, dict, list + """ + if data is None: + raise ValueError("No value for given attribute") + + try: + if data is CoreNull: + return None + if data_type in self.basic_types.values(): + return self.serialize_basic(data, data_type, **kwargs) + + if data_type in self.serialize_type: + return self.serialize_type[data_type](data, **kwargs) + + # If dependencies is empty, try with current data class + # It has to be a subclass of Enum anyway + enum_type = self.dependencies.get(data_type, data.__class__) + if issubclass(enum_type, Enum): + return Serializer.serialize_enum(data, enum_obj=enum_type) + + iter_type = data_type[0] + data_type[-1] + if iter_type in self.serialize_type: + return self.serialize_type[iter_type](data, data_type[1:-1], **kwargs) + + except (ValueError, TypeError) as err: + msg = "Unable to serialize value: {!r} as type: {!r}." + raise SerializationError(msg.format(data, data_type)) from err + return self._serialize(data, **kwargs) + + @classmethod + def _get_custom_serializers(cls, data_type, **kwargs): # pylint: disable=inconsistent-return-statements + custom_serializer = kwargs.get("basic_types_serializers", {}).get(data_type) + if custom_serializer: + return custom_serializer + if kwargs.get("is_xml", False): + return cls._xml_basic_types_serializers.get(data_type) + + @classmethod + def serialize_basic(cls, data, data_type, **kwargs): + """Serialize basic builting data type. + Serializes objects to str, int, float or bool. + + Possible kwargs: + - basic_types_serializers dict[str, callable] : If set, use the callable as serializer + - is_xml bool : If set, use xml_basic_types_serializers + + :param obj data: Object to be serialized. + :param str data_type: Type of object in the iterable. + :rtype: str, int, float, bool + :return: serialized object + """ + custom_serializer = cls._get_custom_serializers(data_type, **kwargs) + if custom_serializer: + return custom_serializer(data) + if data_type == "str": + return cls.serialize_unicode(data) + return eval(data_type)(data) # nosec # pylint: disable=eval-used + + @classmethod + def serialize_unicode(cls, data): + """Special handling for serializing unicode strings in Py2. + Encode to UTF-8 if unicode, otherwise handle as a str. + + :param str data: Object to be serialized. + :rtype: str + :return: serialized object + """ + try: # If I received an enum, return its value + return data.value + except AttributeError: + pass + + try: + if isinstance(data, unicode): # type: ignore + # Don't change it, JSON and XML ElementTree are totally able + # to serialize correctly u'' strings + return data + except NameError: + return str(data) + return str(data) + + def serialize_iter(self, data, iter_type, div=None, **kwargs): + """Serialize iterable. + + Supported kwargs: + - serialization_ctxt dict : The current entry of _attribute_map, or same format. + serialization_ctxt['type'] should be same as data_type. + - is_xml bool : If set, serialize as XML + + :param list data: Object to be serialized. + :param str iter_type: Type of object in the iterable. + :param str div: If set, this str will be used to combine the elements + in the iterable into a combined string. Default is 'None'. + Defaults to False. + :rtype: list, str + :return: serialized iterable + """ + if isinstance(data, str): + raise SerializationError("Refuse str type as a valid iter type.") + + serialization_ctxt = kwargs.get("serialization_ctxt", {}) + is_xml = kwargs.get("is_xml", False) + + serialized = [] + for d in data: + try: + serialized.append(self.serialize_data(d, iter_type, **kwargs)) + except ValueError as err: + if isinstance(err, SerializationError): + raise + serialized.append(None) + + if kwargs.get("do_quote", False): + serialized = ["" if s is None else quote(str(s), safe="") for s in serialized] + + if div: + serialized = ["" if s is None else str(s) for s in serialized] + serialized = div.join(serialized) + + if "xml" in serialization_ctxt or is_xml: + # XML serialization is more complicated + xml_desc = serialization_ctxt.get("xml", {}) + xml_name = xml_desc.get("name") + if not xml_name: + xml_name = serialization_ctxt["key"] + + # Create a wrap node if necessary (use the fact that Element and list have "append") + is_wrapped = xml_desc.get("wrapped", False) + node_name = xml_desc.get("itemsName", xml_name) + if is_wrapped: + final_result = _create_xml_node(xml_name, xml_desc.get("prefix", None), xml_desc.get("ns", None)) + else: + final_result = [] + # All list elements to "local_node" + for el in serialized: + if isinstance(el, ET.Element): + el_node = el + else: + el_node = _create_xml_node(node_name, xml_desc.get("prefix", None), xml_desc.get("ns", None)) + if el is not None: # Otherwise it writes "None" :-p + el_node.text = str(el) + final_result.append(el_node) + return final_result + return serialized + + def serialize_dict(self, attr, dict_type, **kwargs): + """Serialize a dictionary of objects. + + :param dict attr: Object to be serialized. + :param str dict_type: Type of object in the dictionary. + :rtype: dict + :return: serialized dictionary + """ + serialization_ctxt = kwargs.get("serialization_ctxt", {}) + serialized = {} + for key, value in attr.items(): + try: + serialized[self.serialize_unicode(key)] = self.serialize_data(value, dict_type, **kwargs) + except ValueError as err: + if isinstance(err, SerializationError): + raise + serialized[self.serialize_unicode(key)] = None + + if "xml" in serialization_ctxt: + # XML serialization is more complicated + xml_desc = serialization_ctxt["xml"] + xml_name = xml_desc["name"] + + final_result = _create_xml_node(xml_name, xml_desc.get("prefix", None), xml_desc.get("ns", None)) + for key, value in serialized.items(): + ET.SubElement(final_result, key).text = value + return final_result + + return serialized + + def serialize_object(self, attr, **kwargs): # pylint: disable=too-many-return-statements + """Serialize a generic object. + This will be handled as a dictionary. If object passed in is not + a basic type (str, int, float, dict, list) it will simply be + cast to str. + + :param dict attr: Object to be serialized. + :rtype: dict or str + :return: serialized object + """ + if attr is None: + return None + if isinstance(attr, ET.Element): + return attr + obj_type = type(attr) + if obj_type in self.basic_types: + return self.serialize_basic(attr, self.basic_types[obj_type], **kwargs) + if obj_type is _long_type: + return self.serialize_long(attr) + if obj_type is str: + return self.serialize_unicode(attr) + if obj_type is datetime.datetime: + return self.serialize_iso(attr) + if obj_type is datetime.date: + return self.serialize_date(attr) + if obj_type is datetime.time: + return self.serialize_time(attr) + if obj_type is datetime.timedelta: + return self.serialize_duration(attr) + if obj_type is decimal.Decimal: + return self.serialize_decimal(attr) + + # If it's a model or I know this dependency, serialize as a Model + if obj_type in self.dependencies.values() or isinstance(attr, Model): + return self._serialize(attr) + + if obj_type == dict: + serialized = {} + for key, value in attr.items(): + try: + serialized[self.serialize_unicode(key)] = self.serialize_object(value, **kwargs) + except ValueError: + serialized[self.serialize_unicode(key)] = None + return serialized + + if obj_type == list: + serialized = [] + for obj in attr: + try: + serialized.append(self.serialize_object(obj, **kwargs)) + except ValueError: + pass + return serialized + return str(attr) + + @staticmethod + def serialize_enum(attr, enum_obj=None): + try: + result = attr.value + except AttributeError: + result = attr + try: + enum_obj(result) # type: ignore + return result + except ValueError as exc: + for enum_value in enum_obj: # type: ignore + if enum_value.value.lower() == str(attr).lower(): + return enum_value.value + error = "{!r} is not valid value for enum {!r}" + raise SerializationError(error.format(attr, enum_obj)) from exc + + @staticmethod + def serialize_bytearray(attr, **kwargs): # pylint: disable=unused-argument + """Serialize bytearray into base-64 string. + + :param str attr: Object to be serialized. + :rtype: str + :return: serialized base64 + """ + return b64encode(attr).decode() + + @staticmethod + def serialize_base64(attr, **kwargs): # pylint: disable=unused-argument + """Serialize str into base-64 string. + + :param str attr: Object to be serialized. + :rtype: str + :return: serialized base64 + """ + encoded = b64encode(attr).decode("ascii") + return encoded.strip("=").replace("+", "-").replace("/", "_") + + @staticmethod + def serialize_decimal(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Decimal object to float. + + :param decimal attr: Object to be serialized. + :rtype: float + :return: serialized decimal + """ + return float(attr) + + @staticmethod + def serialize_long(attr, **kwargs): # pylint: disable=unused-argument + """Serialize long (Py2) or int (Py3). + + :param int attr: Object to be serialized. + :rtype: int/long + :return: serialized long + """ + return _long_type(attr) + + @staticmethod + def serialize_date(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Date object into ISO-8601 formatted string. + + :param Date attr: Object to be serialized. + :rtype: str + :return: serialized date + """ + if isinstance(attr, str): + attr = isodate.parse_date(attr) + t = "{:04}-{:02}-{:02}".format(attr.year, attr.month, attr.day) + return t + + @staticmethod + def serialize_time(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Time object into ISO-8601 formatted string. + + :param datetime.time attr: Object to be serialized. + :rtype: str + :return: serialized time + """ + if isinstance(attr, str): + attr = isodate.parse_time(attr) + t = "{:02}:{:02}:{:02}".format(attr.hour, attr.minute, attr.second) + if attr.microsecond: + t += ".{:02}".format(attr.microsecond) + return t + + @staticmethod + def serialize_duration(attr, **kwargs): # pylint: disable=unused-argument + """Serialize TimeDelta object into ISO-8601 formatted string. + + :param TimeDelta attr: Object to be serialized. + :rtype: str + :return: serialized duration + """ + if isinstance(attr, str): + attr = isodate.parse_duration(attr) + return isodate.duration_isoformat(attr) + + @staticmethod + def serialize_rfc(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Datetime object into RFC-1123 formatted string. + + :param Datetime attr: Object to be serialized. + :rtype: str + :raises TypeError: if format invalid. + :return: serialized rfc + """ + try: + if not attr.tzinfo: + _LOGGER.warning("Datetime with no tzinfo will be considered UTC.") + utc = attr.utctimetuple() + except AttributeError as exc: + raise TypeError("RFC1123 object must be valid Datetime object.") from exc + + return "{}, {:02} {} {:04} {:02}:{:02}:{:02} GMT".format( + Serializer.days[utc.tm_wday], + utc.tm_mday, + Serializer.months[utc.tm_mon], + utc.tm_year, + utc.tm_hour, + utc.tm_min, + utc.tm_sec, + ) + + @staticmethod + def serialize_iso(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Datetime object into ISO-8601 formatted string. + + :param Datetime attr: Object to be serialized. + :rtype: str + :raises SerializationError: if format invalid. + :return: serialized iso + """ + if isinstance(attr, str): + attr = isodate.parse_datetime(attr) + try: + if not attr.tzinfo: + _LOGGER.warning("Datetime with no tzinfo will be considered UTC.") + utc = attr.utctimetuple() + if utc.tm_year > 9999 or utc.tm_year < 1: + raise OverflowError("Hit max or min date") + + microseconds = str(attr.microsecond).rjust(6, "0").rstrip("0").ljust(3, "0") + if microseconds: + microseconds = "." + microseconds + date = "{:04}-{:02}-{:02}T{:02}:{:02}:{:02}".format( + utc.tm_year, utc.tm_mon, utc.tm_mday, utc.tm_hour, utc.tm_min, utc.tm_sec + ) + return date + microseconds + "Z" + except (ValueError, OverflowError) as err: + msg = "Unable to serialize datetime object." + raise SerializationError(msg) from err + except AttributeError as err: + msg = "ISO-8601 object must be valid Datetime object." + raise TypeError(msg) from err + + @staticmethod + def serialize_unix(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Datetime object into IntTime format. + This is represented as seconds. + + :param Datetime attr: Object to be serialized. + :rtype: int + :raises SerializationError: if format invalid + :return: serialied unix + """ + if isinstance(attr, int): + return attr + try: + if not attr.tzinfo: + _LOGGER.warning("Datetime with no tzinfo will be considered UTC.") + return int(calendar.timegm(attr.utctimetuple())) + except AttributeError as exc: + raise TypeError("Unix time object must be valid Datetime object.") from exc + + +def rest_key_extractor(attr, attr_desc, data): # pylint: disable=unused-argument + key = attr_desc["key"] + working_data = data + + while "." in key: + # Need the cast, as for some reasons "split" is typed as list[str | Any] + dict_keys = cast(List[str], _FLATTEN.split(key)) + if len(dict_keys) == 1: + key = _decode_attribute_map_key(dict_keys[0]) + break + working_key = _decode_attribute_map_key(dict_keys[0]) + working_data = working_data.get(working_key, data) + if working_data is None: + # If at any point while following flatten JSON path see None, it means + # that all properties under are None as well + return None + key = ".".join(dict_keys[1:]) + + return working_data.get(key) + + +def rest_key_case_insensitive_extractor( # pylint: disable=unused-argument, inconsistent-return-statements + attr, attr_desc, data +): + key = attr_desc["key"] + working_data = data + + while "." in key: + dict_keys = _FLATTEN.split(key) + if len(dict_keys) == 1: + key = _decode_attribute_map_key(dict_keys[0]) + break + working_key = _decode_attribute_map_key(dict_keys[0]) + working_data = attribute_key_case_insensitive_extractor(working_key, None, working_data) + if working_data is None: + # If at any point while following flatten JSON path see None, it means + # that all properties under are None as well + return None + key = ".".join(dict_keys[1:]) + + if working_data: + return attribute_key_case_insensitive_extractor(key, None, working_data) + + +def last_rest_key_extractor(attr, attr_desc, data): # pylint: disable=unused-argument + """Extract the attribute in "data" based on the last part of the JSON path key. + + :param str attr: The attribute to extract + :param dict attr_desc: The attribute description + :param dict data: The data to extract from + :rtype: object + :returns: The extracted attribute + """ + key = attr_desc["key"] + dict_keys = _FLATTEN.split(key) + return attribute_key_extractor(dict_keys[-1], None, data) + + +def last_rest_key_case_insensitive_extractor(attr, attr_desc, data): # pylint: disable=unused-argument + """Extract the attribute in "data" based on the last part of the JSON path key. + + This is the case insensitive version of "last_rest_key_extractor" + :param str attr: The attribute to extract + :param dict attr_desc: The attribute description + :param dict data: The data to extract from + :rtype: object + :returns: The extracted attribute + """ + key = attr_desc["key"] + dict_keys = _FLATTEN.split(key) + return attribute_key_case_insensitive_extractor(dict_keys[-1], None, data) + + +def attribute_key_extractor(attr, _, data): + return data.get(attr) + + +def attribute_key_case_insensitive_extractor(attr, _, data): + found_key = None + lower_attr = attr.lower() + for key in data: + if lower_attr == key.lower(): + found_key = key + break + + return data.get(found_key) + + +def _extract_name_from_internal_type(internal_type): + """Given an internal type XML description, extract correct XML name with namespace. + + :param dict internal_type: An model type + :rtype: tuple + :returns: A tuple XML name + namespace dict + """ + internal_type_xml_map = getattr(internal_type, "_xml_map", {}) + xml_name = internal_type_xml_map.get("name", internal_type.__name__) + xml_ns = internal_type_xml_map.get("ns", None) + if xml_ns: + xml_name = "{{{}}}{}".format(xml_ns, xml_name) + return xml_name + + +def xml_key_extractor(attr, attr_desc, data): # pylint: disable=unused-argument,too-many-return-statements + if isinstance(data, dict): + return None + + # Test if this model is XML ready first + if not isinstance(data, ET.Element): + return None + + xml_desc = attr_desc.get("xml", {}) + xml_name = xml_desc.get("name", attr_desc["key"]) + + # Look for a children + is_iter_type = attr_desc["type"].startswith("[") + is_wrapped = xml_desc.get("wrapped", False) + internal_type = attr_desc.get("internalType", None) + internal_type_xml_map = getattr(internal_type, "_xml_map", {}) + + # Integrate namespace if necessary + xml_ns = xml_desc.get("ns", internal_type_xml_map.get("ns", None)) + if xml_ns: + xml_name = "{{{}}}{}".format(xml_ns, xml_name) + + # If it's an attribute, that's simple + if xml_desc.get("attr", False): + return data.get(xml_name) + + # If it's x-ms-text, that's simple too + if xml_desc.get("text", False): + return data.text + + # Scenario where I take the local name: + # - Wrapped node + # - Internal type is an enum (considered basic types) + # - Internal type has no XML/Name node + if is_wrapped or (internal_type and (issubclass(internal_type, Enum) or "name" not in internal_type_xml_map)): + children = data.findall(xml_name) + # If internal type has a local name and it's not a list, I use that name + elif not is_iter_type and internal_type and "name" in internal_type_xml_map: + xml_name = _extract_name_from_internal_type(internal_type) + children = data.findall(xml_name) + # That's an array + else: + if internal_type: # Complex type, ignore itemsName and use the complex type name + items_name = _extract_name_from_internal_type(internal_type) + else: + items_name = xml_desc.get("itemsName", xml_name) + children = data.findall(items_name) + + if len(children) == 0: + if is_iter_type: + if is_wrapped: + return None # is_wrapped no node, we want None + return [] # not wrapped, assume empty list + return None # Assume it's not there, maybe an optional node. + + # If is_iter_type and not wrapped, return all found children + if is_iter_type: + if not is_wrapped: + return children + # Iter and wrapped, should have found one node only (the wrap one) + if len(children) != 1: + raise DeserializationError( + "Tried to deserialize an array not wrapped, and found several nodes '{}'. Maybe you should declare this array as wrapped?".format( + xml_name + ) + ) + return list(children[0]) # Might be empty list and that's ok. + + # Here it's not a itertype, we should have found one element only or empty + if len(children) > 1: + raise DeserializationError("Find several XML '{}' where it was not expected".format(xml_name)) + return children[0] + + +class Deserializer: + """Response object model deserializer. + + :param dict classes: Class type dictionary for deserializing complex types. + :ivar list key_extractors: Ordered list of extractors to be used by this deserializer. + """ + + basic_types = {str: "str", int: "int", bool: "bool", float: "float"} + + valid_date = re.compile(r"\d{4}[-]\d{2}[-]\d{2}T\d{2}:\d{2}:\d{2}\.?\d*Z?[-+]?[\d{2}]?:?[\d{2}]?") + + def __init__(self, classes: Optional[Mapping[str, type]] = None) -> None: + self.deserialize_type = { + "iso-8601": Deserializer.deserialize_iso, + "rfc-1123": Deserializer.deserialize_rfc, + "unix-time": Deserializer.deserialize_unix, + "duration": Deserializer.deserialize_duration, + "date": Deserializer.deserialize_date, + "time": Deserializer.deserialize_time, + "decimal": Deserializer.deserialize_decimal, + "long": Deserializer.deserialize_long, + "bytearray": Deserializer.deserialize_bytearray, + "base64": Deserializer.deserialize_base64, + "object": self.deserialize_object, + "[]": self.deserialize_iter, + "{}": self.deserialize_dict, + } + self.deserialize_expected_types = { + "duration": (isodate.Duration, datetime.timedelta), + "iso-8601": (datetime.datetime), + } + self.dependencies: Dict[str, type] = dict(classes) if classes else {} + self.key_extractors = [rest_key_extractor, xml_key_extractor] + # Additional properties only works if the "rest_key_extractor" is used to + # extract the keys. Making it to work whatever the key extractor is too much + # complicated, with no real scenario for now. + # So adding a flag to disable additional properties detection. This flag should be + # used if your expect the deserialization to NOT come from a JSON REST syntax. + # Otherwise, result are unexpected + self.additional_properties_detection = True + + def __call__(self, target_obj, response_data, content_type=None): + """Call the deserializer to process a REST response. + + :param str target_obj: Target data type to deserialize to. + :param requests.Response response_data: REST response object. + :param str content_type: Swagger "produces" if available. + :raises DeserializationError: if deserialization fails. + :return: Deserialized object. + :rtype: object + """ + data = self._unpack_content(response_data, content_type) + return self._deserialize(target_obj, data) + + def _deserialize(self, target_obj, data): # pylint: disable=inconsistent-return-statements + """Call the deserializer on a model. + + Data needs to be already deserialized as JSON or XML ElementTree + + :param str target_obj: Target data type to deserialize to. + :param object data: Object to deserialize. + :raises DeserializationError: if deserialization fails. + :return: Deserialized object. + :rtype: object + """ + # This is already a model, go recursive just in case + if hasattr(data, "_attribute_map"): + constants = [name for name, config in getattr(data, "_validation", {}).items() if config.get("constant")] + try: + for attr, mapconfig in data._attribute_map.items(): # pylint: disable=protected-access + if attr in constants: + continue + value = getattr(data, attr) + if value is None: + continue + local_type = mapconfig["type"] + internal_data_type = local_type.strip("[]{}") + if internal_data_type not in self.dependencies or isinstance(internal_data_type, Enum): + continue + setattr(data, attr, self._deserialize(local_type, value)) + return data + except AttributeError: + return + + response, class_name = self._classify_target(target_obj, data) + + if isinstance(response, str): + return self.deserialize_data(data, response) + if isinstance(response, type) and issubclass(response, Enum): + return self.deserialize_enum(data, response) + + if data is None or data is CoreNull: + return data + try: + attributes = response._attribute_map # type: ignore # pylint: disable=protected-access + d_attrs = {} + for attr, attr_desc in attributes.items(): + # Check empty string. If it's not empty, someone has a real "additionalProperties"... + if attr == "additional_properties" and attr_desc["key"] == "": + continue + raw_value = None + # Enhance attr_desc with some dynamic data + attr_desc = attr_desc.copy() # Do a copy, do not change the real one + internal_data_type = attr_desc["type"].strip("[]{}") + if internal_data_type in self.dependencies: + attr_desc["internalType"] = self.dependencies[internal_data_type] + + for key_extractor in self.key_extractors: + found_value = key_extractor(attr, attr_desc, data) + if found_value is not None: + if raw_value is not None and raw_value != found_value: + msg = ( + "Ignoring extracted value '%s' from %s for key '%s'" + " (duplicate extraction, follow extractors order)" + ) + _LOGGER.warning(msg, found_value, key_extractor, attr) + continue + raw_value = found_value + + value = self.deserialize_data(raw_value, attr_desc["type"]) + d_attrs[attr] = value + except (AttributeError, TypeError, KeyError) as err: + msg = "Unable to deserialize to object: " + class_name # type: ignore + raise DeserializationError(msg) from err + additional_properties = self._build_additional_properties(attributes, data) + return self._instantiate_model(response, d_attrs, additional_properties) + + def _build_additional_properties(self, attribute_map, data): + if not self.additional_properties_detection: + return None + if "additional_properties" in attribute_map and attribute_map.get("additional_properties", {}).get("key") != "": + # Check empty string. If it's not empty, someone has a real "additionalProperties" + return None + if isinstance(data, ET.Element): + data = {el.tag: el.text for el in data} + + known_keys = { + _decode_attribute_map_key(_FLATTEN.split(desc["key"])[0]) + for desc in attribute_map.values() + if desc["key"] != "" + } + present_keys = set(data.keys()) + missing_keys = present_keys - known_keys + return {key: data[key] for key in missing_keys} + + def _classify_target(self, target, data): + """Check to see whether the deserialization target object can + be classified into a subclass. + Once classification has been determined, initialize object. + + :param str target: The target object type to deserialize to. + :param str/dict data: The response data to deserialize. + :return: The classified target object and its class name. + :rtype: tuple + """ + if target is None: + return None, None + + if isinstance(target, str): + try: + target = self.dependencies[target] + except KeyError: + return target, target + + try: + target = target._classify(data, self.dependencies) # type: ignore # pylint: disable=protected-access + except AttributeError: + pass # Target is not a Model, no classify + return target, target.__class__.__name__ # type: ignore + + def failsafe_deserialize(self, target_obj, data, content_type=None): + """Ignores any errors encountered in deserialization, + and falls back to not deserializing the object. Recommended + for use in error deserialization, as we want to return the + HttpResponseError to users, and not have them deal with + a deserialization error. + + :param str target_obj: The target object type to deserialize to. + :param str/dict data: The response data to deserialize. + :param str content_type: Swagger "produces" if available. + :return: Deserialized object. + :rtype: object + """ + try: + return self(target_obj, data, content_type=content_type) + except: # pylint: disable=bare-except + _LOGGER.debug( + "Ran into a deserialization error. Ignoring since this is failsafe deserialization", exc_info=True + ) + return None + + @staticmethod + def _unpack_content(raw_data, content_type=None): + """Extract the correct structure for deserialization. + + If raw_data is a PipelineResponse, try to extract the result of RawDeserializer. + if we can't, raise. Your Pipeline should have a RawDeserializer. + + If not a pipeline response and raw_data is bytes or string, use content-type + to decode it. If no content-type, try JSON. + + If raw_data is something else, bypass all logic and return it directly. + + :param obj raw_data: Data to be processed. + :param str content_type: How to parse if raw_data is a string/bytes. + :raises JSONDecodeError: If JSON is requested and parsing is impossible. + :raises UnicodeDecodeError: If bytes is not UTF8 + :rtype: object + :return: Unpacked content. + """ + # Assume this is enough to detect a Pipeline Response without importing it + context = getattr(raw_data, "context", {}) + if context: + if RawDeserializer.CONTEXT_NAME in context: + return context[RawDeserializer.CONTEXT_NAME] + raise ValueError("This pipeline didn't have the RawDeserializer policy; can't deserialize") + + # Assume this is enough to recognize universal_http.ClientResponse without importing it + if hasattr(raw_data, "body"): + return RawDeserializer.deserialize_from_http_generics(raw_data.text(), raw_data.headers) + + # Assume this enough to recognize requests.Response without importing it. + if hasattr(raw_data, "_content_consumed"): + return RawDeserializer.deserialize_from_http_generics(raw_data.text, raw_data.headers) + + if isinstance(raw_data, (str, bytes)) or hasattr(raw_data, "read"): + return RawDeserializer.deserialize_from_text(raw_data, content_type) # type: ignore + return raw_data + + def _instantiate_model(self, response, attrs, additional_properties=None): + """Instantiate a response model passing in deserialized args. + + :param Response response: The response model class. + :param dict attrs: The deserialized response attributes. + :param dict additional_properties: Additional properties to be set. + :rtype: Response + :return: The instantiated response model. + """ + if callable(response): + subtype = getattr(response, "_subtype_map", {}) + try: + readonly = [ + k + for k, v in response._validation.items() # pylint: disable=protected-access # type: ignore + if v.get("readonly") + ] + const = [ + k + for k, v in response._validation.items() # pylint: disable=protected-access # type: ignore + if v.get("constant") + ] + kwargs = {k: v for k, v in attrs.items() if k not in subtype and k not in readonly + const} + response_obj = response(**kwargs) + for attr in readonly: + setattr(response_obj, attr, attrs.get(attr)) + if additional_properties: + response_obj.additional_properties = additional_properties # type: ignore + return response_obj + except TypeError as err: + msg = "Unable to deserialize {} into model {}. ".format(kwargs, response) # type: ignore + raise DeserializationError(msg + str(err)) from err + else: + try: + for attr, value in attrs.items(): + setattr(response, attr, value) + return response + except Exception as exp: + msg = "Unable to populate response model. " + msg += "Type: {}, Error: {}".format(type(response), exp) + raise DeserializationError(msg) from exp + + def deserialize_data(self, data, data_type): # pylint: disable=too-many-return-statements + """Process data for deserialization according to data type. + + :param str data: The response string to be deserialized. + :param str data_type: The type to deserialize to. + :raises DeserializationError: if deserialization fails. + :return: Deserialized object. + :rtype: object + """ + if data is None: + return data + + try: + if not data_type: + return data + if data_type in self.basic_types.values(): + return self.deserialize_basic(data, data_type) + if data_type in self.deserialize_type: + if isinstance(data, self.deserialize_expected_types.get(data_type, tuple())): + return data + + is_a_text_parsing_type = lambda x: x not in [ # pylint: disable=unnecessary-lambda-assignment + "object", + "[]", + r"{}", + ] + if isinstance(data, ET.Element) and is_a_text_parsing_type(data_type) and not data.text: + return None + data_val = self.deserialize_type[data_type](data) + return data_val + + iter_type = data_type[0] + data_type[-1] + if iter_type in self.deserialize_type: + return self.deserialize_type[iter_type](data, data_type[1:-1]) + + obj_type = self.dependencies[data_type] + if issubclass(obj_type, Enum): + if isinstance(data, ET.Element): + data = data.text + return self.deserialize_enum(data, obj_type) + + except (ValueError, TypeError, AttributeError) as err: + msg = "Unable to deserialize response data." + msg += " Data: {}, {}".format(data, data_type) + raise DeserializationError(msg) from err + return self._deserialize(obj_type, data) + + def deserialize_iter(self, attr, iter_type): + """Deserialize an iterable. + + :param list attr: Iterable to be deserialized. + :param str iter_type: The type of object in the iterable. + :return: Deserialized iterable. + :rtype: list + """ + if attr is None: + return None + if isinstance(attr, ET.Element): # If I receive an element here, get the children + attr = list(attr) + if not isinstance(attr, (list, set)): + raise DeserializationError("Cannot deserialize as [{}] an object of type {}".format(iter_type, type(attr))) + return [self.deserialize_data(a, iter_type) for a in attr] + + def deserialize_dict(self, attr, dict_type): + """Deserialize a dictionary. + + :param dict/list attr: Dictionary to be deserialized. Also accepts + a list of key, value pairs. + :param str dict_type: The object type of the items in the dictionary. + :return: Deserialized dictionary. + :rtype: dict + """ + if isinstance(attr, list): + return {x["key"]: self.deserialize_data(x["value"], dict_type) for x in attr} + + if isinstance(attr, ET.Element): + # Transform value into {"Key": "value"} + attr = {el.tag: el.text for el in attr} + return {k: self.deserialize_data(v, dict_type) for k, v in attr.items()} + + def deserialize_object(self, attr, **kwargs): # pylint: disable=too-many-return-statements + """Deserialize a generic object. + This will be handled as a dictionary. + + :param dict attr: Dictionary to be deserialized. + :return: Deserialized object. + :rtype: dict + :raises TypeError: if non-builtin datatype encountered. + """ + if attr is None: + return None + if isinstance(attr, ET.Element): + # Do no recurse on XML, just return the tree as-is + return attr + if isinstance(attr, str): + return self.deserialize_basic(attr, "str") + obj_type = type(attr) + if obj_type in self.basic_types: + return self.deserialize_basic(attr, self.basic_types[obj_type]) + if obj_type is _long_type: + return self.deserialize_long(attr) + + if obj_type == dict: + deserialized = {} + for key, value in attr.items(): + try: + deserialized[key] = self.deserialize_object(value, **kwargs) + except ValueError: + deserialized[key] = None + return deserialized + + if obj_type == list: + deserialized = [] + for obj in attr: + try: + deserialized.append(self.deserialize_object(obj, **kwargs)) + except ValueError: + pass + return deserialized + + error = "Cannot deserialize generic object with type: " + raise TypeError(error + str(obj_type)) + + def deserialize_basic(self, attr, data_type): # pylint: disable=too-many-return-statements + """Deserialize basic builtin data type from string. + Will attempt to convert to str, int, float and bool. + This function will also accept '1', '0', 'true' and 'false' as + valid bool values. + + :param str attr: response string to be deserialized. + :param str data_type: deserialization data type. + :return: Deserialized basic type. + :rtype: str, int, float or bool + :raises TypeError: if string format is not valid. + """ + # If we're here, data is supposed to be a basic type. + # If it's still an XML node, take the text + if isinstance(attr, ET.Element): + attr = attr.text + if not attr: + if data_type == "str": + # None or '', node is empty string. + return "" + # None or '', node with a strong type is None. + # Don't try to model "empty bool" or "empty int" + return None + + if data_type == "bool": + if attr in [True, False, 1, 0]: + return bool(attr) + if isinstance(attr, str): + if attr.lower() in ["true", "1"]: + return True + if attr.lower() in ["false", "0"]: + return False + raise TypeError("Invalid boolean value: {}".format(attr)) + + if data_type == "str": + return self.deserialize_unicode(attr) + return eval(data_type)(attr) # nosec # pylint: disable=eval-used + + @staticmethod + def deserialize_unicode(data): + """Preserve unicode objects in Python 2, otherwise return data + as a string. + + :param str data: response string to be deserialized. + :return: Deserialized string. + :rtype: str or unicode + """ + # We might be here because we have an enum modeled as string, + # and we try to deserialize a partial dict with enum inside + if isinstance(data, Enum): + return data + + # Consider this is real string + try: + if isinstance(data, unicode): # type: ignore + return data + except NameError: + return str(data) + return str(data) + + @staticmethod + def deserialize_enum(data, enum_obj): + """Deserialize string into enum object. + + If the string is not a valid enum value it will be returned as-is + and a warning will be logged. + + :param str data: Response string to be deserialized. If this value is + None or invalid it will be returned as-is. + :param Enum enum_obj: Enum object to deserialize to. + :return: Deserialized enum object. + :rtype: Enum + """ + if isinstance(data, enum_obj) or data is None: + return data + if isinstance(data, Enum): + data = data.value + if isinstance(data, int): + # Workaround. We might consider remove it in the future. + try: + return list(enum_obj.__members__.values())[data] + except IndexError as exc: + error = "{!r} is not a valid index for enum {!r}" + raise DeserializationError(error.format(data, enum_obj)) from exc + try: + return enum_obj(str(data)) + except ValueError: + for enum_value in enum_obj: + if enum_value.value.lower() == str(data).lower(): + return enum_value + # We don't fail anymore for unknown value, we deserialize as a string + _LOGGER.warning("Deserializer is not able to find %s as valid enum in %s", data, enum_obj) + return Deserializer.deserialize_unicode(data) + + @staticmethod + def deserialize_bytearray(attr): + """Deserialize string into bytearray. + + :param str attr: response string to be deserialized. + :return: Deserialized bytearray + :rtype: bytearray + :raises TypeError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + return bytearray(b64decode(attr)) # type: ignore + + @staticmethod + def deserialize_base64(attr): + """Deserialize base64 encoded string into string. + + :param str attr: response string to be deserialized. + :return: Deserialized base64 string + :rtype: bytearray + :raises TypeError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + padding = "=" * (3 - (len(attr) + 3) % 4) # type: ignore + attr = attr + padding # type: ignore + encoded = attr.replace("-", "+").replace("_", "/") + return b64decode(encoded) + + @staticmethod + def deserialize_decimal(attr): + """Deserialize string into Decimal object. + + :param str attr: response string to be deserialized. + :return: Deserialized decimal + :raises DeserializationError: if string format invalid. + :rtype: decimal + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + return decimal.Decimal(str(attr)) # type: ignore + except decimal.DecimalException as err: + msg = "Invalid decimal {}".format(attr) + raise DeserializationError(msg) from err + + @staticmethod + def deserialize_long(attr): + """Deserialize string into long (Py2) or int (Py3). + + :param str attr: response string to be deserialized. + :return: Deserialized int + :rtype: long or int + :raises ValueError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + return _long_type(attr) # type: ignore + + @staticmethod + def deserialize_duration(attr): + """Deserialize ISO-8601 formatted string into TimeDelta object. + + :param str attr: response string to be deserialized. + :return: Deserialized duration + :rtype: TimeDelta + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + duration = isodate.parse_duration(attr) + except (ValueError, OverflowError, AttributeError) as err: + msg = "Cannot deserialize duration object." + raise DeserializationError(msg) from err + return duration + + @staticmethod + def deserialize_date(attr): + """Deserialize ISO-8601 formatted string into Date object. + + :param str attr: response string to be deserialized. + :return: Deserialized date + :rtype: Date + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + if re.search(r"[^\W\d_]", attr, re.I + re.U): # type: ignore + raise DeserializationError("Date must have only digits and -. Received: %s" % attr) + # This must NOT use defaultmonth/defaultday. Using None ensure this raises an exception. + return isodate.parse_date(attr, defaultmonth=0, defaultday=0) + + @staticmethod + def deserialize_time(attr): + """Deserialize ISO-8601 formatted string into time object. + + :param str attr: response string to be deserialized. + :return: Deserialized time + :rtype: datetime.time + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + if re.search(r"[^\W\d_]", attr, re.I + re.U): # type: ignore + raise DeserializationError("Date must have only digits and -. Received: %s" % attr) + return isodate.parse_time(attr) + + @staticmethod + def deserialize_rfc(attr): + """Deserialize RFC-1123 formatted string into Datetime object. + + :param str attr: response string to be deserialized. + :return: Deserialized RFC datetime + :rtype: Datetime + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + parsed_date = email.utils.parsedate_tz(attr) # type: ignore + date_obj = datetime.datetime( + *parsed_date[:6], tzinfo=datetime.timezone(datetime.timedelta(minutes=(parsed_date[9] or 0) / 60)) + ) + if not date_obj.tzinfo: + date_obj = date_obj.astimezone(tz=TZ_UTC) + except ValueError as err: + msg = "Cannot deserialize to rfc datetime object." + raise DeserializationError(msg) from err + return date_obj + + @staticmethod + def deserialize_iso(attr): + """Deserialize ISO-8601 formatted string into Datetime object. + + :param str attr: response string to be deserialized. + :return: Deserialized ISO datetime + :rtype: Datetime + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + attr = attr.upper() # type: ignore + match = Deserializer.valid_date.match(attr) + if not match: + raise ValueError("Invalid datetime string: " + attr) + + check_decimal = attr.split(".") + if len(check_decimal) > 1: + decimal_str = "" + for digit in check_decimal[1]: + if digit.isdigit(): + decimal_str += digit + else: + break + if len(decimal_str) > 6: + attr = attr.replace(decimal_str, decimal_str[0:6]) + + date_obj = isodate.parse_datetime(attr) + test_utc = date_obj.utctimetuple() + if test_utc.tm_year > 9999 or test_utc.tm_year < 1: + raise OverflowError("Hit max or min date") + except (ValueError, OverflowError, AttributeError) as err: + msg = "Cannot deserialize datetime object." + raise DeserializationError(msg) from err + return date_obj + + @staticmethod + def deserialize_unix(attr): + """Serialize Datetime object into IntTime format. + This is represented as seconds. + + :param int attr: Object to be serialized. + :return: Deserialized datetime + :rtype: Datetime + :raises DeserializationError: if format invalid + """ + if isinstance(attr, ET.Element): + attr = int(attr.text) # type: ignore + try: + attr = int(attr) + date_obj = datetime.datetime.fromtimestamp(attr, TZ_UTC) + except ValueError as err: + msg = "Cannot deserialize to unix datetime object." + raise DeserializationError(msg) from err + return date_obj diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyTimeVersionTolerant/bodytimeversiontolerant/aio/_client.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyTimeVersionTolerant/bodytimeversiontolerant/aio/_client.py index 385a0d65779..625be8837d9 100644 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyTimeVersionTolerant/bodytimeversiontolerant/aio/_client.py +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyTimeVersionTolerant/bodytimeversiontolerant/aio/_client.py @@ -14,7 +14,7 @@ from azure.core.pipeline import policies from azure.core.rest import AsyncHttpResponse, HttpRequest -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import AutoRestTimeTestServiceConfiguration from .operations import TimeOperations diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyTimeVersionTolerant/bodytimeversiontolerant/aio/operations/_operations.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyTimeVersionTolerant/bodytimeversiontolerant/aio/operations/_operations.py index 5391d898575..ab3aaa64d6d 100644 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyTimeVersionTolerant/bodytimeversiontolerant/aio/operations/_operations.py +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyTimeVersionTolerant/bodytimeversiontolerant/aio/operations/_operations.py @@ -23,7 +23,7 @@ from azure.core.tracing.decorator_async import distributed_trace_async from azure.core.utils import case_insensitive_dict -from ..._serialization import Deserializer, Serializer +from ..._utils.serialization import Deserializer, Serializer from ...operations._operations import build_time_get_request, build_time_put_request from .._configuration import AutoRestTimeTestServiceConfiguration diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyTimeVersionTolerant/bodytimeversiontolerant/operations/_operations.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyTimeVersionTolerant/bodytimeversiontolerant/operations/_operations.py index 54ffb103d45..0dd0b5241fe 100644 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyTimeVersionTolerant/bodytimeversiontolerant/operations/_operations.py +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/BodyTimeVersionTolerant/bodytimeversiontolerant/operations/_operations.py @@ -24,7 +24,7 @@ from azure.core.utils import case_insensitive_dict from .._configuration import AutoRestTimeTestServiceConfiguration -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ClientEnumVersionTolerant/clientenumversiontolerant/_client.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ClientEnumVersionTolerant/clientenumversiontolerant/_client.py index 33ebc3a8cfc..b7e167ed7f2 100644 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ClientEnumVersionTolerant/clientenumversiontolerant/_client.py +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ClientEnumVersionTolerant/clientenumversiontolerant/_client.py @@ -17,7 +17,7 @@ from . import models as _models from ._configuration import ClientWithEnumConfiguration from ._operations import ClientWithEnumOperationsMixin -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer class ClientWithEnum(ClientWithEnumOperationsMixin): # pylint: disable=client-accepts-api-version-keyword diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ClientEnumVersionTolerant/clientenumversiontolerant/_operations/_operations.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ClientEnumVersionTolerant/clientenumversiontolerant/_operations/_operations.py index 81a48bfcb49..9ef06d356fd 100644 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ClientEnumVersionTolerant/clientenumversiontolerant/_operations/_operations.py +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ClientEnumVersionTolerant/clientenumversiontolerant/_operations/_operations.py @@ -8,6 +8,7 @@ from collections.abc import MutableMapping from typing import Any, Callable, Dict, Optional, TypeVar, Union +from azure.core import PipelineClient from azure.core.exceptions import ( ClientAuthenticationError, HttpResponseError, @@ -22,8 +23,9 @@ from azure.core.utils import case_insensitive_dict from .. import models as _models -from .._serialization import Serializer -from .._vendor import ClientWithEnumMixinABC +from .._configuration import ClientWithEnumConfiguration +from .._utils.serialization import Serializer +from .._utils.utils import ClientMixinABC T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] @@ -44,7 +46,7 @@ def build_client_with_enum_head_request(*, x_ms_enum: Union[str, _models.Enum0], return HttpRequest(method="HEAD", url=_url, headers=_headers, **kwargs) -class ClientWithEnumOperationsMixin(ClientWithEnumMixinABC): +class ClientWithEnumOperationsMixin(ClientMixinABC[PipelineClient, ClientWithEnumConfiguration]): @distributed_trace def head(self, **kwargs: Any) -> None: # pylint: disable=inconsistent-return-statements diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ClientEnumVersionTolerant/clientenumversiontolerant/_utils/__init__.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ClientEnumVersionTolerant/clientenumversiontolerant/_utils/__init__.py new file mode 100644 index 00000000000..0af9b28f660 --- /dev/null +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ClientEnumVersionTolerant/clientenumversiontolerant/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ClientEnumVersionTolerant/clientenumversiontolerant/_utils/serialization.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ClientEnumVersionTolerant/clientenumversiontolerant/_utils/serialization.py new file mode 100644 index 00000000000..f5187701d7b --- /dev/null +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ClientEnumVersionTolerant/clientenumversiontolerant/_utils/serialization.py @@ -0,0 +1,2032 @@ +# pylint: disable=line-too-long,useless-suppression,too-many-lines +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +# pyright: reportUnnecessaryTypeIgnoreComment=false + +from base64 import b64decode, b64encode +import calendar +import datetime +import decimal +import email +from enum import Enum +import json +import logging +import re +import sys +import codecs +from typing import ( + Dict, + Any, + cast, + Optional, + Union, + AnyStr, + IO, + Mapping, + Callable, + MutableMapping, + List, +) + +try: + from urllib import quote # type: ignore +except ImportError: + from urllib.parse import quote +import xml.etree.ElementTree as ET + +import isodate # type: ignore +from typing_extensions import Self + +from azure.core.exceptions import DeserializationError, SerializationError +from azure.core.serialization import NULL as CoreNull + +_BOM = codecs.BOM_UTF8.decode(encoding="utf-8") + +JSON = MutableMapping[str, Any] + + +class RawDeserializer: + + # Accept "text" because we're open minded people... + JSON_REGEXP = re.compile(r"^(application|text)/([a-z+.]+\+)?json$") + + # Name used in context + CONTEXT_NAME = "deserialized_data" + + @classmethod + def deserialize_from_text(cls, data: Optional[Union[AnyStr, IO]], content_type: Optional[str] = None) -> Any: + """Decode data according to content-type. + + Accept a stream of data as well, but will be load at once in memory for now. + + If no content-type, will return the string version (not bytes, not stream) + + :param data: Input, could be bytes or stream (will be decoded with UTF8) or text + :type data: str or bytes or IO + :param str content_type: The content type. + :return: The deserialized data. + :rtype: object + """ + if hasattr(data, "read"): + # Assume a stream + data = cast(IO, data).read() + + if isinstance(data, bytes): + data_as_str = data.decode(encoding="utf-8-sig") + else: + # Explain to mypy the correct type. + data_as_str = cast(str, data) + + # Remove Byte Order Mark if present in string + data_as_str = data_as_str.lstrip(_BOM) + + if content_type is None: + return data + + if cls.JSON_REGEXP.match(content_type): + try: + return json.loads(data_as_str) + except ValueError as err: + raise DeserializationError("JSON is invalid: {}".format(err), err) from err + elif "xml" in (content_type or []): + try: + + try: + if isinstance(data, unicode): # type: ignore + # If I'm Python 2.7 and unicode XML will scream if I try a "fromstring" on unicode string + data_as_str = data_as_str.encode(encoding="utf-8") # type: ignore + except NameError: + pass + + return ET.fromstring(data_as_str) # nosec + except ET.ParseError as err: + # It might be because the server has an issue, and returned JSON with + # content-type XML.... + # So let's try a JSON load, and if it's still broken + # let's flow the initial exception + def _json_attemp(data): + try: + return True, json.loads(data) + except ValueError: + return False, None # Don't care about this one + + success, json_result = _json_attemp(data) + if success: + return json_result + # If i'm here, it's not JSON, it's not XML, let's scream + # and raise the last context in this block (the XML exception) + # The function hack is because Py2.7 messes up with exception + # context otherwise. + _LOGGER.critical("Wasn't XML not JSON, failing") + raise DeserializationError("XML is invalid") from err + elif content_type.startswith("text/"): + return data_as_str + raise DeserializationError("Cannot deserialize content-type: {}".format(content_type)) + + @classmethod + def deserialize_from_http_generics(cls, body_bytes: Optional[Union[AnyStr, IO]], headers: Mapping) -> Any: + """Deserialize from HTTP response. + + Use bytes and headers to NOT use any requests/aiohttp or whatever + specific implementation. + Headers will tested for "content-type" + + :param bytes body_bytes: The body of the response. + :param dict headers: The headers of the response. + :returns: The deserialized data. + :rtype: object + """ + # Try to use content-type from headers if available + content_type = None + if "content-type" in headers: + content_type = headers["content-type"].split(";")[0].strip().lower() + # Ouch, this server did not declare what it sent... + # Let's guess it's JSON... + # Also, since Autorest was considering that an empty body was a valid JSON, + # need that test as well.... + else: + content_type = "application/json" + + if body_bytes: + return cls.deserialize_from_text(body_bytes, content_type) + return None + + +_LOGGER = logging.getLogger(__name__) + +try: + _long_type = long # type: ignore +except NameError: + _long_type = int + +TZ_UTC = datetime.timezone.utc + +_FLATTEN = re.compile(r"(? None: + self.additional_properties: Optional[Dict[str, Any]] = {} + for k in kwargs: # pylint: disable=consider-using-dict-items + if k not in self._attribute_map: + _LOGGER.warning("%s is not a known attribute of class %s and will be ignored", k, self.__class__) + elif k in self._validation and self._validation[k].get("readonly", False): + _LOGGER.warning("Readonly attribute %s will be ignored in class %s", k, self.__class__) + else: + setattr(self, k, kwargs[k]) + + def __eq__(self, other: Any) -> bool: + """Compare objects by comparing all attributes. + + :param object other: The object to compare + :returns: True if objects are equal + :rtype: bool + """ + if isinstance(other, self.__class__): + return self.__dict__ == other.__dict__ + return False + + def __ne__(self, other: Any) -> bool: + """Compare objects by comparing all attributes. + + :param object other: The object to compare + :returns: True if objects are not equal + :rtype: bool + """ + return not self.__eq__(other) + + def __str__(self) -> str: + return str(self.__dict__) + + @classmethod + def enable_additional_properties_sending(cls) -> None: + cls._attribute_map["additional_properties"] = {"key": "", "type": "{object}"} + + @classmethod + def is_xml_model(cls) -> bool: + try: + cls._xml_map # type: ignore + except AttributeError: + return False + return True + + @classmethod + def _create_xml_node(cls): + """Create XML node. + + :returns: The XML node + :rtype: xml.etree.ElementTree.Element + """ + try: + xml_map = cls._xml_map # type: ignore + except AttributeError: + xml_map = {} + + return _create_xml_node(xml_map.get("name", cls.__name__), xml_map.get("prefix", None), xml_map.get("ns", None)) + + def serialize(self, keep_readonly: bool = False, **kwargs: Any) -> JSON: + """Return the JSON that would be sent to server from this model. + + This is an alias to `as_dict(full_restapi_key_transformer, keep_readonly=False)`. + + If you want XML serialization, you can pass the kwargs is_xml=True. + + :param bool keep_readonly: If you want to serialize the readonly attributes + :returns: A dict JSON compatible object + :rtype: dict + """ + serializer = Serializer(self._infer_class_models()) + return serializer._serialize( # type: ignore # pylint: disable=protected-access + self, keep_readonly=keep_readonly, **kwargs + ) + + def as_dict( + self, + keep_readonly: bool = True, + key_transformer: Callable[[str, Dict[str, Any], Any], Any] = attribute_transformer, + **kwargs: Any + ) -> JSON: + """Return a dict that can be serialized using json.dump. + + Advanced usage might optionally use a callback as parameter: + + .. code::python + + def my_key_transformer(key, attr_desc, value): + return key + + Key is the attribute name used in Python. Attr_desc + is a dict of metadata. Currently contains 'type' with the + msrest type and 'key' with the RestAPI encoded key. + Value is the current value in this object. + + The string returned will be used to serialize the key. + If the return type is a list, this is considered hierarchical + result dict. + + See the three examples in this file: + + - attribute_transformer + - full_restapi_key_transformer + - last_restapi_key_transformer + + If you want XML serialization, you can pass the kwargs is_xml=True. + + :param bool keep_readonly: If you want to serialize the readonly attributes + :param function key_transformer: A key transformer function. + :returns: A dict JSON compatible object + :rtype: dict + """ + serializer = Serializer(self._infer_class_models()) + return serializer._serialize( # type: ignore # pylint: disable=protected-access + self, key_transformer=key_transformer, keep_readonly=keep_readonly, **kwargs + ) + + @classmethod + def _infer_class_models(cls): + try: + str_models = cls.__module__.rsplit(".", 1)[0] + models = sys.modules[str_models] + client_models = {k: v for k, v in models.__dict__.items() if isinstance(v, type)} + if cls.__name__ not in client_models: + raise ValueError("Not Autorest generated code") + except Exception: # pylint: disable=broad-exception-caught + # Assume it's not Autorest generated (tests?). Add ourselves as dependencies. + client_models = {cls.__name__: cls} + return client_models + + @classmethod + def deserialize(cls, data: Any, content_type: Optional[str] = None) -> Self: + """Parse a str using the RestAPI syntax and return a model. + + :param str data: A str using RestAPI structure. JSON by default. + :param str content_type: JSON by default, set application/xml if XML. + :returns: An instance of this model + :raises DeserializationError: if something went wrong + :rtype: Self + """ + deserializer = Deserializer(cls._infer_class_models()) + return deserializer(cls.__name__, data, content_type=content_type) # type: ignore + + @classmethod + def from_dict( + cls, + data: Any, + key_extractors: Optional[Callable[[str, Dict[str, Any], Any], Any]] = None, + content_type: Optional[str] = None, + ) -> Self: + """Parse a dict using given key extractor return a model. + + By default consider key + extractors (rest_key_case_insensitive_extractor, attribute_key_case_insensitive_extractor + and last_rest_key_case_insensitive_extractor) + + :param dict data: A dict using RestAPI structure + :param function key_extractors: A key extractor function. + :param str content_type: JSON by default, set application/xml if XML. + :returns: An instance of this model + :raises DeserializationError: if something went wrong + :rtype: Self + """ + deserializer = Deserializer(cls._infer_class_models()) + deserializer.key_extractors = ( # type: ignore + [ # type: ignore + attribute_key_case_insensitive_extractor, + rest_key_case_insensitive_extractor, + last_rest_key_case_insensitive_extractor, + ] + if key_extractors is None + else key_extractors + ) + return deserializer(cls.__name__, data, content_type=content_type) # type: ignore + + @classmethod + def _flatten_subtype(cls, key, objects): + if "_subtype_map" not in cls.__dict__: + return {} + result = dict(cls._subtype_map[key]) + for valuetype in cls._subtype_map[key].values(): + result.update(objects[valuetype]._flatten_subtype(key, objects)) # pylint: disable=protected-access + return result + + @classmethod + def _classify(cls, response, objects): + """Check the class _subtype_map for any child classes. + We want to ignore any inherited _subtype_maps. + + :param dict response: The initial data + :param dict objects: The class objects + :returns: The class to be used + :rtype: class + """ + for subtype_key in cls.__dict__.get("_subtype_map", {}).keys(): + subtype_value = None + + if not isinstance(response, ET.Element): + rest_api_response_key = cls._get_rest_key_parts(subtype_key)[-1] + subtype_value = response.get(rest_api_response_key, None) or response.get(subtype_key, None) + else: + subtype_value = xml_key_extractor(subtype_key, cls._attribute_map[subtype_key], response) + if subtype_value: + # Try to match base class. Can be class name only + # (bug to fix in Autorest to support x-ms-discriminator-name) + if cls.__name__ == subtype_value: + return cls + flatten_mapping_type = cls._flatten_subtype(subtype_key, objects) + try: + return objects[flatten_mapping_type[subtype_value]] # type: ignore + except KeyError: + _LOGGER.warning( + "Subtype value %s has no mapping, use base class %s.", + subtype_value, + cls.__name__, + ) + break + else: + _LOGGER.warning("Discriminator %s is absent or null, use base class %s.", subtype_key, cls.__name__) + break + return cls + + @classmethod + def _get_rest_key_parts(cls, attr_key): + """Get the RestAPI key of this attr, split it and decode part + :param str attr_key: Attribute key must be in attribute_map. + :returns: A list of RestAPI part + :rtype: list + """ + rest_split_key = _FLATTEN.split(cls._attribute_map[attr_key]["key"]) + return [_decode_attribute_map_key(key_part) for key_part in rest_split_key] + + +def _decode_attribute_map_key(key): + """This decode a key in an _attribute_map to the actual key we want to look at + inside the received data. + + :param str key: A key string from the generated code + :returns: The decoded key + :rtype: str + """ + return key.replace("\\.", ".") + + +class Serializer: # pylint: disable=too-many-public-methods + """Request object model serializer.""" + + basic_types = {str: "str", int: "int", bool: "bool", float: "float"} + + _xml_basic_types_serializers = {"bool": lambda x: str(x).lower()} + days = {0: "Mon", 1: "Tue", 2: "Wed", 3: "Thu", 4: "Fri", 5: "Sat", 6: "Sun"} + months = { + 1: "Jan", + 2: "Feb", + 3: "Mar", + 4: "Apr", + 5: "May", + 6: "Jun", + 7: "Jul", + 8: "Aug", + 9: "Sep", + 10: "Oct", + 11: "Nov", + 12: "Dec", + } + validation = { + "min_length": lambda x, y: len(x) < y, + "max_length": lambda x, y: len(x) > y, + "minimum": lambda x, y: x < y, + "maximum": lambda x, y: x > y, + "minimum_ex": lambda x, y: x <= y, + "maximum_ex": lambda x, y: x >= y, + "min_items": lambda x, y: len(x) < y, + "max_items": lambda x, y: len(x) > y, + "pattern": lambda x, y: not re.match(y, x, re.UNICODE), + "unique": lambda x, y: len(x) != len(set(x)), + "multiple": lambda x, y: x % y != 0, + } + + def __init__(self, classes: Optional[Mapping[str, type]] = None) -> None: + self.serialize_type = { + "iso-8601": Serializer.serialize_iso, + "rfc-1123": Serializer.serialize_rfc, + "unix-time": Serializer.serialize_unix, + "duration": Serializer.serialize_duration, + "date": Serializer.serialize_date, + "time": Serializer.serialize_time, + "decimal": Serializer.serialize_decimal, + "long": Serializer.serialize_long, + "bytearray": Serializer.serialize_bytearray, + "base64": Serializer.serialize_base64, + "object": self.serialize_object, + "[]": self.serialize_iter, + "{}": self.serialize_dict, + } + self.dependencies: Dict[str, type] = dict(classes) if classes else {} + self.key_transformer = full_restapi_key_transformer + self.client_side_validation = True + + def _serialize( # pylint: disable=too-many-nested-blocks, too-many-branches, too-many-statements, too-many-locals + self, target_obj, data_type=None, **kwargs + ): + """Serialize data into a string according to type. + + :param object target_obj: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str, dict + :raises SerializationError: if serialization fails. + :returns: The serialized data. + """ + key_transformer = kwargs.get("key_transformer", self.key_transformer) + keep_readonly = kwargs.get("keep_readonly", False) + if target_obj is None: + return None + + attr_name = None + class_name = target_obj.__class__.__name__ + + if data_type: + return self.serialize_data(target_obj, data_type, **kwargs) + + if not hasattr(target_obj, "_attribute_map"): + data_type = type(target_obj).__name__ + if data_type in self.basic_types.values(): + return self.serialize_data(target_obj, data_type, **kwargs) + + # Force "is_xml" kwargs if we detect a XML model + try: + is_xml_model_serialization = kwargs["is_xml"] + except KeyError: + is_xml_model_serialization = kwargs.setdefault("is_xml", target_obj.is_xml_model()) + + serialized = {} + if is_xml_model_serialization: + serialized = target_obj._create_xml_node() # pylint: disable=protected-access + try: + attributes = target_obj._attribute_map # pylint: disable=protected-access + for attr, attr_desc in attributes.items(): + attr_name = attr + if not keep_readonly and target_obj._validation.get( # pylint: disable=protected-access + attr_name, {} + ).get("readonly", False): + continue + + if attr_name == "additional_properties" and attr_desc["key"] == "": + if target_obj.additional_properties is not None: + serialized.update(target_obj.additional_properties) + continue + try: + + orig_attr = getattr(target_obj, attr) + if is_xml_model_serialization: + pass # Don't provide "transformer" for XML for now. Keep "orig_attr" + else: # JSON + keys, orig_attr = key_transformer(attr, attr_desc.copy(), orig_attr) + keys = keys if isinstance(keys, list) else [keys] + + kwargs["serialization_ctxt"] = attr_desc + new_attr = self.serialize_data(orig_attr, attr_desc["type"], **kwargs) + + if is_xml_model_serialization: + xml_desc = attr_desc.get("xml", {}) + xml_name = xml_desc.get("name", attr_desc["key"]) + xml_prefix = xml_desc.get("prefix", None) + xml_ns = xml_desc.get("ns", None) + if xml_desc.get("attr", False): + if xml_ns: + ET.register_namespace(xml_prefix, xml_ns) + xml_name = "{{{}}}{}".format(xml_ns, xml_name) + serialized.set(xml_name, new_attr) # type: ignore + continue + if xml_desc.get("text", False): + serialized.text = new_attr # type: ignore + continue + if isinstance(new_attr, list): + serialized.extend(new_attr) # type: ignore + elif isinstance(new_attr, ET.Element): + # If the down XML has no XML/Name, + # we MUST replace the tag with the local tag. But keeping the namespaces. + if "name" not in getattr(orig_attr, "_xml_map", {}): + splitted_tag = new_attr.tag.split("}") + if len(splitted_tag) == 2: # Namespace + new_attr.tag = "}".join([splitted_tag[0], xml_name]) + else: + new_attr.tag = xml_name + serialized.append(new_attr) # type: ignore + else: # That's a basic type + # Integrate namespace if necessary + local_node = _create_xml_node(xml_name, xml_prefix, xml_ns) + local_node.text = str(new_attr) + serialized.append(local_node) # type: ignore + else: # JSON + for k in reversed(keys): # type: ignore + new_attr = {k: new_attr} + + _new_attr = new_attr + _serialized = serialized + for k in keys: # type: ignore + if k not in _serialized: + _serialized.update(_new_attr) # type: ignore + _new_attr = _new_attr[k] # type: ignore + _serialized = _serialized[k] + except ValueError as err: + if isinstance(err, SerializationError): + raise + + except (AttributeError, KeyError, TypeError) as err: + msg = "Attribute {} in object {} cannot be serialized.\n{}".format(attr_name, class_name, str(target_obj)) + raise SerializationError(msg) from err + return serialized + + def body(self, data, data_type, **kwargs): + """Serialize data intended for a request body. + + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: dict + :raises SerializationError: if serialization fails. + :raises ValueError: if data is None + :returns: The serialized request body + """ + + # Just in case this is a dict + internal_data_type_str = data_type.strip("[]{}") + internal_data_type = self.dependencies.get(internal_data_type_str, None) + try: + is_xml_model_serialization = kwargs["is_xml"] + except KeyError: + if internal_data_type and issubclass(internal_data_type, Model): + is_xml_model_serialization = kwargs.setdefault("is_xml", internal_data_type.is_xml_model()) + else: + is_xml_model_serialization = False + if internal_data_type and not isinstance(internal_data_type, Enum): + try: + deserializer = Deserializer(self.dependencies) + # Since it's on serialization, it's almost sure that format is not JSON REST + # We're not able to deal with additional properties for now. + deserializer.additional_properties_detection = False + if is_xml_model_serialization: + deserializer.key_extractors = [ # type: ignore + attribute_key_case_insensitive_extractor, + ] + else: + deserializer.key_extractors = [ + rest_key_case_insensitive_extractor, + attribute_key_case_insensitive_extractor, + last_rest_key_case_insensitive_extractor, + ] + data = deserializer._deserialize(data_type, data) # pylint: disable=protected-access + except DeserializationError as err: + raise SerializationError("Unable to build a model: " + str(err)) from err + + return self._serialize(data, data_type, **kwargs) + + def url(self, name, data, data_type, **kwargs): + """Serialize data intended for a URL path. + + :param str name: The name of the URL path parameter. + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str + :returns: The serialized URL path + :raises TypeError: if serialization fails. + :raises ValueError: if data is None + """ + try: + output = self.serialize_data(data, data_type, **kwargs) + if data_type == "bool": + output = json.dumps(output) + + if kwargs.get("skip_quote") is True: + output = str(output) + output = output.replace("{", quote("{")).replace("}", quote("}")) + else: + output = quote(str(output), safe="") + except SerializationError as exc: + raise TypeError("{} must be type {}.".format(name, data_type)) from exc + return output + + def query(self, name, data, data_type, **kwargs): + """Serialize data intended for a URL query. + + :param str name: The name of the query parameter. + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str, list + :raises TypeError: if serialization fails. + :raises ValueError: if data is None + :returns: The serialized query parameter + """ + try: + # Treat the list aside, since we don't want to encode the div separator + if data_type.startswith("["): + internal_data_type = data_type[1:-1] + do_quote = not kwargs.get("skip_quote", False) + return self.serialize_iter(data, internal_data_type, do_quote=do_quote, **kwargs) + + # Not a list, regular serialization + output = self.serialize_data(data, data_type, **kwargs) + if data_type == "bool": + output = json.dumps(output) + if kwargs.get("skip_quote") is True: + output = str(output) + else: + output = quote(str(output), safe="") + except SerializationError as exc: + raise TypeError("{} must be type {}.".format(name, data_type)) from exc + return str(output) + + def header(self, name, data, data_type, **kwargs): + """Serialize data intended for a request header. + + :param str name: The name of the header. + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str + :raises TypeError: if serialization fails. + :raises ValueError: if data is None + :returns: The serialized header + """ + try: + if data_type in ["[str]"]: + data = ["" if d is None else d for d in data] + + output = self.serialize_data(data, data_type, **kwargs) + if data_type == "bool": + output = json.dumps(output) + except SerializationError as exc: + raise TypeError("{} must be type {}.".format(name, data_type)) from exc + return str(output) + + def serialize_data(self, data, data_type, **kwargs): + """Serialize generic data according to supplied data type. + + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :raises AttributeError: if required data is None. + :raises ValueError: if data is None + :raises SerializationError: if serialization fails. + :returns: The serialized data. + :rtype: str, int, float, bool, dict, list + """ + if data is None: + raise ValueError("No value for given attribute") + + try: + if data is CoreNull: + return None + if data_type in self.basic_types.values(): + return self.serialize_basic(data, data_type, **kwargs) + + if data_type in self.serialize_type: + return self.serialize_type[data_type](data, **kwargs) + + # If dependencies is empty, try with current data class + # It has to be a subclass of Enum anyway + enum_type = self.dependencies.get(data_type, data.__class__) + if issubclass(enum_type, Enum): + return Serializer.serialize_enum(data, enum_obj=enum_type) + + iter_type = data_type[0] + data_type[-1] + if iter_type in self.serialize_type: + return self.serialize_type[iter_type](data, data_type[1:-1], **kwargs) + + except (ValueError, TypeError) as err: + msg = "Unable to serialize value: {!r} as type: {!r}." + raise SerializationError(msg.format(data, data_type)) from err + return self._serialize(data, **kwargs) + + @classmethod + def _get_custom_serializers(cls, data_type, **kwargs): # pylint: disable=inconsistent-return-statements + custom_serializer = kwargs.get("basic_types_serializers", {}).get(data_type) + if custom_serializer: + return custom_serializer + if kwargs.get("is_xml", False): + return cls._xml_basic_types_serializers.get(data_type) + + @classmethod + def serialize_basic(cls, data, data_type, **kwargs): + """Serialize basic builting data type. + Serializes objects to str, int, float or bool. + + Possible kwargs: + - basic_types_serializers dict[str, callable] : If set, use the callable as serializer + - is_xml bool : If set, use xml_basic_types_serializers + + :param obj data: Object to be serialized. + :param str data_type: Type of object in the iterable. + :rtype: str, int, float, bool + :return: serialized object + """ + custom_serializer = cls._get_custom_serializers(data_type, **kwargs) + if custom_serializer: + return custom_serializer(data) + if data_type == "str": + return cls.serialize_unicode(data) + return eval(data_type)(data) # nosec # pylint: disable=eval-used + + @classmethod + def serialize_unicode(cls, data): + """Special handling for serializing unicode strings in Py2. + Encode to UTF-8 if unicode, otherwise handle as a str. + + :param str data: Object to be serialized. + :rtype: str + :return: serialized object + """ + try: # If I received an enum, return its value + return data.value + except AttributeError: + pass + + try: + if isinstance(data, unicode): # type: ignore + # Don't change it, JSON and XML ElementTree are totally able + # to serialize correctly u'' strings + return data + except NameError: + return str(data) + return str(data) + + def serialize_iter(self, data, iter_type, div=None, **kwargs): + """Serialize iterable. + + Supported kwargs: + - serialization_ctxt dict : The current entry of _attribute_map, or same format. + serialization_ctxt['type'] should be same as data_type. + - is_xml bool : If set, serialize as XML + + :param list data: Object to be serialized. + :param str iter_type: Type of object in the iterable. + :param str div: If set, this str will be used to combine the elements + in the iterable into a combined string. Default is 'None'. + Defaults to False. + :rtype: list, str + :return: serialized iterable + """ + if isinstance(data, str): + raise SerializationError("Refuse str type as a valid iter type.") + + serialization_ctxt = kwargs.get("serialization_ctxt", {}) + is_xml = kwargs.get("is_xml", False) + + serialized = [] + for d in data: + try: + serialized.append(self.serialize_data(d, iter_type, **kwargs)) + except ValueError as err: + if isinstance(err, SerializationError): + raise + serialized.append(None) + + if kwargs.get("do_quote", False): + serialized = ["" if s is None else quote(str(s), safe="") for s in serialized] + + if div: + serialized = ["" if s is None else str(s) for s in serialized] + serialized = div.join(serialized) + + if "xml" in serialization_ctxt or is_xml: + # XML serialization is more complicated + xml_desc = serialization_ctxt.get("xml", {}) + xml_name = xml_desc.get("name") + if not xml_name: + xml_name = serialization_ctxt["key"] + + # Create a wrap node if necessary (use the fact that Element and list have "append") + is_wrapped = xml_desc.get("wrapped", False) + node_name = xml_desc.get("itemsName", xml_name) + if is_wrapped: + final_result = _create_xml_node(xml_name, xml_desc.get("prefix", None), xml_desc.get("ns", None)) + else: + final_result = [] + # All list elements to "local_node" + for el in serialized: + if isinstance(el, ET.Element): + el_node = el + else: + el_node = _create_xml_node(node_name, xml_desc.get("prefix", None), xml_desc.get("ns", None)) + if el is not None: # Otherwise it writes "None" :-p + el_node.text = str(el) + final_result.append(el_node) + return final_result + return serialized + + def serialize_dict(self, attr, dict_type, **kwargs): + """Serialize a dictionary of objects. + + :param dict attr: Object to be serialized. + :param str dict_type: Type of object in the dictionary. + :rtype: dict + :return: serialized dictionary + """ + serialization_ctxt = kwargs.get("serialization_ctxt", {}) + serialized = {} + for key, value in attr.items(): + try: + serialized[self.serialize_unicode(key)] = self.serialize_data(value, dict_type, **kwargs) + except ValueError as err: + if isinstance(err, SerializationError): + raise + serialized[self.serialize_unicode(key)] = None + + if "xml" in serialization_ctxt: + # XML serialization is more complicated + xml_desc = serialization_ctxt["xml"] + xml_name = xml_desc["name"] + + final_result = _create_xml_node(xml_name, xml_desc.get("prefix", None), xml_desc.get("ns", None)) + for key, value in serialized.items(): + ET.SubElement(final_result, key).text = value + return final_result + + return serialized + + def serialize_object(self, attr, **kwargs): # pylint: disable=too-many-return-statements + """Serialize a generic object. + This will be handled as a dictionary. If object passed in is not + a basic type (str, int, float, dict, list) it will simply be + cast to str. + + :param dict attr: Object to be serialized. + :rtype: dict or str + :return: serialized object + """ + if attr is None: + return None + if isinstance(attr, ET.Element): + return attr + obj_type = type(attr) + if obj_type in self.basic_types: + return self.serialize_basic(attr, self.basic_types[obj_type], **kwargs) + if obj_type is _long_type: + return self.serialize_long(attr) + if obj_type is str: + return self.serialize_unicode(attr) + if obj_type is datetime.datetime: + return self.serialize_iso(attr) + if obj_type is datetime.date: + return self.serialize_date(attr) + if obj_type is datetime.time: + return self.serialize_time(attr) + if obj_type is datetime.timedelta: + return self.serialize_duration(attr) + if obj_type is decimal.Decimal: + return self.serialize_decimal(attr) + + # If it's a model or I know this dependency, serialize as a Model + if obj_type in self.dependencies.values() or isinstance(attr, Model): + return self._serialize(attr) + + if obj_type == dict: + serialized = {} + for key, value in attr.items(): + try: + serialized[self.serialize_unicode(key)] = self.serialize_object(value, **kwargs) + except ValueError: + serialized[self.serialize_unicode(key)] = None + return serialized + + if obj_type == list: + serialized = [] + for obj in attr: + try: + serialized.append(self.serialize_object(obj, **kwargs)) + except ValueError: + pass + return serialized + return str(attr) + + @staticmethod + def serialize_enum(attr, enum_obj=None): + try: + result = attr.value + except AttributeError: + result = attr + try: + enum_obj(result) # type: ignore + return result + except ValueError as exc: + for enum_value in enum_obj: # type: ignore + if enum_value.value.lower() == str(attr).lower(): + return enum_value.value + error = "{!r} is not valid value for enum {!r}" + raise SerializationError(error.format(attr, enum_obj)) from exc + + @staticmethod + def serialize_bytearray(attr, **kwargs): # pylint: disable=unused-argument + """Serialize bytearray into base-64 string. + + :param str attr: Object to be serialized. + :rtype: str + :return: serialized base64 + """ + return b64encode(attr).decode() + + @staticmethod + def serialize_base64(attr, **kwargs): # pylint: disable=unused-argument + """Serialize str into base-64 string. + + :param str attr: Object to be serialized. + :rtype: str + :return: serialized base64 + """ + encoded = b64encode(attr).decode("ascii") + return encoded.strip("=").replace("+", "-").replace("/", "_") + + @staticmethod + def serialize_decimal(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Decimal object to float. + + :param decimal attr: Object to be serialized. + :rtype: float + :return: serialized decimal + """ + return float(attr) + + @staticmethod + def serialize_long(attr, **kwargs): # pylint: disable=unused-argument + """Serialize long (Py2) or int (Py3). + + :param int attr: Object to be serialized. + :rtype: int/long + :return: serialized long + """ + return _long_type(attr) + + @staticmethod + def serialize_date(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Date object into ISO-8601 formatted string. + + :param Date attr: Object to be serialized. + :rtype: str + :return: serialized date + """ + if isinstance(attr, str): + attr = isodate.parse_date(attr) + t = "{:04}-{:02}-{:02}".format(attr.year, attr.month, attr.day) + return t + + @staticmethod + def serialize_time(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Time object into ISO-8601 formatted string. + + :param datetime.time attr: Object to be serialized. + :rtype: str + :return: serialized time + """ + if isinstance(attr, str): + attr = isodate.parse_time(attr) + t = "{:02}:{:02}:{:02}".format(attr.hour, attr.minute, attr.second) + if attr.microsecond: + t += ".{:02}".format(attr.microsecond) + return t + + @staticmethod + def serialize_duration(attr, **kwargs): # pylint: disable=unused-argument + """Serialize TimeDelta object into ISO-8601 formatted string. + + :param TimeDelta attr: Object to be serialized. + :rtype: str + :return: serialized duration + """ + if isinstance(attr, str): + attr = isodate.parse_duration(attr) + return isodate.duration_isoformat(attr) + + @staticmethod + def serialize_rfc(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Datetime object into RFC-1123 formatted string. + + :param Datetime attr: Object to be serialized. + :rtype: str + :raises TypeError: if format invalid. + :return: serialized rfc + """ + try: + if not attr.tzinfo: + _LOGGER.warning("Datetime with no tzinfo will be considered UTC.") + utc = attr.utctimetuple() + except AttributeError as exc: + raise TypeError("RFC1123 object must be valid Datetime object.") from exc + + return "{}, {:02} {} {:04} {:02}:{:02}:{:02} GMT".format( + Serializer.days[utc.tm_wday], + utc.tm_mday, + Serializer.months[utc.tm_mon], + utc.tm_year, + utc.tm_hour, + utc.tm_min, + utc.tm_sec, + ) + + @staticmethod + def serialize_iso(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Datetime object into ISO-8601 formatted string. + + :param Datetime attr: Object to be serialized. + :rtype: str + :raises SerializationError: if format invalid. + :return: serialized iso + """ + if isinstance(attr, str): + attr = isodate.parse_datetime(attr) + try: + if not attr.tzinfo: + _LOGGER.warning("Datetime with no tzinfo will be considered UTC.") + utc = attr.utctimetuple() + if utc.tm_year > 9999 or utc.tm_year < 1: + raise OverflowError("Hit max or min date") + + microseconds = str(attr.microsecond).rjust(6, "0").rstrip("0").ljust(3, "0") + if microseconds: + microseconds = "." + microseconds + date = "{:04}-{:02}-{:02}T{:02}:{:02}:{:02}".format( + utc.tm_year, utc.tm_mon, utc.tm_mday, utc.tm_hour, utc.tm_min, utc.tm_sec + ) + return date + microseconds + "Z" + except (ValueError, OverflowError) as err: + msg = "Unable to serialize datetime object." + raise SerializationError(msg) from err + except AttributeError as err: + msg = "ISO-8601 object must be valid Datetime object." + raise TypeError(msg) from err + + @staticmethod + def serialize_unix(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Datetime object into IntTime format. + This is represented as seconds. + + :param Datetime attr: Object to be serialized. + :rtype: int + :raises SerializationError: if format invalid + :return: serialied unix + """ + if isinstance(attr, int): + return attr + try: + if not attr.tzinfo: + _LOGGER.warning("Datetime with no tzinfo will be considered UTC.") + return int(calendar.timegm(attr.utctimetuple())) + except AttributeError as exc: + raise TypeError("Unix time object must be valid Datetime object.") from exc + + +def rest_key_extractor(attr, attr_desc, data): # pylint: disable=unused-argument + key = attr_desc["key"] + working_data = data + + while "." in key: + # Need the cast, as for some reasons "split" is typed as list[str | Any] + dict_keys = cast(List[str], _FLATTEN.split(key)) + if len(dict_keys) == 1: + key = _decode_attribute_map_key(dict_keys[0]) + break + working_key = _decode_attribute_map_key(dict_keys[0]) + working_data = working_data.get(working_key, data) + if working_data is None: + # If at any point while following flatten JSON path see None, it means + # that all properties under are None as well + return None + key = ".".join(dict_keys[1:]) + + return working_data.get(key) + + +def rest_key_case_insensitive_extractor( # pylint: disable=unused-argument, inconsistent-return-statements + attr, attr_desc, data +): + key = attr_desc["key"] + working_data = data + + while "." in key: + dict_keys = _FLATTEN.split(key) + if len(dict_keys) == 1: + key = _decode_attribute_map_key(dict_keys[0]) + break + working_key = _decode_attribute_map_key(dict_keys[0]) + working_data = attribute_key_case_insensitive_extractor(working_key, None, working_data) + if working_data is None: + # If at any point while following flatten JSON path see None, it means + # that all properties under are None as well + return None + key = ".".join(dict_keys[1:]) + + if working_data: + return attribute_key_case_insensitive_extractor(key, None, working_data) + + +def last_rest_key_extractor(attr, attr_desc, data): # pylint: disable=unused-argument + """Extract the attribute in "data" based on the last part of the JSON path key. + + :param str attr: The attribute to extract + :param dict attr_desc: The attribute description + :param dict data: The data to extract from + :rtype: object + :returns: The extracted attribute + """ + key = attr_desc["key"] + dict_keys = _FLATTEN.split(key) + return attribute_key_extractor(dict_keys[-1], None, data) + + +def last_rest_key_case_insensitive_extractor(attr, attr_desc, data): # pylint: disable=unused-argument + """Extract the attribute in "data" based on the last part of the JSON path key. + + This is the case insensitive version of "last_rest_key_extractor" + :param str attr: The attribute to extract + :param dict attr_desc: The attribute description + :param dict data: The data to extract from + :rtype: object + :returns: The extracted attribute + """ + key = attr_desc["key"] + dict_keys = _FLATTEN.split(key) + return attribute_key_case_insensitive_extractor(dict_keys[-1], None, data) + + +def attribute_key_extractor(attr, _, data): + return data.get(attr) + + +def attribute_key_case_insensitive_extractor(attr, _, data): + found_key = None + lower_attr = attr.lower() + for key in data: + if lower_attr == key.lower(): + found_key = key + break + + return data.get(found_key) + + +def _extract_name_from_internal_type(internal_type): + """Given an internal type XML description, extract correct XML name with namespace. + + :param dict internal_type: An model type + :rtype: tuple + :returns: A tuple XML name + namespace dict + """ + internal_type_xml_map = getattr(internal_type, "_xml_map", {}) + xml_name = internal_type_xml_map.get("name", internal_type.__name__) + xml_ns = internal_type_xml_map.get("ns", None) + if xml_ns: + xml_name = "{{{}}}{}".format(xml_ns, xml_name) + return xml_name + + +def xml_key_extractor(attr, attr_desc, data): # pylint: disable=unused-argument,too-many-return-statements + if isinstance(data, dict): + return None + + # Test if this model is XML ready first + if not isinstance(data, ET.Element): + return None + + xml_desc = attr_desc.get("xml", {}) + xml_name = xml_desc.get("name", attr_desc["key"]) + + # Look for a children + is_iter_type = attr_desc["type"].startswith("[") + is_wrapped = xml_desc.get("wrapped", False) + internal_type = attr_desc.get("internalType", None) + internal_type_xml_map = getattr(internal_type, "_xml_map", {}) + + # Integrate namespace if necessary + xml_ns = xml_desc.get("ns", internal_type_xml_map.get("ns", None)) + if xml_ns: + xml_name = "{{{}}}{}".format(xml_ns, xml_name) + + # If it's an attribute, that's simple + if xml_desc.get("attr", False): + return data.get(xml_name) + + # If it's x-ms-text, that's simple too + if xml_desc.get("text", False): + return data.text + + # Scenario where I take the local name: + # - Wrapped node + # - Internal type is an enum (considered basic types) + # - Internal type has no XML/Name node + if is_wrapped or (internal_type and (issubclass(internal_type, Enum) or "name" not in internal_type_xml_map)): + children = data.findall(xml_name) + # If internal type has a local name and it's not a list, I use that name + elif not is_iter_type and internal_type and "name" in internal_type_xml_map: + xml_name = _extract_name_from_internal_type(internal_type) + children = data.findall(xml_name) + # That's an array + else: + if internal_type: # Complex type, ignore itemsName and use the complex type name + items_name = _extract_name_from_internal_type(internal_type) + else: + items_name = xml_desc.get("itemsName", xml_name) + children = data.findall(items_name) + + if len(children) == 0: + if is_iter_type: + if is_wrapped: + return None # is_wrapped no node, we want None + return [] # not wrapped, assume empty list + return None # Assume it's not there, maybe an optional node. + + # If is_iter_type and not wrapped, return all found children + if is_iter_type: + if not is_wrapped: + return children + # Iter and wrapped, should have found one node only (the wrap one) + if len(children) != 1: + raise DeserializationError( + "Tried to deserialize an array not wrapped, and found several nodes '{}'. Maybe you should declare this array as wrapped?".format( + xml_name + ) + ) + return list(children[0]) # Might be empty list and that's ok. + + # Here it's not a itertype, we should have found one element only or empty + if len(children) > 1: + raise DeserializationError("Find several XML '{}' where it was not expected".format(xml_name)) + return children[0] + + +class Deserializer: + """Response object model deserializer. + + :param dict classes: Class type dictionary for deserializing complex types. + :ivar list key_extractors: Ordered list of extractors to be used by this deserializer. + """ + + basic_types = {str: "str", int: "int", bool: "bool", float: "float"} + + valid_date = re.compile(r"\d{4}[-]\d{2}[-]\d{2}T\d{2}:\d{2}:\d{2}\.?\d*Z?[-+]?[\d{2}]?:?[\d{2}]?") + + def __init__(self, classes: Optional[Mapping[str, type]] = None) -> None: + self.deserialize_type = { + "iso-8601": Deserializer.deserialize_iso, + "rfc-1123": Deserializer.deserialize_rfc, + "unix-time": Deserializer.deserialize_unix, + "duration": Deserializer.deserialize_duration, + "date": Deserializer.deserialize_date, + "time": Deserializer.deserialize_time, + "decimal": Deserializer.deserialize_decimal, + "long": Deserializer.deserialize_long, + "bytearray": Deserializer.deserialize_bytearray, + "base64": Deserializer.deserialize_base64, + "object": self.deserialize_object, + "[]": self.deserialize_iter, + "{}": self.deserialize_dict, + } + self.deserialize_expected_types = { + "duration": (isodate.Duration, datetime.timedelta), + "iso-8601": (datetime.datetime), + } + self.dependencies: Dict[str, type] = dict(classes) if classes else {} + self.key_extractors = [rest_key_extractor, xml_key_extractor] + # Additional properties only works if the "rest_key_extractor" is used to + # extract the keys. Making it to work whatever the key extractor is too much + # complicated, with no real scenario for now. + # So adding a flag to disable additional properties detection. This flag should be + # used if your expect the deserialization to NOT come from a JSON REST syntax. + # Otherwise, result are unexpected + self.additional_properties_detection = True + + def __call__(self, target_obj, response_data, content_type=None): + """Call the deserializer to process a REST response. + + :param str target_obj: Target data type to deserialize to. + :param requests.Response response_data: REST response object. + :param str content_type: Swagger "produces" if available. + :raises DeserializationError: if deserialization fails. + :return: Deserialized object. + :rtype: object + """ + data = self._unpack_content(response_data, content_type) + return self._deserialize(target_obj, data) + + def _deserialize(self, target_obj, data): # pylint: disable=inconsistent-return-statements + """Call the deserializer on a model. + + Data needs to be already deserialized as JSON or XML ElementTree + + :param str target_obj: Target data type to deserialize to. + :param object data: Object to deserialize. + :raises DeserializationError: if deserialization fails. + :return: Deserialized object. + :rtype: object + """ + # This is already a model, go recursive just in case + if hasattr(data, "_attribute_map"): + constants = [name for name, config in getattr(data, "_validation", {}).items() if config.get("constant")] + try: + for attr, mapconfig in data._attribute_map.items(): # pylint: disable=protected-access + if attr in constants: + continue + value = getattr(data, attr) + if value is None: + continue + local_type = mapconfig["type"] + internal_data_type = local_type.strip("[]{}") + if internal_data_type not in self.dependencies or isinstance(internal_data_type, Enum): + continue + setattr(data, attr, self._deserialize(local_type, value)) + return data + except AttributeError: + return + + response, class_name = self._classify_target(target_obj, data) + + if isinstance(response, str): + return self.deserialize_data(data, response) + if isinstance(response, type) and issubclass(response, Enum): + return self.deserialize_enum(data, response) + + if data is None or data is CoreNull: + return data + try: + attributes = response._attribute_map # type: ignore # pylint: disable=protected-access + d_attrs = {} + for attr, attr_desc in attributes.items(): + # Check empty string. If it's not empty, someone has a real "additionalProperties"... + if attr == "additional_properties" and attr_desc["key"] == "": + continue + raw_value = None + # Enhance attr_desc with some dynamic data + attr_desc = attr_desc.copy() # Do a copy, do not change the real one + internal_data_type = attr_desc["type"].strip("[]{}") + if internal_data_type in self.dependencies: + attr_desc["internalType"] = self.dependencies[internal_data_type] + + for key_extractor in self.key_extractors: + found_value = key_extractor(attr, attr_desc, data) + if found_value is not None: + if raw_value is not None and raw_value != found_value: + msg = ( + "Ignoring extracted value '%s' from %s for key '%s'" + " (duplicate extraction, follow extractors order)" + ) + _LOGGER.warning(msg, found_value, key_extractor, attr) + continue + raw_value = found_value + + value = self.deserialize_data(raw_value, attr_desc["type"]) + d_attrs[attr] = value + except (AttributeError, TypeError, KeyError) as err: + msg = "Unable to deserialize to object: " + class_name # type: ignore + raise DeserializationError(msg) from err + additional_properties = self._build_additional_properties(attributes, data) + return self._instantiate_model(response, d_attrs, additional_properties) + + def _build_additional_properties(self, attribute_map, data): + if not self.additional_properties_detection: + return None + if "additional_properties" in attribute_map and attribute_map.get("additional_properties", {}).get("key") != "": + # Check empty string. If it's not empty, someone has a real "additionalProperties" + return None + if isinstance(data, ET.Element): + data = {el.tag: el.text for el in data} + + known_keys = { + _decode_attribute_map_key(_FLATTEN.split(desc["key"])[0]) + for desc in attribute_map.values() + if desc["key"] != "" + } + present_keys = set(data.keys()) + missing_keys = present_keys - known_keys + return {key: data[key] for key in missing_keys} + + def _classify_target(self, target, data): + """Check to see whether the deserialization target object can + be classified into a subclass. + Once classification has been determined, initialize object. + + :param str target: The target object type to deserialize to. + :param str/dict data: The response data to deserialize. + :return: The classified target object and its class name. + :rtype: tuple + """ + if target is None: + return None, None + + if isinstance(target, str): + try: + target = self.dependencies[target] + except KeyError: + return target, target + + try: + target = target._classify(data, self.dependencies) # type: ignore # pylint: disable=protected-access + except AttributeError: + pass # Target is not a Model, no classify + return target, target.__class__.__name__ # type: ignore + + def failsafe_deserialize(self, target_obj, data, content_type=None): + """Ignores any errors encountered in deserialization, + and falls back to not deserializing the object. Recommended + for use in error deserialization, as we want to return the + HttpResponseError to users, and not have them deal with + a deserialization error. + + :param str target_obj: The target object type to deserialize to. + :param str/dict data: The response data to deserialize. + :param str content_type: Swagger "produces" if available. + :return: Deserialized object. + :rtype: object + """ + try: + return self(target_obj, data, content_type=content_type) + except: # pylint: disable=bare-except + _LOGGER.debug( + "Ran into a deserialization error. Ignoring since this is failsafe deserialization", exc_info=True + ) + return None + + @staticmethod + def _unpack_content(raw_data, content_type=None): + """Extract the correct structure for deserialization. + + If raw_data is a PipelineResponse, try to extract the result of RawDeserializer. + if we can't, raise. Your Pipeline should have a RawDeserializer. + + If not a pipeline response and raw_data is bytes or string, use content-type + to decode it. If no content-type, try JSON. + + If raw_data is something else, bypass all logic and return it directly. + + :param obj raw_data: Data to be processed. + :param str content_type: How to parse if raw_data is a string/bytes. + :raises JSONDecodeError: If JSON is requested and parsing is impossible. + :raises UnicodeDecodeError: If bytes is not UTF8 + :rtype: object + :return: Unpacked content. + """ + # Assume this is enough to detect a Pipeline Response without importing it + context = getattr(raw_data, "context", {}) + if context: + if RawDeserializer.CONTEXT_NAME in context: + return context[RawDeserializer.CONTEXT_NAME] + raise ValueError("This pipeline didn't have the RawDeserializer policy; can't deserialize") + + # Assume this is enough to recognize universal_http.ClientResponse without importing it + if hasattr(raw_data, "body"): + return RawDeserializer.deserialize_from_http_generics(raw_data.text(), raw_data.headers) + + # Assume this enough to recognize requests.Response without importing it. + if hasattr(raw_data, "_content_consumed"): + return RawDeserializer.deserialize_from_http_generics(raw_data.text, raw_data.headers) + + if isinstance(raw_data, (str, bytes)) or hasattr(raw_data, "read"): + return RawDeserializer.deserialize_from_text(raw_data, content_type) # type: ignore + return raw_data + + def _instantiate_model(self, response, attrs, additional_properties=None): + """Instantiate a response model passing in deserialized args. + + :param Response response: The response model class. + :param dict attrs: The deserialized response attributes. + :param dict additional_properties: Additional properties to be set. + :rtype: Response + :return: The instantiated response model. + """ + if callable(response): + subtype = getattr(response, "_subtype_map", {}) + try: + readonly = [ + k + for k, v in response._validation.items() # pylint: disable=protected-access # type: ignore + if v.get("readonly") + ] + const = [ + k + for k, v in response._validation.items() # pylint: disable=protected-access # type: ignore + if v.get("constant") + ] + kwargs = {k: v for k, v in attrs.items() if k not in subtype and k not in readonly + const} + response_obj = response(**kwargs) + for attr in readonly: + setattr(response_obj, attr, attrs.get(attr)) + if additional_properties: + response_obj.additional_properties = additional_properties # type: ignore + return response_obj + except TypeError as err: + msg = "Unable to deserialize {} into model {}. ".format(kwargs, response) # type: ignore + raise DeserializationError(msg + str(err)) from err + else: + try: + for attr, value in attrs.items(): + setattr(response, attr, value) + return response + except Exception as exp: + msg = "Unable to populate response model. " + msg += "Type: {}, Error: {}".format(type(response), exp) + raise DeserializationError(msg) from exp + + def deserialize_data(self, data, data_type): # pylint: disable=too-many-return-statements + """Process data for deserialization according to data type. + + :param str data: The response string to be deserialized. + :param str data_type: The type to deserialize to. + :raises DeserializationError: if deserialization fails. + :return: Deserialized object. + :rtype: object + """ + if data is None: + return data + + try: + if not data_type: + return data + if data_type in self.basic_types.values(): + return self.deserialize_basic(data, data_type) + if data_type in self.deserialize_type: + if isinstance(data, self.deserialize_expected_types.get(data_type, tuple())): + return data + + is_a_text_parsing_type = lambda x: x not in [ # pylint: disable=unnecessary-lambda-assignment + "object", + "[]", + r"{}", + ] + if isinstance(data, ET.Element) and is_a_text_parsing_type(data_type) and not data.text: + return None + data_val = self.deserialize_type[data_type](data) + return data_val + + iter_type = data_type[0] + data_type[-1] + if iter_type in self.deserialize_type: + return self.deserialize_type[iter_type](data, data_type[1:-1]) + + obj_type = self.dependencies[data_type] + if issubclass(obj_type, Enum): + if isinstance(data, ET.Element): + data = data.text + return self.deserialize_enum(data, obj_type) + + except (ValueError, TypeError, AttributeError) as err: + msg = "Unable to deserialize response data." + msg += " Data: {}, {}".format(data, data_type) + raise DeserializationError(msg) from err + return self._deserialize(obj_type, data) + + def deserialize_iter(self, attr, iter_type): + """Deserialize an iterable. + + :param list attr: Iterable to be deserialized. + :param str iter_type: The type of object in the iterable. + :return: Deserialized iterable. + :rtype: list + """ + if attr is None: + return None + if isinstance(attr, ET.Element): # If I receive an element here, get the children + attr = list(attr) + if not isinstance(attr, (list, set)): + raise DeserializationError("Cannot deserialize as [{}] an object of type {}".format(iter_type, type(attr))) + return [self.deserialize_data(a, iter_type) for a in attr] + + def deserialize_dict(self, attr, dict_type): + """Deserialize a dictionary. + + :param dict/list attr: Dictionary to be deserialized. Also accepts + a list of key, value pairs. + :param str dict_type: The object type of the items in the dictionary. + :return: Deserialized dictionary. + :rtype: dict + """ + if isinstance(attr, list): + return {x["key"]: self.deserialize_data(x["value"], dict_type) for x in attr} + + if isinstance(attr, ET.Element): + # Transform value into {"Key": "value"} + attr = {el.tag: el.text for el in attr} + return {k: self.deserialize_data(v, dict_type) for k, v in attr.items()} + + def deserialize_object(self, attr, **kwargs): # pylint: disable=too-many-return-statements + """Deserialize a generic object. + This will be handled as a dictionary. + + :param dict attr: Dictionary to be deserialized. + :return: Deserialized object. + :rtype: dict + :raises TypeError: if non-builtin datatype encountered. + """ + if attr is None: + return None + if isinstance(attr, ET.Element): + # Do no recurse on XML, just return the tree as-is + return attr + if isinstance(attr, str): + return self.deserialize_basic(attr, "str") + obj_type = type(attr) + if obj_type in self.basic_types: + return self.deserialize_basic(attr, self.basic_types[obj_type]) + if obj_type is _long_type: + return self.deserialize_long(attr) + + if obj_type == dict: + deserialized = {} + for key, value in attr.items(): + try: + deserialized[key] = self.deserialize_object(value, **kwargs) + except ValueError: + deserialized[key] = None + return deserialized + + if obj_type == list: + deserialized = [] + for obj in attr: + try: + deserialized.append(self.deserialize_object(obj, **kwargs)) + except ValueError: + pass + return deserialized + + error = "Cannot deserialize generic object with type: " + raise TypeError(error + str(obj_type)) + + def deserialize_basic(self, attr, data_type): # pylint: disable=too-many-return-statements + """Deserialize basic builtin data type from string. + Will attempt to convert to str, int, float and bool. + This function will also accept '1', '0', 'true' and 'false' as + valid bool values. + + :param str attr: response string to be deserialized. + :param str data_type: deserialization data type. + :return: Deserialized basic type. + :rtype: str, int, float or bool + :raises TypeError: if string format is not valid. + """ + # If we're here, data is supposed to be a basic type. + # If it's still an XML node, take the text + if isinstance(attr, ET.Element): + attr = attr.text + if not attr: + if data_type == "str": + # None or '', node is empty string. + return "" + # None or '', node with a strong type is None. + # Don't try to model "empty bool" or "empty int" + return None + + if data_type == "bool": + if attr in [True, False, 1, 0]: + return bool(attr) + if isinstance(attr, str): + if attr.lower() in ["true", "1"]: + return True + if attr.lower() in ["false", "0"]: + return False + raise TypeError("Invalid boolean value: {}".format(attr)) + + if data_type == "str": + return self.deserialize_unicode(attr) + return eval(data_type)(attr) # nosec # pylint: disable=eval-used + + @staticmethod + def deserialize_unicode(data): + """Preserve unicode objects in Python 2, otherwise return data + as a string. + + :param str data: response string to be deserialized. + :return: Deserialized string. + :rtype: str or unicode + """ + # We might be here because we have an enum modeled as string, + # and we try to deserialize a partial dict with enum inside + if isinstance(data, Enum): + return data + + # Consider this is real string + try: + if isinstance(data, unicode): # type: ignore + return data + except NameError: + return str(data) + return str(data) + + @staticmethod + def deserialize_enum(data, enum_obj): + """Deserialize string into enum object. + + If the string is not a valid enum value it will be returned as-is + and a warning will be logged. + + :param str data: Response string to be deserialized. If this value is + None or invalid it will be returned as-is. + :param Enum enum_obj: Enum object to deserialize to. + :return: Deserialized enum object. + :rtype: Enum + """ + if isinstance(data, enum_obj) or data is None: + return data + if isinstance(data, Enum): + data = data.value + if isinstance(data, int): + # Workaround. We might consider remove it in the future. + try: + return list(enum_obj.__members__.values())[data] + except IndexError as exc: + error = "{!r} is not a valid index for enum {!r}" + raise DeserializationError(error.format(data, enum_obj)) from exc + try: + return enum_obj(str(data)) + except ValueError: + for enum_value in enum_obj: + if enum_value.value.lower() == str(data).lower(): + return enum_value + # We don't fail anymore for unknown value, we deserialize as a string + _LOGGER.warning("Deserializer is not able to find %s as valid enum in %s", data, enum_obj) + return Deserializer.deserialize_unicode(data) + + @staticmethod + def deserialize_bytearray(attr): + """Deserialize string into bytearray. + + :param str attr: response string to be deserialized. + :return: Deserialized bytearray + :rtype: bytearray + :raises TypeError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + return bytearray(b64decode(attr)) # type: ignore + + @staticmethod + def deserialize_base64(attr): + """Deserialize base64 encoded string into string. + + :param str attr: response string to be deserialized. + :return: Deserialized base64 string + :rtype: bytearray + :raises TypeError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + padding = "=" * (3 - (len(attr) + 3) % 4) # type: ignore + attr = attr + padding # type: ignore + encoded = attr.replace("-", "+").replace("_", "/") + return b64decode(encoded) + + @staticmethod + def deserialize_decimal(attr): + """Deserialize string into Decimal object. + + :param str attr: response string to be deserialized. + :return: Deserialized decimal + :raises DeserializationError: if string format invalid. + :rtype: decimal + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + return decimal.Decimal(str(attr)) # type: ignore + except decimal.DecimalException as err: + msg = "Invalid decimal {}".format(attr) + raise DeserializationError(msg) from err + + @staticmethod + def deserialize_long(attr): + """Deserialize string into long (Py2) or int (Py3). + + :param str attr: response string to be deserialized. + :return: Deserialized int + :rtype: long or int + :raises ValueError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + return _long_type(attr) # type: ignore + + @staticmethod + def deserialize_duration(attr): + """Deserialize ISO-8601 formatted string into TimeDelta object. + + :param str attr: response string to be deserialized. + :return: Deserialized duration + :rtype: TimeDelta + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + duration = isodate.parse_duration(attr) + except (ValueError, OverflowError, AttributeError) as err: + msg = "Cannot deserialize duration object." + raise DeserializationError(msg) from err + return duration + + @staticmethod + def deserialize_date(attr): + """Deserialize ISO-8601 formatted string into Date object. + + :param str attr: response string to be deserialized. + :return: Deserialized date + :rtype: Date + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + if re.search(r"[^\W\d_]", attr, re.I + re.U): # type: ignore + raise DeserializationError("Date must have only digits and -. Received: %s" % attr) + # This must NOT use defaultmonth/defaultday. Using None ensure this raises an exception. + return isodate.parse_date(attr, defaultmonth=0, defaultday=0) + + @staticmethod + def deserialize_time(attr): + """Deserialize ISO-8601 formatted string into time object. + + :param str attr: response string to be deserialized. + :return: Deserialized time + :rtype: datetime.time + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + if re.search(r"[^\W\d_]", attr, re.I + re.U): # type: ignore + raise DeserializationError("Date must have only digits and -. Received: %s" % attr) + return isodate.parse_time(attr) + + @staticmethod + def deserialize_rfc(attr): + """Deserialize RFC-1123 formatted string into Datetime object. + + :param str attr: response string to be deserialized. + :return: Deserialized RFC datetime + :rtype: Datetime + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + parsed_date = email.utils.parsedate_tz(attr) # type: ignore + date_obj = datetime.datetime( + *parsed_date[:6], tzinfo=datetime.timezone(datetime.timedelta(minutes=(parsed_date[9] or 0) / 60)) + ) + if not date_obj.tzinfo: + date_obj = date_obj.astimezone(tz=TZ_UTC) + except ValueError as err: + msg = "Cannot deserialize to rfc datetime object." + raise DeserializationError(msg) from err + return date_obj + + @staticmethod + def deserialize_iso(attr): + """Deserialize ISO-8601 formatted string into Datetime object. + + :param str attr: response string to be deserialized. + :return: Deserialized ISO datetime + :rtype: Datetime + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + attr = attr.upper() # type: ignore + match = Deserializer.valid_date.match(attr) + if not match: + raise ValueError("Invalid datetime string: " + attr) + + check_decimal = attr.split(".") + if len(check_decimal) > 1: + decimal_str = "" + for digit in check_decimal[1]: + if digit.isdigit(): + decimal_str += digit + else: + break + if len(decimal_str) > 6: + attr = attr.replace(decimal_str, decimal_str[0:6]) + + date_obj = isodate.parse_datetime(attr) + test_utc = date_obj.utctimetuple() + if test_utc.tm_year > 9999 or test_utc.tm_year < 1: + raise OverflowError("Hit max or min date") + except (ValueError, OverflowError, AttributeError) as err: + msg = "Cannot deserialize datetime object." + raise DeserializationError(msg) from err + return date_obj + + @staticmethod + def deserialize_unix(attr): + """Serialize Datetime object into IntTime format. + This is represented as seconds. + + :param int attr: Object to be serialized. + :return: Deserialized datetime + :rtype: Datetime + :raises DeserializationError: if format invalid + """ + if isinstance(attr, ET.Element): + attr = int(attr.text) # type: ignore + try: + attr = int(attr) + date_obj = datetime.datetime.fromtimestamp(attr, TZ_UTC) + except ValueError as err: + msg = "Cannot deserialize to unix datetime object." + raise DeserializationError(msg) from err + return date_obj diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ClientEnumVersionTolerant/clientenumversiontolerant/_utils/utils.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ClientEnumVersionTolerant/clientenumversiontolerant/_utils/utils.py new file mode 100644 index 00000000000..39b612f39a9 --- /dev/null +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ClientEnumVersionTolerant/clientenumversiontolerant/_utils/utils.py @@ -0,0 +1,25 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from abc import ABC +from typing import Generic, TYPE_CHECKING, TypeVar + +if TYPE_CHECKING: + from .serialization import Deserializer, Serializer + + +TClient = TypeVar("TClient") +TConfig = TypeVar("TConfig") + + +class ClientMixinABC(ABC, Generic[TClient, TConfig]): + """DO NOT use this class. It is for internal typing use only.""" + + _client: TClient + _config: TConfig + _serialize: "Serializer" + _deserialize: "Deserializer" diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ClientEnumVersionTolerant/clientenumversiontolerant/_vendor.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ClientEnumVersionTolerant/clientenumversiontolerant/_vendor.py deleted file mode 100644 index f74d78ebfa4..00000000000 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ClientEnumVersionTolerant/clientenumversiontolerant/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) AutoRest Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import ClientWithEnumConfiguration - -if TYPE_CHECKING: - from azure.core import PipelineClient - - from ._serialization import Deserializer, Serializer - - -class ClientWithEnumMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "PipelineClient" - _config: ClientWithEnumConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ClientEnumVersionTolerant/clientenumversiontolerant/aio/_client.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ClientEnumVersionTolerant/clientenumversiontolerant/aio/_client.py index 92c0eeb9c2a..b6f52b1084e 100644 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ClientEnumVersionTolerant/clientenumversiontolerant/aio/_client.py +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ClientEnumVersionTolerant/clientenumversiontolerant/aio/_client.py @@ -15,7 +15,7 @@ from azure.core.rest import AsyncHttpResponse, HttpRequest from .. import models as _models -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import ClientWithEnumConfiguration from ._operations import ClientWithEnumOperationsMixin diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ClientEnumVersionTolerant/clientenumversiontolerant/aio/_operations/_operations.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ClientEnumVersionTolerant/clientenumversiontolerant/aio/_operations/_operations.py index 9f60d3e7ec1..23593cd7492 100644 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ClientEnumVersionTolerant/clientenumversiontolerant/aio/_operations/_operations.py +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ClientEnumVersionTolerant/clientenumversiontolerant/aio/_operations/_operations.py @@ -9,6 +9,7 @@ from collections.abc import MutableMapping from typing import Any, Callable, Dict, Optional, TypeVar +from azure.core import AsyncPipelineClient from azure.core.exceptions import ( ClientAuthenticationError, HttpResponseError, @@ -22,13 +23,14 @@ from azure.core.tracing.decorator_async import distributed_trace_async from ..._operations._operations import build_client_with_enum_head_request -from .._vendor import ClientWithEnumMixinABC +from ..._utils.utils import ClientMixinABC +from .._configuration import ClientWithEnumConfiguration T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, AsyncHttpResponse], T, Dict[str, Any]], Any]] -class ClientWithEnumOperationsMixin(ClientWithEnumMixinABC): +class ClientWithEnumOperationsMixin(ClientMixinABC[AsyncPipelineClient, ClientWithEnumConfiguration]): @distributed_trace_async async def head(self, **kwargs: Any) -> None: diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ClientEnumVersionTolerant/clientenumversiontolerant/aio/_vendor.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ClientEnumVersionTolerant/clientenumversiontolerant/aio/_vendor.py deleted file mode 100644 index 121f3fa2125..00000000000 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ClientEnumVersionTolerant/clientenumversiontolerant/aio/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) AutoRest Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import ClientWithEnumConfiguration - -if TYPE_CHECKING: - from azure.core import AsyncPipelineClient - - from .._serialization import Deserializer, Serializer - - -class ClientWithEnumMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "AsyncPipelineClient" - _config: ClientWithEnumConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ClientEnumVersionTolerant/clientenumversiontolerant/models/_models.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ClientEnumVersionTolerant/clientenumversiontolerant/models/_models.py index 1d1b7707def..109cf147510 100644 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ClientEnumVersionTolerant/clientenumversiontolerant/models/_models.py +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ClientEnumVersionTolerant/clientenumversiontolerant/models/_models.py @@ -8,7 +8,7 @@ from typing import Any, Optional -from .. import _serialization +from .._utils import serialization as _serialization class Error(_serialization.Model): diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ConstantsVersionTolerant/constantsversiontolerant/_client.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ConstantsVersionTolerant/constantsversiontolerant/_client.py index c03ff7f9b3b..7528dfc3743 100644 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ConstantsVersionTolerant/constantsversiontolerant/_client.py +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ConstantsVersionTolerant/constantsversiontolerant/_client.py @@ -15,7 +15,7 @@ from azure.core.rest import HttpRequest, HttpResponse from ._configuration import AutoRestSwaggerConstantServiceConfiguration -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer from .operations import ContantsOperations diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ConstantsVersionTolerant/constantsversiontolerant/_utils/__init__.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ConstantsVersionTolerant/constantsversiontolerant/_utils/__init__.py new file mode 100644 index 00000000000..0af9b28f660 --- /dev/null +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ConstantsVersionTolerant/constantsversiontolerant/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ConstantsVersionTolerant/constantsversiontolerant/_utils/serialization.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ConstantsVersionTolerant/constantsversiontolerant/_utils/serialization.py new file mode 100644 index 00000000000..f5187701d7b --- /dev/null +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ConstantsVersionTolerant/constantsversiontolerant/_utils/serialization.py @@ -0,0 +1,2032 @@ +# pylint: disable=line-too-long,useless-suppression,too-many-lines +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +# pyright: reportUnnecessaryTypeIgnoreComment=false + +from base64 import b64decode, b64encode +import calendar +import datetime +import decimal +import email +from enum import Enum +import json +import logging +import re +import sys +import codecs +from typing import ( + Dict, + Any, + cast, + Optional, + Union, + AnyStr, + IO, + Mapping, + Callable, + MutableMapping, + List, +) + +try: + from urllib import quote # type: ignore +except ImportError: + from urllib.parse import quote +import xml.etree.ElementTree as ET + +import isodate # type: ignore +from typing_extensions import Self + +from azure.core.exceptions import DeserializationError, SerializationError +from azure.core.serialization import NULL as CoreNull + +_BOM = codecs.BOM_UTF8.decode(encoding="utf-8") + +JSON = MutableMapping[str, Any] + + +class RawDeserializer: + + # Accept "text" because we're open minded people... + JSON_REGEXP = re.compile(r"^(application|text)/([a-z+.]+\+)?json$") + + # Name used in context + CONTEXT_NAME = "deserialized_data" + + @classmethod + def deserialize_from_text(cls, data: Optional[Union[AnyStr, IO]], content_type: Optional[str] = None) -> Any: + """Decode data according to content-type. + + Accept a stream of data as well, but will be load at once in memory for now. + + If no content-type, will return the string version (not bytes, not stream) + + :param data: Input, could be bytes or stream (will be decoded with UTF8) or text + :type data: str or bytes or IO + :param str content_type: The content type. + :return: The deserialized data. + :rtype: object + """ + if hasattr(data, "read"): + # Assume a stream + data = cast(IO, data).read() + + if isinstance(data, bytes): + data_as_str = data.decode(encoding="utf-8-sig") + else: + # Explain to mypy the correct type. + data_as_str = cast(str, data) + + # Remove Byte Order Mark if present in string + data_as_str = data_as_str.lstrip(_BOM) + + if content_type is None: + return data + + if cls.JSON_REGEXP.match(content_type): + try: + return json.loads(data_as_str) + except ValueError as err: + raise DeserializationError("JSON is invalid: {}".format(err), err) from err + elif "xml" in (content_type or []): + try: + + try: + if isinstance(data, unicode): # type: ignore + # If I'm Python 2.7 and unicode XML will scream if I try a "fromstring" on unicode string + data_as_str = data_as_str.encode(encoding="utf-8") # type: ignore + except NameError: + pass + + return ET.fromstring(data_as_str) # nosec + except ET.ParseError as err: + # It might be because the server has an issue, and returned JSON with + # content-type XML.... + # So let's try a JSON load, and if it's still broken + # let's flow the initial exception + def _json_attemp(data): + try: + return True, json.loads(data) + except ValueError: + return False, None # Don't care about this one + + success, json_result = _json_attemp(data) + if success: + return json_result + # If i'm here, it's not JSON, it's not XML, let's scream + # and raise the last context in this block (the XML exception) + # The function hack is because Py2.7 messes up with exception + # context otherwise. + _LOGGER.critical("Wasn't XML not JSON, failing") + raise DeserializationError("XML is invalid") from err + elif content_type.startswith("text/"): + return data_as_str + raise DeserializationError("Cannot deserialize content-type: {}".format(content_type)) + + @classmethod + def deserialize_from_http_generics(cls, body_bytes: Optional[Union[AnyStr, IO]], headers: Mapping) -> Any: + """Deserialize from HTTP response. + + Use bytes and headers to NOT use any requests/aiohttp or whatever + specific implementation. + Headers will tested for "content-type" + + :param bytes body_bytes: The body of the response. + :param dict headers: The headers of the response. + :returns: The deserialized data. + :rtype: object + """ + # Try to use content-type from headers if available + content_type = None + if "content-type" in headers: + content_type = headers["content-type"].split(";")[0].strip().lower() + # Ouch, this server did not declare what it sent... + # Let's guess it's JSON... + # Also, since Autorest was considering that an empty body was a valid JSON, + # need that test as well.... + else: + content_type = "application/json" + + if body_bytes: + return cls.deserialize_from_text(body_bytes, content_type) + return None + + +_LOGGER = logging.getLogger(__name__) + +try: + _long_type = long # type: ignore +except NameError: + _long_type = int + +TZ_UTC = datetime.timezone.utc + +_FLATTEN = re.compile(r"(? None: + self.additional_properties: Optional[Dict[str, Any]] = {} + for k in kwargs: # pylint: disable=consider-using-dict-items + if k not in self._attribute_map: + _LOGGER.warning("%s is not a known attribute of class %s and will be ignored", k, self.__class__) + elif k in self._validation and self._validation[k].get("readonly", False): + _LOGGER.warning("Readonly attribute %s will be ignored in class %s", k, self.__class__) + else: + setattr(self, k, kwargs[k]) + + def __eq__(self, other: Any) -> bool: + """Compare objects by comparing all attributes. + + :param object other: The object to compare + :returns: True if objects are equal + :rtype: bool + """ + if isinstance(other, self.__class__): + return self.__dict__ == other.__dict__ + return False + + def __ne__(self, other: Any) -> bool: + """Compare objects by comparing all attributes. + + :param object other: The object to compare + :returns: True if objects are not equal + :rtype: bool + """ + return not self.__eq__(other) + + def __str__(self) -> str: + return str(self.__dict__) + + @classmethod + def enable_additional_properties_sending(cls) -> None: + cls._attribute_map["additional_properties"] = {"key": "", "type": "{object}"} + + @classmethod + def is_xml_model(cls) -> bool: + try: + cls._xml_map # type: ignore + except AttributeError: + return False + return True + + @classmethod + def _create_xml_node(cls): + """Create XML node. + + :returns: The XML node + :rtype: xml.etree.ElementTree.Element + """ + try: + xml_map = cls._xml_map # type: ignore + except AttributeError: + xml_map = {} + + return _create_xml_node(xml_map.get("name", cls.__name__), xml_map.get("prefix", None), xml_map.get("ns", None)) + + def serialize(self, keep_readonly: bool = False, **kwargs: Any) -> JSON: + """Return the JSON that would be sent to server from this model. + + This is an alias to `as_dict(full_restapi_key_transformer, keep_readonly=False)`. + + If you want XML serialization, you can pass the kwargs is_xml=True. + + :param bool keep_readonly: If you want to serialize the readonly attributes + :returns: A dict JSON compatible object + :rtype: dict + """ + serializer = Serializer(self._infer_class_models()) + return serializer._serialize( # type: ignore # pylint: disable=protected-access + self, keep_readonly=keep_readonly, **kwargs + ) + + def as_dict( + self, + keep_readonly: bool = True, + key_transformer: Callable[[str, Dict[str, Any], Any], Any] = attribute_transformer, + **kwargs: Any + ) -> JSON: + """Return a dict that can be serialized using json.dump. + + Advanced usage might optionally use a callback as parameter: + + .. code::python + + def my_key_transformer(key, attr_desc, value): + return key + + Key is the attribute name used in Python. Attr_desc + is a dict of metadata. Currently contains 'type' with the + msrest type and 'key' with the RestAPI encoded key. + Value is the current value in this object. + + The string returned will be used to serialize the key. + If the return type is a list, this is considered hierarchical + result dict. + + See the three examples in this file: + + - attribute_transformer + - full_restapi_key_transformer + - last_restapi_key_transformer + + If you want XML serialization, you can pass the kwargs is_xml=True. + + :param bool keep_readonly: If you want to serialize the readonly attributes + :param function key_transformer: A key transformer function. + :returns: A dict JSON compatible object + :rtype: dict + """ + serializer = Serializer(self._infer_class_models()) + return serializer._serialize( # type: ignore # pylint: disable=protected-access + self, key_transformer=key_transformer, keep_readonly=keep_readonly, **kwargs + ) + + @classmethod + def _infer_class_models(cls): + try: + str_models = cls.__module__.rsplit(".", 1)[0] + models = sys.modules[str_models] + client_models = {k: v for k, v in models.__dict__.items() if isinstance(v, type)} + if cls.__name__ not in client_models: + raise ValueError("Not Autorest generated code") + except Exception: # pylint: disable=broad-exception-caught + # Assume it's not Autorest generated (tests?). Add ourselves as dependencies. + client_models = {cls.__name__: cls} + return client_models + + @classmethod + def deserialize(cls, data: Any, content_type: Optional[str] = None) -> Self: + """Parse a str using the RestAPI syntax and return a model. + + :param str data: A str using RestAPI structure. JSON by default. + :param str content_type: JSON by default, set application/xml if XML. + :returns: An instance of this model + :raises DeserializationError: if something went wrong + :rtype: Self + """ + deserializer = Deserializer(cls._infer_class_models()) + return deserializer(cls.__name__, data, content_type=content_type) # type: ignore + + @classmethod + def from_dict( + cls, + data: Any, + key_extractors: Optional[Callable[[str, Dict[str, Any], Any], Any]] = None, + content_type: Optional[str] = None, + ) -> Self: + """Parse a dict using given key extractor return a model. + + By default consider key + extractors (rest_key_case_insensitive_extractor, attribute_key_case_insensitive_extractor + and last_rest_key_case_insensitive_extractor) + + :param dict data: A dict using RestAPI structure + :param function key_extractors: A key extractor function. + :param str content_type: JSON by default, set application/xml if XML. + :returns: An instance of this model + :raises DeserializationError: if something went wrong + :rtype: Self + """ + deserializer = Deserializer(cls._infer_class_models()) + deserializer.key_extractors = ( # type: ignore + [ # type: ignore + attribute_key_case_insensitive_extractor, + rest_key_case_insensitive_extractor, + last_rest_key_case_insensitive_extractor, + ] + if key_extractors is None + else key_extractors + ) + return deserializer(cls.__name__, data, content_type=content_type) # type: ignore + + @classmethod + def _flatten_subtype(cls, key, objects): + if "_subtype_map" not in cls.__dict__: + return {} + result = dict(cls._subtype_map[key]) + for valuetype in cls._subtype_map[key].values(): + result.update(objects[valuetype]._flatten_subtype(key, objects)) # pylint: disable=protected-access + return result + + @classmethod + def _classify(cls, response, objects): + """Check the class _subtype_map for any child classes. + We want to ignore any inherited _subtype_maps. + + :param dict response: The initial data + :param dict objects: The class objects + :returns: The class to be used + :rtype: class + """ + for subtype_key in cls.__dict__.get("_subtype_map", {}).keys(): + subtype_value = None + + if not isinstance(response, ET.Element): + rest_api_response_key = cls._get_rest_key_parts(subtype_key)[-1] + subtype_value = response.get(rest_api_response_key, None) or response.get(subtype_key, None) + else: + subtype_value = xml_key_extractor(subtype_key, cls._attribute_map[subtype_key], response) + if subtype_value: + # Try to match base class. Can be class name only + # (bug to fix in Autorest to support x-ms-discriminator-name) + if cls.__name__ == subtype_value: + return cls + flatten_mapping_type = cls._flatten_subtype(subtype_key, objects) + try: + return objects[flatten_mapping_type[subtype_value]] # type: ignore + except KeyError: + _LOGGER.warning( + "Subtype value %s has no mapping, use base class %s.", + subtype_value, + cls.__name__, + ) + break + else: + _LOGGER.warning("Discriminator %s is absent or null, use base class %s.", subtype_key, cls.__name__) + break + return cls + + @classmethod + def _get_rest_key_parts(cls, attr_key): + """Get the RestAPI key of this attr, split it and decode part + :param str attr_key: Attribute key must be in attribute_map. + :returns: A list of RestAPI part + :rtype: list + """ + rest_split_key = _FLATTEN.split(cls._attribute_map[attr_key]["key"]) + return [_decode_attribute_map_key(key_part) for key_part in rest_split_key] + + +def _decode_attribute_map_key(key): + """This decode a key in an _attribute_map to the actual key we want to look at + inside the received data. + + :param str key: A key string from the generated code + :returns: The decoded key + :rtype: str + """ + return key.replace("\\.", ".") + + +class Serializer: # pylint: disable=too-many-public-methods + """Request object model serializer.""" + + basic_types = {str: "str", int: "int", bool: "bool", float: "float"} + + _xml_basic_types_serializers = {"bool": lambda x: str(x).lower()} + days = {0: "Mon", 1: "Tue", 2: "Wed", 3: "Thu", 4: "Fri", 5: "Sat", 6: "Sun"} + months = { + 1: "Jan", + 2: "Feb", + 3: "Mar", + 4: "Apr", + 5: "May", + 6: "Jun", + 7: "Jul", + 8: "Aug", + 9: "Sep", + 10: "Oct", + 11: "Nov", + 12: "Dec", + } + validation = { + "min_length": lambda x, y: len(x) < y, + "max_length": lambda x, y: len(x) > y, + "minimum": lambda x, y: x < y, + "maximum": lambda x, y: x > y, + "minimum_ex": lambda x, y: x <= y, + "maximum_ex": lambda x, y: x >= y, + "min_items": lambda x, y: len(x) < y, + "max_items": lambda x, y: len(x) > y, + "pattern": lambda x, y: not re.match(y, x, re.UNICODE), + "unique": lambda x, y: len(x) != len(set(x)), + "multiple": lambda x, y: x % y != 0, + } + + def __init__(self, classes: Optional[Mapping[str, type]] = None) -> None: + self.serialize_type = { + "iso-8601": Serializer.serialize_iso, + "rfc-1123": Serializer.serialize_rfc, + "unix-time": Serializer.serialize_unix, + "duration": Serializer.serialize_duration, + "date": Serializer.serialize_date, + "time": Serializer.serialize_time, + "decimal": Serializer.serialize_decimal, + "long": Serializer.serialize_long, + "bytearray": Serializer.serialize_bytearray, + "base64": Serializer.serialize_base64, + "object": self.serialize_object, + "[]": self.serialize_iter, + "{}": self.serialize_dict, + } + self.dependencies: Dict[str, type] = dict(classes) if classes else {} + self.key_transformer = full_restapi_key_transformer + self.client_side_validation = True + + def _serialize( # pylint: disable=too-many-nested-blocks, too-many-branches, too-many-statements, too-many-locals + self, target_obj, data_type=None, **kwargs + ): + """Serialize data into a string according to type. + + :param object target_obj: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str, dict + :raises SerializationError: if serialization fails. + :returns: The serialized data. + """ + key_transformer = kwargs.get("key_transformer", self.key_transformer) + keep_readonly = kwargs.get("keep_readonly", False) + if target_obj is None: + return None + + attr_name = None + class_name = target_obj.__class__.__name__ + + if data_type: + return self.serialize_data(target_obj, data_type, **kwargs) + + if not hasattr(target_obj, "_attribute_map"): + data_type = type(target_obj).__name__ + if data_type in self.basic_types.values(): + return self.serialize_data(target_obj, data_type, **kwargs) + + # Force "is_xml" kwargs if we detect a XML model + try: + is_xml_model_serialization = kwargs["is_xml"] + except KeyError: + is_xml_model_serialization = kwargs.setdefault("is_xml", target_obj.is_xml_model()) + + serialized = {} + if is_xml_model_serialization: + serialized = target_obj._create_xml_node() # pylint: disable=protected-access + try: + attributes = target_obj._attribute_map # pylint: disable=protected-access + for attr, attr_desc in attributes.items(): + attr_name = attr + if not keep_readonly and target_obj._validation.get( # pylint: disable=protected-access + attr_name, {} + ).get("readonly", False): + continue + + if attr_name == "additional_properties" and attr_desc["key"] == "": + if target_obj.additional_properties is not None: + serialized.update(target_obj.additional_properties) + continue + try: + + orig_attr = getattr(target_obj, attr) + if is_xml_model_serialization: + pass # Don't provide "transformer" for XML for now. Keep "orig_attr" + else: # JSON + keys, orig_attr = key_transformer(attr, attr_desc.copy(), orig_attr) + keys = keys if isinstance(keys, list) else [keys] + + kwargs["serialization_ctxt"] = attr_desc + new_attr = self.serialize_data(orig_attr, attr_desc["type"], **kwargs) + + if is_xml_model_serialization: + xml_desc = attr_desc.get("xml", {}) + xml_name = xml_desc.get("name", attr_desc["key"]) + xml_prefix = xml_desc.get("prefix", None) + xml_ns = xml_desc.get("ns", None) + if xml_desc.get("attr", False): + if xml_ns: + ET.register_namespace(xml_prefix, xml_ns) + xml_name = "{{{}}}{}".format(xml_ns, xml_name) + serialized.set(xml_name, new_attr) # type: ignore + continue + if xml_desc.get("text", False): + serialized.text = new_attr # type: ignore + continue + if isinstance(new_attr, list): + serialized.extend(new_attr) # type: ignore + elif isinstance(new_attr, ET.Element): + # If the down XML has no XML/Name, + # we MUST replace the tag with the local tag. But keeping the namespaces. + if "name" not in getattr(orig_attr, "_xml_map", {}): + splitted_tag = new_attr.tag.split("}") + if len(splitted_tag) == 2: # Namespace + new_attr.tag = "}".join([splitted_tag[0], xml_name]) + else: + new_attr.tag = xml_name + serialized.append(new_attr) # type: ignore + else: # That's a basic type + # Integrate namespace if necessary + local_node = _create_xml_node(xml_name, xml_prefix, xml_ns) + local_node.text = str(new_attr) + serialized.append(local_node) # type: ignore + else: # JSON + for k in reversed(keys): # type: ignore + new_attr = {k: new_attr} + + _new_attr = new_attr + _serialized = serialized + for k in keys: # type: ignore + if k not in _serialized: + _serialized.update(_new_attr) # type: ignore + _new_attr = _new_attr[k] # type: ignore + _serialized = _serialized[k] + except ValueError as err: + if isinstance(err, SerializationError): + raise + + except (AttributeError, KeyError, TypeError) as err: + msg = "Attribute {} in object {} cannot be serialized.\n{}".format(attr_name, class_name, str(target_obj)) + raise SerializationError(msg) from err + return serialized + + def body(self, data, data_type, **kwargs): + """Serialize data intended for a request body. + + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: dict + :raises SerializationError: if serialization fails. + :raises ValueError: if data is None + :returns: The serialized request body + """ + + # Just in case this is a dict + internal_data_type_str = data_type.strip("[]{}") + internal_data_type = self.dependencies.get(internal_data_type_str, None) + try: + is_xml_model_serialization = kwargs["is_xml"] + except KeyError: + if internal_data_type and issubclass(internal_data_type, Model): + is_xml_model_serialization = kwargs.setdefault("is_xml", internal_data_type.is_xml_model()) + else: + is_xml_model_serialization = False + if internal_data_type and not isinstance(internal_data_type, Enum): + try: + deserializer = Deserializer(self.dependencies) + # Since it's on serialization, it's almost sure that format is not JSON REST + # We're not able to deal with additional properties for now. + deserializer.additional_properties_detection = False + if is_xml_model_serialization: + deserializer.key_extractors = [ # type: ignore + attribute_key_case_insensitive_extractor, + ] + else: + deserializer.key_extractors = [ + rest_key_case_insensitive_extractor, + attribute_key_case_insensitive_extractor, + last_rest_key_case_insensitive_extractor, + ] + data = deserializer._deserialize(data_type, data) # pylint: disable=protected-access + except DeserializationError as err: + raise SerializationError("Unable to build a model: " + str(err)) from err + + return self._serialize(data, data_type, **kwargs) + + def url(self, name, data, data_type, **kwargs): + """Serialize data intended for a URL path. + + :param str name: The name of the URL path parameter. + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str + :returns: The serialized URL path + :raises TypeError: if serialization fails. + :raises ValueError: if data is None + """ + try: + output = self.serialize_data(data, data_type, **kwargs) + if data_type == "bool": + output = json.dumps(output) + + if kwargs.get("skip_quote") is True: + output = str(output) + output = output.replace("{", quote("{")).replace("}", quote("}")) + else: + output = quote(str(output), safe="") + except SerializationError as exc: + raise TypeError("{} must be type {}.".format(name, data_type)) from exc + return output + + def query(self, name, data, data_type, **kwargs): + """Serialize data intended for a URL query. + + :param str name: The name of the query parameter. + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str, list + :raises TypeError: if serialization fails. + :raises ValueError: if data is None + :returns: The serialized query parameter + """ + try: + # Treat the list aside, since we don't want to encode the div separator + if data_type.startswith("["): + internal_data_type = data_type[1:-1] + do_quote = not kwargs.get("skip_quote", False) + return self.serialize_iter(data, internal_data_type, do_quote=do_quote, **kwargs) + + # Not a list, regular serialization + output = self.serialize_data(data, data_type, **kwargs) + if data_type == "bool": + output = json.dumps(output) + if kwargs.get("skip_quote") is True: + output = str(output) + else: + output = quote(str(output), safe="") + except SerializationError as exc: + raise TypeError("{} must be type {}.".format(name, data_type)) from exc + return str(output) + + def header(self, name, data, data_type, **kwargs): + """Serialize data intended for a request header. + + :param str name: The name of the header. + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str + :raises TypeError: if serialization fails. + :raises ValueError: if data is None + :returns: The serialized header + """ + try: + if data_type in ["[str]"]: + data = ["" if d is None else d for d in data] + + output = self.serialize_data(data, data_type, **kwargs) + if data_type == "bool": + output = json.dumps(output) + except SerializationError as exc: + raise TypeError("{} must be type {}.".format(name, data_type)) from exc + return str(output) + + def serialize_data(self, data, data_type, **kwargs): + """Serialize generic data according to supplied data type. + + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :raises AttributeError: if required data is None. + :raises ValueError: if data is None + :raises SerializationError: if serialization fails. + :returns: The serialized data. + :rtype: str, int, float, bool, dict, list + """ + if data is None: + raise ValueError("No value for given attribute") + + try: + if data is CoreNull: + return None + if data_type in self.basic_types.values(): + return self.serialize_basic(data, data_type, **kwargs) + + if data_type in self.serialize_type: + return self.serialize_type[data_type](data, **kwargs) + + # If dependencies is empty, try with current data class + # It has to be a subclass of Enum anyway + enum_type = self.dependencies.get(data_type, data.__class__) + if issubclass(enum_type, Enum): + return Serializer.serialize_enum(data, enum_obj=enum_type) + + iter_type = data_type[0] + data_type[-1] + if iter_type in self.serialize_type: + return self.serialize_type[iter_type](data, data_type[1:-1], **kwargs) + + except (ValueError, TypeError) as err: + msg = "Unable to serialize value: {!r} as type: {!r}." + raise SerializationError(msg.format(data, data_type)) from err + return self._serialize(data, **kwargs) + + @classmethod + def _get_custom_serializers(cls, data_type, **kwargs): # pylint: disable=inconsistent-return-statements + custom_serializer = kwargs.get("basic_types_serializers", {}).get(data_type) + if custom_serializer: + return custom_serializer + if kwargs.get("is_xml", False): + return cls._xml_basic_types_serializers.get(data_type) + + @classmethod + def serialize_basic(cls, data, data_type, **kwargs): + """Serialize basic builting data type. + Serializes objects to str, int, float or bool. + + Possible kwargs: + - basic_types_serializers dict[str, callable] : If set, use the callable as serializer + - is_xml bool : If set, use xml_basic_types_serializers + + :param obj data: Object to be serialized. + :param str data_type: Type of object in the iterable. + :rtype: str, int, float, bool + :return: serialized object + """ + custom_serializer = cls._get_custom_serializers(data_type, **kwargs) + if custom_serializer: + return custom_serializer(data) + if data_type == "str": + return cls.serialize_unicode(data) + return eval(data_type)(data) # nosec # pylint: disable=eval-used + + @classmethod + def serialize_unicode(cls, data): + """Special handling for serializing unicode strings in Py2. + Encode to UTF-8 if unicode, otherwise handle as a str. + + :param str data: Object to be serialized. + :rtype: str + :return: serialized object + """ + try: # If I received an enum, return its value + return data.value + except AttributeError: + pass + + try: + if isinstance(data, unicode): # type: ignore + # Don't change it, JSON and XML ElementTree are totally able + # to serialize correctly u'' strings + return data + except NameError: + return str(data) + return str(data) + + def serialize_iter(self, data, iter_type, div=None, **kwargs): + """Serialize iterable. + + Supported kwargs: + - serialization_ctxt dict : The current entry of _attribute_map, or same format. + serialization_ctxt['type'] should be same as data_type. + - is_xml bool : If set, serialize as XML + + :param list data: Object to be serialized. + :param str iter_type: Type of object in the iterable. + :param str div: If set, this str will be used to combine the elements + in the iterable into a combined string. Default is 'None'. + Defaults to False. + :rtype: list, str + :return: serialized iterable + """ + if isinstance(data, str): + raise SerializationError("Refuse str type as a valid iter type.") + + serialization_ctxt = kwargs.get("serialization_ctxt", {}) + is_xml = kwargs.get("is_xml", False) + + serialized = [] + for d in data: + try: + serialized.append(self.serialize_data(d, iter_type, **kwargs)) + except ValueError as err: + if isinstance(err, SerializationError): + raise + serialized.append(None) + + if kwargs.get("do_quote", False): + serialized = ["" if s is None else quote(str(s), safe="") for s in serialized] + + if div: + serialized = ["" if s is None else str(s) for s in serialized] + serialized = div.join(serialized) + + if "xml" in serialization_ctxt or is_xml: + # XML serialization is more complicated + xml_desc = serialization_ctxt.get("xml", {}) + xml_name = xml_desc.get("name") + if not xml_name: + xml_name = serialization_ctxt["key"] + + # Create a wrap node if necessary (use the fact that Element and list have "append") + is_wrapped = xml_desc.get("wrapped", False) + node_name = xml_desc.get("itemsName", xml_name) + if is_wrapped: + final_result = _create_xml_node(xml_name, xml_desc.get("prefix", None), xml_desc.get("ns", None)) + else: + final_result = [] + # All list elements to "local_node" + for el in serialized: + if isinstance(el, ET.Element): + el_node = el + else: + el_node = _create_xml_node(node_name, xml_desc.get("prefix", None), xml_desc.get("ns", None)) + if el is not None: # Otherwise it writes "None" :-p + el_node.text = str(el) + final_result.append(el_node) + return final_result + return serialized + + def serialize_dict(self, attr, dict_type, **kwargs): + """Serialize a dictionary of objects. + + :param dict attr: Object to be serialized. + :param str dict_type: Type of object in the dictionary. + :rtype: dict + :return: serialized dictionary + """ + serialization_ctxt = kwargs.get("serialization_ctxt", {}) + serialized = {} + for key, value in attr.items(): + try: + serialized[self.serialize_unicode(key)] = self.serialize_data(value, dict_type, **kwargs) + except ValueError as err: + if isinstance(err, SerializationError): + raise + serialized[self.serialize_unicode(key)] = None + + if "xml" in serialization_ctxt: + # XML serialization is more complicated + xml_desc = serialization_ctxt["xml"] + xml_name = xml_desc["name"] + + final_result = _create_xml_node(xml_name, xml_desc.get("prefix", None), xml_desc.get("ns", None)) + for key, value in serialized.items(): + ET.SubElement(final_result, key).text = value + return final_result + + return serialized + + def serialize_object(self, attr, **kwargs): # pylint: disable=too-many-return-statements + """Serialize a generic object. + This will be handled as a dictionary. If object passed in is not + a basic type (str, int, float, dict, list) it will simply be + cast to str. + + :param dict attr: Object to be serialized. + :rtype: dict or str + :return: serialized object + """ + if attr is None: + return None + if isinstance(attr, ET.Element): + return attr + obj_type = type(attr) + if obj_type in self.basic_types: + return self.serialize_basic(attr, self.basic_types[obj_type], **kwargs) + if obj_type is _long_type: + return self.serialize_long(attr) + if obj_type is str: + return self.serialize_unicode(attr) + if obj_type is datetime.datetime: + return self.serialize_iso(attr) + if obj_type is datetime.date: + return self.serialize_date(attr) + if obj_type is datetime.time: + return self.serialize_time(attr) + if obj_type is datetime.timedelta: + return self.serialize_duration(attr) + if obj_type is decimal.Decimal: + return self.serialize_decimal(attr) + + # If it's a model or I know this dependency, serialize as a Model + if obj_type in self.dependencies.values() or isinstance(attr, Model): + return self._serialize(attr) + + if obj_type == dict: + serialized = {} + for key, value in attr.items(): + try: + serialized[self.serialize_unicode(key)] = self.serialize_object(value, **kwargs) + except ValueError: + serialized[self.serialize_unicode(key)] = None + return serialized + + if obj_type == list: + serialized = [] + for obj in attr: + try: + serialized.append(self.serialize_object(obj, **kwargs)) + except ValueError: + pass + return serialized + return str(attr) + + @staticmethod + def serialize_enum(attr, enum_obj=None): + try: + result = attr.value + except AttributeError: + result = attr + try: + enum_obj(result) # type: ignore + return result + except ValueError as exc: + for enum_value in enum_obj: # type: ignore + if enum_value.value.lower() == str(attr).lower(): + return enum_value.value + error = "{!r} is not valid value for enum {!r}" + raise SerializationError(error.format(attr, enum_obj)) from exc + + @staticmethod + def serialize_bytearray(attr, **kwargs): # pylint: disable=unused-argument + """Serialize bytearray into base-64 string. + + :param str attr: Object to be serialized. + :rtype: str + :return: serialized base64 + """ + return b64encode(attr).decode() + + @staticmethod + def serialize_base64(attr, **kwargs): # pylint: disable=unused-argument + """Serialize str into base-64 string. + + :param str attr: Object to be serialized. + :rtype: str + :return: serialized base64 + """ + encoded = b64encode(attr).decode("ascii") + return encoded.strip("=").replace("+", "-").replace("/", "_") + + @staticmethod + def serialize_decimal(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Decimal object to float. + + :param decimal attr: Object to be serialized. + :rtype: float + :return: serialized decimal + """ + return float(attr) + + @staticmethod + def serialize_long(attr, **kwargs): # pylint: disable=unused-argument + """Serialize long (Py2) or int (Py3). + + :param int attr: Object to be serialized. + :rtype: int/long + :return: serialized long + """ + return _long_type(attr) + + @staticmethod + def serialize_date(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Date object into ISO-8601 formatted string. + + :param Date attr: Object to be serialized. + :rtype: str + :return: serialized date + """ + if isinstance(attr, str): + attr = isodate.parse_date(attr) + t = "{:04}-{:02}-{:02}".format(attr.year, attr.month, attr.day) + return t + + @staticmethod + def serialize_time(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Time object into ISO-8601 formatted string. + + :param datetime.time attr: Object to be serialized. + :rtype: str + :return: serialized time + """ + if isinstance(attr, str): + attr = isodate.parse_time(attr) + t = "{:02}:{:02}:{:02}".format(attr.hour, attr.minute, attr.second) + if attr.microsecond: + t += ".{:02}".format(attr.microsecond) + return t + + @staticmethod + def serialize_duration(attr, **kwargs): # pylint: disable=unused-argument + """Serialize TimeDelta object into ISO-8601 formatted string. + + :param TimeDelta attr: Object to be serialized. + :rtype: str + :return: serialized duration + """ + if isinstance(attr, str): + attr = isodate.parse_duration(attr) + return isodate.duration_isoformat(attr) + + @staticmethod + def serialize_rfc(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Datetime object into RFC-1123 formatted string. + + :param Datetime attr: Object to be serialized. + :rtype: str + :raises TypeError: if format invalid. + :return: serialized rfc + """ + try: + if not attr.tzinfo: + _LOGGER.warning("Datetime with no tzinfo will be considered UTC.") + utc = attr.utctimetuple() + except AttributeError as exc: + raise TypeError("RFC1123 object must be valid Datetime object.") from exc + + return "{}, {:02} {} {:04} {:02}:{:02}:{:02} GMT".format( + Serializer.days[utc.tm_wday], + utc.tm_mday, + Serializer.months[utc.tm_mon], + utc.tm_year, + utc.tm_hour, + utc.tm_min, + utc.tm_sec, + ) + + @staticmethod + def serialize_iso(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Datetime object into ISO-8601 formatted string. + + :param Datetime attr: Object to be serialized. + :rtype: str + :raises SerializationError: if format invalid. + :return: serialized iso + """ + if isinstance(attr, str): + attr = isodate.parse_datetime(attr) + try: + if not attr.tzinfo: + _LOGGER.warning("Datetime with no tzinfo will be considered UTC.") + utc = attr.utctimetuple() + if utc.tm_year > 9999 or utc.tm_year < 1: + raise OverflowError("Hit max or min date") + + microseconds = str(attr.microsecond).rjust(6, "0").rstrip("0").ljust(3, "0") + if microseconds: + microseconds = "." + microseconds + date = "{:04}-{:02}-{:02}T{:02}:{:02}:{:02}".format( + utc.tm_year, utc.tm_mon, utc.tm_mday, utc.tm_hour, utc.tm_min, utc.tm_sec + ) + return date + microseconds + "Z" + except (ValueError, OverflowError) as err: + msg = "Unable to serialize datetime object." + raise SerializationError(msg) from err + except AttributeError as err: + msg = "ISO-8601 object must be valid Datetime object." + raise TypeError(msg) from err + + @staticmethod + def serialize_unix(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Datetime object into IntTime format. + This is represented as seconds. + + :param Datetime attr: Object to be serialized. + :rtype: int + :raises SerializationError: if format invalid + :return: serialied unix + """ + if isinstance(attr, int): + return attr + try: + if not attr.tzinfo: + _LOGGER.warning("Datetime with no tzinfo will be considered UTC.") + return int(calendar.timegm(attr.utctimetuple())) + except AttributeError as exc: + raise TypeError("Unix time object must be valid Datetime object.") from exc + + +def rest_key_extractor(attr, attr_desc, data): # pylint: disable=unused-argument + key = attr_desc["key"] + working_data = data + + while "." in key: + # Need the cast, as for some reasons "split" is typed as list[str | Any] + dict_keys = cast(List[str], _FLATTEN.split(key)) + if len(dict_keys) == 1: + key = _decode_attribute_map_key(dict_keys[0]) + break + working_key = _decode_attribute_map_key(dict_keys[0]) + working_data = working_data.get(working_key, data) + if working_data is None: + # If at any point while following flatten JSON path see None, it means + # that all properties under are None as well + return None + key = ".".join(dict_keys[1:]) + + return working_data.get(key) + + +def rest_key_case_insensitive_extractor( # pylint: disable=unused-argument, inconsistent-return-statements + attr, attr_desc, data +): + key = attr_desc["key"] + working_data = data + + while "." in key: + dict_keys = _FLATTEN.split(key) + if len(dict_keys) == 1: + key = _decode_attribute_map_key(dict_keys[0]) + break + working_key = _decode_attribute_map_key(dict_keys[0]) + working_data = attribute_key_case_insensitive_extractor(working_key, None, working_data) + if working_data is None: + # If at any point while following flatten JSON path see None, it means + # that all properties under are None as well + return None + key = ".".join(dict_keys[1:]) + + if working_data: + return attribute_key_case_insensitive_extractor(key, None, working_data) + + +def last_rest_key_extractor(attr, attr_desc, data): # pylint: disable=unused-argument + """Extract the attribute in "data" based on the last part of the JSON path key. + + :param str attr: The attribute to extract + :param dict attr_desc: The attribute description + :param dict data: The data to extract from + :rtype: object + :returns: The extracted attribute + """ + key = attr_desc["key"] + dict_keys = _FLATTEN.split(key) + return attribute_key_extractor(dict_keys[-1], None, data) + + +def last_rest_key_case_insensitive_extractor(attr, attr_desc, data): # pylint: disable=unused-argument + """Extract the attribute in "data" based on the last part of the JSON path key. + + This is the case insensitive version of "last_rest_key_extractor" + :param str attr: The attribute to extract + :param dict attr_desc: The attribute description + :param dict data: The data to extract from + :rtype: object + :returns: The extracted attribute + """ + key = attr_desc["key"] + dict_keys = _FLATTEN.split(key) + return attribute_key_case_insensitive_extractor(dict_keys[-1], None, data) + + +def attribute_key_extractor(attr, _, data): + return data.get(attr) + + +def attribute_key_case_insensitive_extractor(attr, _, data): + found_key = None + lower_attr = attr.lower() + for key in data: + if lower_attr == key.lower(): + found_key = key + break + + return data.get(found_key) + + +def _extract_name_from_internal_type(internal_type): + """Given an internal type XML description, extract correct XML name with namespace. + + :param dict internal_type: An model type + :rtype: tuple + :returns: A tuple XML name + namespace dict + """ + internal_type_xml_map = getattr(internal_type, "_xml_map", {}) + xml_name = internal_type_xml_map.get("name", internal_type.__name__) + xml_ns = internal_type_xml_map.get("ns", None) + if xml_ns: + xml_name = "{{{}}}{}".format(xml_ns, xml_name) + return xml_name + + +def xml_key_extractor(attr, attr_desc, data): # pylint: disable=unused-argument,too-many-return-statements + if isinstance(data, dict): + return None + + # Test if this model is XML ready first + if not isinstance(data, ET.Element): + return None + + xml_desc = attr_desc.get("xml", {}) + xml_name = xml_desc.get("name", attr_desc["key"]) + + # Look for a children + is_iter_type = attr_desc["type"].startswith("[") + is_wrapped = xml_desc.get("wrapped", False) + internal_type = attr_desc.get("internalType", None) + internal_type_xml_map = getattr(internal_type, "_xml_map", {}) + + # Integrate namespace if necessary + xml_ns = xml_desc.get("ns", internal_type_xml_map.get("ns", None)) + if xml_ns: + xml_name = "{{{}}}{}".format(xml_ns, xml_name) + + # If it's an attribute, that's simple + if xml_desc.get("attr", False): + return data.get(xml_name) + + # If it's x-ms-text, that's simple too + if xml_desc.get("text", False): + return data.text + + # Scenario where I take the local name: + # - Wrapped node + # - Internal type is an enum (considered basic types) + # - Internal type has no XML/Name node + if is_wrapped or (internal_type and (issubclass(internal_type, Enum) or "name" not in internal_type_xml_map)): + children = data.findall(xml_name) + # If internal type has a local name and it's not a list, I use that name + elif not is_iter_type and internal_type and "name" in internal_type_xml_map: + xml_name = _extract_name_from_internal_type(internal_type) + children = data.findall(xml_name) + # That's an array + else: + if internal_type: # Complex type, ignore itemsName and use the complex type name + items_name = _extract_name_from_internal_type(internal_type) + else: + items_name = xml_desc.get("itemsName", xml_name) + children = data.findall(items_name) + + if len(children) == 0: + if is_iter_type: + if is_wrapped: + return None # is_wrapped no node, we want None + return [] # not wrapped, assume empty list + return None # Assume it's not there, maybe an optional node. + + # If is_iter_type and not wrapped, return all found children + if is_iter_type: + if not is_wrapped: + return children + # Iter and wrapped, should have found one node only (the wrap one) + if len(children) != 1: + raise DeserializationError( + "Tried to deserialize an array not wrapped, and found several nodes '{}'. Maybe you should declare this array as wrapped?".format( + xml_name + ) + ) + return list(children[0]) # Might be empty list and that's ok. + + # Here it's not a itertype, we should have found one element only or empty + if len(children) > 1: + raise DeserializationError("Find several XML '{}' where it was not expected".format(xml_name)) + return children[0] + + +class Deserializer: + """Response object model deserializer. + + :param dict classes: Class type dictionary for deserializing complex types. + :ivar list key_extractors: Ordered list of extractors to be used by this deserializer. + """ + + basic_types = {str: "str", int: "int", bool: "bool", float: "float"} + + valid_date = re.compile(r"\d{4}[-]\d{2}[-]\d{2}T\d{2}:\d{2}:\d{2}\.?\d*Z?[-+]?[\d{2}]?:?[\d{2}]?") + + def __init__(self, classes: Optional[Mapping[str, type]] = None) -> None: + self.deserialize_type = { + "iso-8601": Deserializer.deserialize_iso, + "rfc-1123": Deserializer.deserialize_rfc, + "unix-time": Deserializer.deserialize_unix, + "duration": Deserializer.deserialize_duration, + "date": Deserializer.deserialize_date, + "time": Deserializer.deserialize_time, + "decimal": Deserializer.deserialize_decimal, + "long": Deserializer.deserialize_long, + "bytearray": Deserializer.deserialize_bytearray, + "base64": Deserializer.deserialize_base64, + "object": self.deserialize_object, + "[]": self.deserialize_iter, + "{}": self.deserialize_dict, + } + self.deserialize_expected_types = { + "duration": (isodate.Duration, datetime.timedelta), + "iso-8601": (datetime.datetime), + } + self.dependencies: Dict[str, type] = dict(classes) if classes else {} + self.key_extractors = [rest_key_extractor, xml_key_extractor] + # Additional properties only works if the "rest_key_extractor" is used to + # extract the keys. Making it to work whatever the key extractor is too much + # complicated, with no real scenario for now. + # So adding a flag to disable additional properties detection. This flag should be + # used if your expect the deserialization to NOT come from a JSON REST syntax. + # Otherwise, result are unexpected + self.additional_properties_detection = True + + def __call__(self, target_obj, response_data, content_type=None): + """Call the deserializer to process a REST response. + + :param str target_obj: Target data type to deserialize to. + :param requests.Response response_data: REST response object. + :param str content_type: Swagger "produces" if available. + :raises DeserializationError: if deserialization fails. + :return: Deserialized object. + :rtype: object + """ + data = self._unpack_content(response_data, content_type) + return self._deserialize(target_obj, data) + + def _deserialize(self, target_obj, data): # pylint: disable=inconsistent-return-statements + """Call the deserializer on a model. + + Data needs to be already deserialized as JSON or XML ElementTree + + :param str target_obj: Target data type to deserialize to. + :param object data: Object to deserialize. + :raises DeserializationError: if deserialization fails. + :return: Deserialized object. + :rtype: object + """ + # This is already a model, go recursive just in case + if hasattr(data, "_attribute_map"): + constants = [name for name, config in getattr(data, "_validation", {}).items() if config.get("constant")] + try: + for attr, mapconfig in data._attribute_map.items(): # pylint: disable=protected-access + if attr in constants: + continue + value = getattr(data, attr) + if value is None: + continue + local_type = mapconfig["type"] + internal_data_type = local_type.strip("[]{}") + if internal_data_type not in self.dependencies or isinstance(internal_data_type, Enum): + continue + setattr(data, attr, self._deserialize(local_type, value)) + return data + except AttributeError: + return + + response, class_name = self._classify_target(target_obj, data) + + if isinstance(response, str): + return self.deserialize_data(data, response) + if isinstance(response, type) and issubclass(response, Enum): + return self.deserialize_enum(data, response) + + if data is None or data is CoreNull: + return data + try: + attributes = response._attribute_map # type: ignore # pylint: disable=protected-access + d_attrs = {} + for attr, attr_desc in attributes.items(): + # Check empty string. If it's not empty, someone has a real "additionalProperties"... + if attr == "additional_properties" and attr_desc["key"] == "": + continue + raw_value = None + # Enhance attr_desc with some dynamic data + attr_desc = attr_desc.copy() # Do a copy, do not change the real one + internal_data_type = attr_desc["type"].strip("[]{}") + if internal_data_type in self.dependencies: + attr_desc["internalType"] = self.dependencies[internal_data_type] + + for key_extractor in self.key_extractors: + found_value = key_extractor(attr, attr_desc, data) + if found_value is not None: + if raw_value is not None and raw_value != found_value: + msg = ( + "Ignoring extracted value '%s' from %s for key '%s'" + " (duplicate extraction, follow extractors order)" + ) + _LOGGER.warning(msg, found_value, key_extractor, attr) + continue + raw_value = found_value + + value = self.deserialize_data(raw_value, attr_desc["type"]) + d_attrs[attr] = value + except (AttributeError, TypeError, KeyError) as err: + msg = "Unable to deserialize to object: " + class_name # type: ignore + raise DeserializationError(msg) from err + additional_properties = self._build_additional_properties(attributes, data) + return self._instantiate_model(response, d_attrs, additional_properties) + + def _build_additional_properties(self, attribute_map, data): + if not self.additional_properties_detection: + return None + if "additional_properties" in attribute_map and attribute_map.get("additional_properties", {}).get("key") != "": + # Check empty string. If it's not empty, someone has a real "additionalProperties" + return None + if isinstance(data, ET.Element): + data = {el.tag: el.text for el in data} + + known_keys = { + _decode_attribute_map_key(_FLATTEN.split(desc["key"])[0]) + for desc in attribute_map.values() + if desc["key"] != "" + } + present_keys = set(data.keys()) + missing_keys = present_keys - known_keys + return {key: data[key] for key in missing_keys} + + def _classify_target(self, target, data): + """Check to see whether the deserialization target object can + be classified into a subclass. + Once classification has been determined, initialize object. + + :param str target: The target object type to deserialize to. + :param str/dict data: The response data to deserialize. + :return: The classified target object and its class name. + :rtype: tuple + """ + if target is None: + return None, None + + if isinstance(target, str): + try: + target = self.dependencies[target] + except KeyError: + return target, target + + try: + target = target._classify(data, self.dependencies) # type: ignore # pylint: disable=protected-access + except AttributeError: + pass # Target is not a Model, no classify + return target, target.__class__.__name__ # type: ignore + + def failsafe_deserialize(self, target_obj, data, content_type=None): + """Ignores any errors encountered in deserialization, + and falls back to not deserializing the object. Recommended + for use in error deserialization, as we want to return the + HttpResponseError to users, and not have them deal with + a deserialization error. + + :param str target_obj: The target object type to deserialize to. + :param str/dict data: The response data to deserialize. + :param str content_type: Swagger "produces" if available. + :return: Deserialized object. + :rtype: object + """ + try: + return self(target_obj, data, content_type=content_type) + except: # pylint: disable=bare-except + _LOGGER.debug( + "Ran into a deserialization error. Ignoring since this is failsafe deserialization", exc_info=True + ) + return None + + @staticmethod + def _unpack_content(raw_data, content_type=None): + """Extract the correct structure for deserialization. + + If raw_data is a PipelineResponse, try to extract the result of RawDeserializer. + if we can't, raise. Your Pipeline should have a RawDeserializer. + + If not a pipeline response and raw_data is bytes or string, use content-type + to decode it. If no content-type, try JSON. + + If raw_data is something else, bypass all logic and return it directly. + + :param obj raw_data: Data to be processed. + :param str content_type: How to parse if raw_data is a string/bytes. + :raises JSONDecodeError: If JSON is requested and parsing is impossible. + :raises UnicodeDecodeError: If bytes is not UTF8 + :rtype: object + :return: Unpacked content. + """ + # Assume this is enough to detect a Pipeline Response without importing it + context = getattr(raw_data, "context", {}) + if context: + if RawDeserializer.CONTEXT_NAME in context: + return context[RawDeserializer.CONTEXT_NAME] + raise ValueError("This pipeline didn't have the RawDeserializer policy; can't deserialize") + + # Assume this is enough to recognize universal_http.ClientResponse without importing it + if hasattr(raw_data, "body"): + return RawDeserializer.deserialize_from_http_generics(raw_data.text(), raw_data.headers) + + # Assume this enough to recognize requests.Response without importing it. + if hasattr(raw_data, "_content_consumed"): + return RawDeserializer.deserialize_from_http_generics(raw_data.text, raw_data.headers) + + if isinstance(raw_data, (str, bytes)) or hasattr(raw_data, "read"): + return RawDeserializer.deserialize_from_text(raw_data, content_type) # type: ignore + return raw_data + + def _instantiate_model(self, response, attrs, additional_properties=None): + """Instantiate a response model passing in deserialized args. + + :param Response response: The response model class. + :param dict attrs: The deserialized response attributes. + :param dict additional_properties: Additional properties to be set. + :rtype: Response + :return: The instantiated response model. + """ + if callable(response): + subtype = getattr(response, "_subtype_map", {}) + try: + readonly = [ + k + for k, v in response._validation.items() # pylint: disable=protected-access # type: ignore + if v.get("readonly") + ] + const = [ + k + for k, v in response._validation.items() # pylint: disable=protected-access # type: ignore + if v.get("constant") + ] + kwargs = {k: v for k, v in attrs.items() if k not in subtype and k not in readonly + const} + response_obj = response(**kwargs) + for attr in readonly: + setattr(response_obj, attr, attrs.get(attr)) + if additional_properties: + response_obj.additional_properties = additional_properties # type: ignore + return response_obj + except TypeError as err: + msg = "Unable to deserialize {} into model {}. ".format(kwargs, response) # type: ignore + raise DeserializationError(msg + str(err)) from err + else: + try: + for attr, value in attrs.items(): + setattr(response, attr, value) + return response + except Exception as exp: + msg = "Unable to populate response model. " + msg += "Type: {}, Error: {}".format(type(response), exp) + raise DeserializationError(msg) from exp + + def deserialize_data(self, data, data_type): # pylint: disable=too-many-return-statements + """Process data for deserialization according to data type. + + :param str data: The response string to be deserialized. + :param str data_type: The type to deserialize to. + :raises DeserializationError: if deserialization fails. + :return: Deserialized object. + :rtype: object + """ + if data is None: + return data + + try: + if not data_type: + return data + if data_type in self.basic_types.values(): + return self.deserialize_basic(data, data_type) + if data_type in self.deserialize_type: + if isinstance(data, self.deserialize_expected_types.get(data_type, tuple())): + return data + + is_a_text_parsing_type = lambda x: x not in [ # pylint: disable=unnecessary-lambda-assignment + "object", + "[]", + r"{}", + ] + if isinstance(data, ET.Element) and is_a_text_parsing_type(data_type) and not data.text: + return None + data_val = self.deserialize_type[data_type](data) + return data_val + + iter_type = data_type[0] + data_type[-1] + if iter_type in self.deserialize_type: + return self.deserialize_type[iter_type](data, data_type[1:-1]) + + obj_type = self.dependencies[data_type] + if issubclass(obj_type, Enum): + if isinstance(data, ET.Element): + data = data.text + return self.deserialize_enum(data, obj_type) + + except (ValueError, TypeError, AttributeError) as err: + msg = "Unable to deserialize response data." + msg += " Data: {}, {}".format(data, data_type) + raise DeserializationError(msg) from err + return self._deserialize(obj_type, data) + + def deserialize_iter(self, attr, iter_type): + """Deserialize an iterable. + + :param list attr: Iterable to be deserialized. + :param str iter_type: The type of object in the iterable. + :return: Deserialized iterable. + :rtype: list + """ + if attr is None: + return None + if isinstance(attr, ET.Element): # If I receive an element here, get the children + attr = list(attr) + if not isinstance(attr, (list, set)): + raise DeserializationError("Cannot deserialize as [{}] an object of type {}".format(iter_type, type(attr))) + return [self.deserialize_data(a, iter_type) for a in attr] + + def deserialize_dict(self, attr, dict_type): + """Deserialize a dictionary. + + :param dict/list attr: Dictionary to be deserialized. Also accepts + a list of key, value pairs. + :param str dict_type: The object type of the items in the dictionary. + :return: Deserialized dictionary. + :rtype: dict + """ + if isinstance(attr, list): + return {x["key"]: self.deserialize_data(x["value"], dict_type) for x in attr} + + if isinstance(attr, ET.Element): + # Transform value into {"Key": "value"} + attr = {el.tag: el.text for el in attr} + return {k: self.deserialize_data(v, dict_type) for k, v in attr.items()} + + def deserialize_object(self, attr, **kwargs): # pylint: disable=too-many-return-statements + """Deserialize a generic object. + This will be handled as a dictionary. + + :param dict attr: Dictionary to be deserialized. + :return: Deserialized object. + :rtype: dict + :raises TypeError: if non-builtin datatype encountered. + """ + if attr is None: + return None + if isinstance(attr, ET.Element): + # Do no recurse on XML, just return the tree as-is + return attr + if isinstance(attr, str): + return self.deserialize_basic(attr, "str") + obj_type = type(attr) + if obj_type in self.basic_types: + return self.deserialize_basic(attr, self.basic_types[obj_type]) + if obj_type is _long_type: + return self.deserialize_long(attr) + + if obj_type == dict: + deserialized = {} + for key, value in attr.items(): + try: + deserialized[key] = self.deserialize_object(value, **kwargs) + except ValueError: + deserialized[key] = None + return deserialized + + if obj_type == list: + deserialized = [] + for obj in attr: + try: + deserialized.append(self.deserialize_object(obj, **kwargs)) + except ValueError: + pass + return deserialized + + error = "Cannot deserialize generic object with type: " + raise TypeError(error + str(obj_type)) + + def deserialize_basic(self, attr, data_type): # pylint: disable=too-many-return-statements + """Deserialize basic builtin data type from string. + Will attempt to convert to str, int, float and bool. + This function will also accept '1', '0', 'true' and 'false' as + valid bool values. + + :param str attr: response string to be deserialized. + :param str data_type: deserialization data type. + :return: Deserialized basic type. + :rtype: str, int, float or bool + :raises TypeError: if string format is not valid. + """ + # If we're here, data is supposed to be a basic type. + # If it's still an XML node, take the text + if isinstance(attr, ET.Element): + attr = attr.text + if not attr: + if data_type == "str": + # None or '', node is empty string. + return "" + # None or '', node with a strong type is None. + # Don't try to model "empty bool" or "empty int" + return None + + if data_type == "bool": + if attr in [True, False, 1, 0]: + return bool(attr) + if isinstance(attr, str): + if attr.lower() in ["true", "1"]: + return True + if attr.lower() in ["false", "0"]: + return False + raise TypeError("Invalid boolean value: {}".format(attr)) + + if data_type == "str": + return self.deserialize_unicode(attr) + return eval(data_type)(attr) # nosec # pylint: disable=eval-used + + @staticmethod + def deserialize_unicode(data): + """Preserve unicode objects in Python 2, otherwise return data + as a string. + + :param str data: response string to be deserialized. + :return: Deserialized string. + :rtype: str or unicode + """ + # We might be here because we have an enum modeled as string, + # and we try to deserialize a partial dict with enum inside + if isinstance(data, Enum): + return data + + # Consider this is real string + try: + if isinstance(data, unicode): # type: ignore + return data + except NameError: + return str(data) + return str(data) + + @staticmethod + def deserialize_enum(data, enum_obj): + """Deserialize string into enum object. + + If the string is not a valid enum value it will be returned as-is + and a warning will be logged. + + :param str data: Response string to be deserialized. If this value is + None or invalid it will be returned as-is. + :param Enum enum_obj: Enum object to deserialize to. + :return: Deserialized enum object. + :rtype: Enum + """ + if isinstance(data, enum_obj) or data is None: + return data + if isinstance(data, Enum): + data = data.value + if isinstance(data, int): + # Workaround. We might consider remove it in the future. + try: + return list(enum_obj.__members__.values())[data] + except IndexError as exc: + error = "{!r} is not a valid index for enum {!r}" + raise DeserializationError(error.format(data, enum_obj)) from exc + try: + return enum_obj(str(data)) + except ValueError: + for enum_value in enum_obj: + if enum_value.value.lower() == str(data).lower(): + return enum_value + # We don't fail anymore for unknown value, we deserialize as a string + _LOGGER.warning("Deserializer is not able to find %s as valid enum in %s", data, enum_obj) + return Deserializer.deserialize_unicode(data) + + @staticmethod + def deserialize_bytearray(attr): + """Deserialize string into bytearray. + + :param str attr: response string to be deserialized. + :return: Deserialized bytearray + :rtype: bytearray + :raises TypeError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + return bytearray(b64decode(attr)) # type: ignore + + @staticmethod + def deserialize_base64(attr): + """Deserialize base64 encoded string into string. + + :param str attr: response string to be deserialized. + :return: Deserialized base64 string + :rtype: bytearray + :raises TypeError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + padding = "=" * (3 - (len(attr) + 3) % 4) # type: ignore + attr = attr + padding # type: ignore + encoded = attr.replace("-", "+").replace("_", "/") + return b64decode(encoded) + + @staticmethod + def deserialize_decimal(attr): + """Deserialize string into Decimal object. + + :param str attr: response string to be deserialized. + :return: Deserialized decimal + :raises DeserializationError: if string format invalid. + :rtype: decimal + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + return decimal.Decimal(str(attr)) # type: ignore + except decimal.DecimalException as err: + msg = "Invalid decimal {}".format(attr) + raise DeserializationError(msg) from err + + @staticmethod + def deserialize_long(attr): + """Deserialize string into long (Py2) or int (Py3). + + :param str attr: response string to be deserialized. + :return: Deserialized int + :rtype: long or int + :raises ValueError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + return _long_type(attr) # type: ignore + + @staticmethod + def deserialize_duration(attr): + """Deserialize ISO-8601 formatted string into TimeDelta object. + + :param str attr: response string to be deserialized. + :return: Deserialized duration + :rtype: TimeDelta + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + duration = isodate.parse_duration(attr) + except (ValueError, OverflowError, AttributeError) as err: + msg = "Cannot deserialize duration object." + raise DeserializationError(msg) from err + return duration + + @staticmethod + def deserialize_date(attr): + """Deserialize ISO-8601 formatted string into Date object. + + :param str attr: response string to be deserialized. + :return: Deserialized date + :rtype: Date + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + if re.search(r"[^\W\d_]", attr, re.I + re.U): # type: ignore + raise DeserializationError("Date must have only digits and -. Received: %s" % attr) + # This must NOT use defaultmonth/defaultday. Using None ensure this raises an exception. + return isodate.parse_date(attr, defaultmonth=0, defaultday=0) + + @staticmethod + def deserialize_time(attr): + """Deserialize ISO-8601 formatted string into time object. + + :param str attr: response string to be deserialized. + :return: Deserialized time + :rtype: datetime.time + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + if re.search(r"[^\W\d_]", attr, re.I + re.U): # type: ignore + raise DeserializationError("Date must have only digits and -. Received: %s" % attr) + return isodate.parse_time(attr) + + @staticmethod + def deserialize_rfc(attr): + """Deserialize RFC-1123 formatted string into Datetime object. + + :param str attr: response string to be deserialized. + :return: Deserialized RFC datetime + :rtype: Datetime + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + parsed_date = email.utils.parsedate_tz(attr) # type: ignore + date_obj = datetime.datetime( + *parsed_date[:6], tzinfo=datetime.timezone(datetime.timedelta(minutes=(parsed_date[9] or 0) / 60)) + ) + if not date_obj.tzinfo: + date_obj = date_obj.astimezone(tz=TZ_UTC) + except ValueError as err: + msg = "Cannot deserialize to rfc datetime object." + raise DeserializationError(msg) from err + return date_obj + + @staticmethod + def deserialize_iso(attr): + """Deserialize ISO-8601 formatted string into Datetime object. + + :param str attr: response string to be deserialized. + :return: Deserialized ISO datetime + :rtype: Datetime + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + attr = attr.upper() # type: ignore + match = Deserializer.valid_date.match(attr) + if not match: + raise ValueError("Invalid datetime string: " + attr) + + check_decimal = attr.split(".") + if len(check_decimal) > 1: + decimal_str = "" + for digit in check_decimal[1]: + if digit.isdigit(): + decimal_str += digit + else: + break + if len(decimal_str) > 6: + attr = attr.replace(decimal_str, decimal_str[0:6]) + + date_obj = isodate.parse_datetime(attr) + test_utc = date_obj.utctimetuple() + if test_utc.tm_year > 9999 or test_utc.tm_year < 1: + raise OverflowError("Hit max or min date") + except (ValueError, OverflowError, AttributeError) as err: + msg = "Cannot deserialize datetime object." + raise DeserializationError(msg) from err + return date_obj + + @staticmethod + def deserialize_unix(attr): + """Serialize Datetime object into IntTime format. + This is represented as seconds. + + :param int attr: Object to be serialized. + :return: Deserialized datetime + :rtype: Datetime + :raises DeserializationError: if format invalid + """ + if isinstance(attr, ET.Element): + attr = int(attr.text) # type: ignore + try: + attr = int(attr) + date_obj = datetime.datetime.fromtimestamp(attr, TZ_UTC) + except ValueError as err: + msg = "Cannot deserialize to unix datetime object." + raise DeserializationError(msg) from err + return date_obj diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ConstantsVersionTolerant/constantsversiontolerant/aio/_client.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ConstantsVersionTolerant/constantsversiontolerant/aio/_client.py index 2967f8efb46..999fc01988b 100644 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ConstantsVersionTolerant/constantsversiontolerant/aio/_client.py +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ConstantsVersionTolerant/constantsversiontolerant/aio/_client.py @@ -14,7 +14,7 @@ from azure.core.pipeline import policies from azure.core.rest import AsyncHttpResponse, HttpRequest -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import AutoRestSwaggerConstantServiceConfiguration from .operations import ContantsOperations diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ConstantsVersionTolerant/constantsversiontolerant/aio/operations/_operations.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ConstantsVersionTolerant/constantsversiontolerant/aio/operations/_operations.py index 1d1a1c9e484..1b3afa72110 100644 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ConstantsVersionTolerant/constantsversiontolerant/aio/operations/_operations.py +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ConstantsVersionTolerant/constantsversiontolerant/aio/operations/_operations.py @@ -22,7 +22,7 @@ from azure.core.tracing.decorator_async import distributed_trace_async from azure.core.utils import case_insensitive_dict -from ..._serialization import Deserializer, Serializer +from ..._utils.serialization import Deserializer, Serializer from ...operations._operations import ( build_contants_put_client_constants_request, build_contants_put_model_as_string_no_required_one_value_default_request, diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ConstantsVersionTolerant/constantsversiontolerant/operations/_operations.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ConstantsVersionTolerant/constantsversiontolerant/operations/_operations.py index e412ecd7177..fc94494bdea 100644 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ConstantsVersionTolerant/constantsversiontolerant/operations/_operations.py +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ConstantsVersionTolerant/constantsversiontolerant/operations/_operations.py @@ -24,7 +24,7 @@ from azure.core.utils import case_insensitive_dict from .._configuration import AutoRestSwaggerConstantServiceConfiguration -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/CustomBaseUriMoreOptionsVersionTolerant/custombaseurlmoreoptionsversiontolerant/_client.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/CustomBaseUriMoreOptionsVersionTolerant/custombaseurlmoreoptionsversiontolerant/_client.py index 42e20516536..221ca4a0265 100644 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/CustomBaseUriMoreOptionsVersionTolerant/custombaseurlmoreoptionsversiontolerant/_client.py +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/CustomBaseUriMoreOptionsVersionTolerant/custombaseurlmoreoptionsversiontolerant/_client.py @@ -15,7 +15,7 @@ from azure.core.rest import HttpRequest, HttpResponse from ._configuration import AutoRestParameterizedCustomHostTestClientConfiguration -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer from .operations import PathsOperations diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/CustomBaseUriMoreOptionsVersionTolerant/custombaseurlmoreoptionsversiontolerant/_utils/__init__.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/CustomBaseUriMoreOptionsVersionTolerant/custombaseurlmoreoptionsversiontolerant/_utils/__init__.py new file mode 100644 index 00000000000..0af9b28f660 --- /dev/null +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/CustomBaseUriMoreOptionsVersionTolerant/custombaseurlmoreoptionsversiontolerant/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/CustomBaseUriMoreOptionsVersionTolerant/custombaseurlmoreoptionsversiontolerant/_utils/serialization.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/CustomBaseUriMoreOptionsVersionTolerant/custombaseurlmoreoptionsversiontolerant/_utils/serialization.py new file mode 100644 index 00000000000..f5187701d7b --- /dev/null +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/CustomBaseUriMoreOptionsVersionTolerant/custombaseurlmoreoptionsversiontolerant/_utils/serialization.py @@ -0,0 +1,2032 @@ +# pylint: disable=line-too-long,useless-suppression,too-many-lines +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +# pyright: reportUnnecessaryTypeIgnoreComment=false + +from base64 import b64decode, b64encode +import calendar +import datetime +import decimal +import email +from enum import Enum +import json +import logging +import re +import sys +import codecs +from typing import ( + Dict, + Any, + cast, + Optional, + Union, + AnyStr, + IO, + Mapping, + Callable, + MutableMapping, + List, +) + +try: + from urllib import quote # type: ignore +except ImportError: + from urllib.parse import quote +import xml.etree.ElementTree as ET + +import isodate # type: ignore +from typing_extensions import Self + +from azure.core.exceptions import DeserializationError, SerializationError +from azure.core.serialization import NULL as CoreNull + +_BOM = codecs.BOM_UTF8.decode(encoding="utf-8") + +JSON = MutableMapping[str, Any] + + +class RawDeserializer: + + # Accept "text" because we're open minded people... + JSON_REGEXP = re.compile(r"^(application|text)/([a-z+.]+\+)?json$") + + # Name used in context + CONTEXT_NAME = "deserialized_data" + + @classmethod + def deserialize_from_text(cls, data: Optional[Union[AnyStr, IO]], content_type: Optional[str] = None) -> Any: + """Decode data according to content-type. + + Accept a stream of data as well, but will be load at once in memory for now. + + If no content-type, will return the string version (not bytes, not stream) + + :param data: Input, could be bytes or stream (will be decoded with UTF8) or text + :type data: str or bytes or IO + :param str content_type: The content type. + :return: The deserialized data. + :rtype: object + """ + if hasattr(data, "read"): + # Assume a stream + data = cast(IO, data).read() + + if isinstance(data, bytes): + data_as_str = data.decode(encoding="utf-8-sig") + else: + # Explain to mypy the correct type. + data_as_str = cast(str, data) + + # Remove Byte Order Mark if present in string + data_as_str = data_as_str.lstrip(_BOM) + + if content_type is None: + return data + + if cls.JSON_REGEXP.match(content_type): + try: + return json.loads(data_as_str) + except ValueError as err: + raise DeserializationError("JSON is invalid: {}".format(err), err) from err + elif "xml" in (content_type or []): + try: + + try: + if isinstance(data, unicode): # type: ignore + # If I'm Python 2.7 and unicode XML will scream if I try a "fromstring" on unicode string + data_as_str = data_as_str.encode(encoding="utf-8") # type: ignore + except NameError: + pass + + return ET.fromstring(data_as_str) # nosec + except ET.ParseError as err: + # It might be because the server has an issue, and returned JSON with + # content-type XML.... + # So let's try a JSON load, and if it's still broken + # let's flow the initial exception + def _json_attemp(data): + try: + return True, json.loads(data) + except ValueError: + return False, None # Don't care about this one + + success, json_result = _json_attemp(data) + if success: + return json_result + # If i'm here, it's not JSON, it's not XML, let's scream + # and raise the last context in this block (the XML exception) + # The function hack is because Py2.7 messes up with exception + # context otherwise. + _LOGGER.critical("Wasn't XML not JSON, failing") + raise DeserializationError("XML is invalid") from err + elif content_type.startswith("text/"): + return data_as_str + raise DeserializationError("Cannot deserialize content-type: {}".format(content_type)) + + @classmethod + def deserialize_from_http_generics(cls, body_bytes: Optional[Union[AnyStr, IO]], headers: Mapping) -> Any: + """Deserialize from HTTP response. + + Use bytes and headers to NOT use any requests/aiohttp or whatever + specific implementation. + Headers will tested for "content-type" + + :param bytes body_bytes: The body of the response. + :param dict headers: The headers of the response. + :returns: The deserialized data. + :rtype: object + """ + # Try to use content-type from headers if available + content_type = None + if "content-type" in headers: + content_type = headers["content-type"].split(";")[0].strip().lower() + # Ouch, this server did not declare what it sent... + # Let's guess it's JSON... + # Also, since Autorest was considering that an empty body was a valid JSON, + # need that test as well.... + else: + content_type = "application/json" + + if body_bytes: + return cls.deserialize_from_text(body_bytes, content_type) + return None + + +_LOGGER = logging.getLogger(__name__) + +try: + _long_type = long # type: ignore +except NameError: + _long_type = int + +TZ_UTC = datetime.timezone.utc + +_FLATTEN = re.compile(r"(? None: + self.additional_properties: Optional[Dict[str, Any]] = {} + for k in kwargs: # pylint: disable=consider-using-dict-items + if k not in self._attribute_map: + _LOGGER.warning("%s is not a known attribute of class %s and will be ignored", k, self.__class__) + elif k in self._validation and self._validation[k].get("readonly", False): + _LOGGER.warning("Readonly attribute %s will be ignored in class %s", k, self.__class__) + else: + setattr(self, k, kwargs[k]) + + def __eq__(self, other: Any) -> bool: + """Compare objects by comparing all attributes. + + :param object other: The object to compare + :returns: True if objects are equal + :rtype: bool + """ + if isinstance(other, self.__class__): + return self.__dict__ == other.__dict__ + return False + + def __ne__(self, other: Any) -> bool: + """Compare objects by comparing all attributes. + + :param object other: The object to compare + :returns: True if objects are not equal + :rtype: bool + """ + return not self.__eq__(other) + + def __str__(self) -> str: + return str(self.__dict__) + + @classmethod + def enable_additional_properties_sending(cls) -> None: + cls._attribute_map["additional_properties"] = {"key": "", "type": "{object}"} + + @classmethod + def is_xml_model(cls) -> bool: + try: + cls._xml_map # type: ignore + except AttributeError: + return False + return True + + @classmethod + def _create_xml_node(cls): + """Create XML node. + + :returns: The XML node + :rtype: xml.etree.ElementTree.Element + """ + try: + xml_map = cls._xml_map # type: ignore + except AttributeError: + xml_map = {} + + return _create_xml_node(xml_map.get("name", cls.__name__), xml_map.get("prefix", None), xml_map.get("ns", None)) + + def serialize(self, keep_readonly: bool = False, **kwargs: Any) -> JSON: + """Return the JSON that would be sent to server from this model. + + This is an alias to `as_dict(full_restapi_key_transformer, keep_readonly=False)`. + + If you want XML serialization, you can pass the kwargs is_xml=True. + + :param bool keep_readonly: If you want to serialize the readonly attributes + :returns: A dict JSON compatible object + :rtype: dict + """ + serializer = Serializer(self._infer_class_models()) + return serializer._serialize( # type: ignore # pylint: disable=protected-access + self, keep_readonly=keep_readonly, **kwargs + ) + + def as_dict( + self, + keep_readonly: bool = True, + key_transformer: Callable[[str, Dict[str, Any], Any], Any] = attribute_transformer, + **kwargs: Any + ) -> JSON: + """Return a dict that can be serialized using json.dump. + + Advanced usage might optionally use a callback as parameter: + + .. code::python + + def my_key_transformer(key, attr_desc, value): + return key + + Key is the attribute name used in Python. Attr_desc + is a dict of metadata. Currently contains 'type' with the + msrest type and 'key' with the RestAPI encoded key. + Value is the current value in this object. + + The string returned will be used to serialize the key. + If the return type is a list, this is considered hierarchical + result dict. + + See the three examples in this file: + + - attribute_transformer + - full_restapi_key_transformer + - last_restapi_key_transformer + + If you want XML serialization, you can pass the kwargs is_xml=True. + + :param bool keep_readonly: If you want to serialize the readonly attributes + :param function key_transformer: A key transformer function. + :returns: A dict JSON compatible object + :rtype: dict + """ + serializer = Serializer(self._infer_class_models()) + return serializer._serialize( # type: ignore # pylint: disable=protected-access + self, key_transformer=key_transformer, keep_readonly=keep_readonly, **kwargs + ) + + @classmethod + def _infer_class_models(cls): + try: + str_models = cls.__module__.rsplit(".", 1)[0] + models = sys.modules[str_models] + client_models = {k: v for k, v in models.__dict__.items() if isinstance(v, type)} + if cls.__name__ not in client_models: + raise ValueError("Not Autorest generated code") + except Exception: # pylint: disable=broad-exception-caught + # Assume it's not Autorest generated (tests?). Add ourselves as dependencies. + client_models = {cls.__name__: cls} + return client_models + + @classmethod + def deserialize(cls, data: Any, content_type: Optional[str] = None) -> Self: + """Parse a str using the RestAPI syntax and return a model. + + :param str data: A str using RestAPI structure. JSON by default. + :param str content_type: JSON by default, set application/xml if XML. + :returns: An instance of this model + :raises DeserializationError: if something went wrong + :rtype: Self + """ + deserializer = Deserializer(cls._infer_class_models()) + return deserializer(cls.__name__, data, content_type=content_type) # type: ignore + + @classmethod + def from_dict( + cls, + data: Any, + key_extractors: Optional[Callable[[str, Dict[str, Any], Any], Any]] = None, + content_type: Optional[str] = None, + ) -> Self: + """Parse a dict using given key extractor return a model. + + By default consider key + extractors (rest_key_case_insensitive_extractor, attribute_key_case_insensitive_extractor + and last_rest_key_case_insensitive_extractor) + + :param dict data: A dict using RestAPI structure + :param function key_extractors: A key extractor function. + :param str content_type: JSON by default, set application/xml if XML. + :returns: An instance of this model + :raises DeserializationError: if something went wrong + :rtype: Self + """ + deserializer = Deserializer(cls._infer_class_models()) + deserializer.key_extractors = ( # type: ignore + [ # type: ignore + attribute_key_case_insensitive_extractor, + rest_key_case_insensitive_extractor, + last_rest_key_case_insensitive_extractor, + ] + if key_extractors is None + else key_extractors + ) + return deserializer(cls.__name__, data, content_type=content_type) # type: ignore + + @classmethod + def _flatten_subtype(cls, key, objects): + if "_subtype_map" not in cls.__dict__: + return {} + result = dict(cls._subtype_map[key]) + for valuetype in cls._subtype_map[key].values(): + result.update(objects[valuetype]._flatten_subtype(key, objects)) # pylint: disable=protected-access + return result + + @classmethod + def _classify(cls, response, objects): + """Check the class _subtype_map for any child classes. + We want to ignore any inherited _subtype_maps. + + :param dict response: The initial data + :param dict objects: The class objects + :returns: The class to be used + :rtype: class + """ + for subtype_key in cls.__dict__.get("_subtype_map", {}).keys(): + subtype_value = None + + if not isinstance(response, ET.Element): + rest_api_response_key = cls._get_rest_key_parts(subtype_key)[-1] + subtype_value = response.get(rest_api_response_key, None) or response.get(subtype_key, None) + else: + subtype_value = xml_key_extractor(subtype_key, cls._attribute_map[subtype_key], response) + if subtype_value: + # Try to match base class. Can be class name only + # (bug to fix in Autorest to support x-ms-discriminator-name) + if cls.__name__ == subtype_value: + return cls + flatten_mapping_type = cls._flatten_subtype(subtype_key, objects) + try: + return objects[flatten_mapping_type[subtype_value]] # type: ignore + except KeyError: + _LOGGER.warning( + "Subtype value %s has no mapping, use base class %s.", + subtype_value, + cls.__name__, + ) + break + else: + _LOGGER.warning("Discriminator %s is absent or null, use base class %s.", subtype_key, cls.__name__) + break + return cls + + @classmethod + def _get_rest_key_parts(cls, attr_key): + """Get the RestAPI key of this attr, split it and decode part + :param str attr_key: Attribute key must be in attribute_map. + :returns: A list of RestAPI part + :rtype: list + """ + rest_split_key = _FLATTEN.split(cls._attribute_map[attr_key]["key"]) + return [_decode_attribute_map_key(key_part) for key_part in rest_split_key] + + +def _decode_attribute_map_key(key): + """This decode a key in an _attribute_map to the actual key we want to look at + inside the received data. + + :param str key: A key string from the generated code + :returns: The decoded key + :rtype: str + """ + return key.replace("\\.", ".") + + +class Serializer: # pylint: disable=too-many-public-methods + """Request object model serializer.""" + + basic_types = {str: "str", int: "int", bool: "bool", float: "float"} + + _xml_basic_types_serializers = {"bool": lambda x: str(x).lower()} + days = {0: "Mon", 1: "Tue", 2: "Wed", 3: "Thu", 4: "Fri", 5: "Sat", 6: "Sun"} + months = { + 1: "Jan", + 2: "Feb", + 3: "Mar", + 4: "Apr", + 5: "May", + 6: "Jun", + 7: "Jul", + 8: "Aug", + 9: "Sep", + 10: "Oct", + 11: "Nov", + 12: "Dec", + } + validation = { + "min_length": lambda x, y: len(x) < y, + "max_length": lambda x, y: len(x) > y, + "minimum": lambda x, y: x < y, + "maximum": lambda x, y: x > y, + "minimum_ex": lambda x, y: x <= y, + "maximum_ex": lambda x, y: x >= y, + "min_items": lambda x, y: len(x) < y, + "max_items": lambda x, y: len(x) > y, + "pattern": lambda x, y: not re.match(y, x, re.UNICODE), + "unique": lambda x, y: len(x) != len(set(x)), + "multiple": lambda x, y: x % y != 0, + } + + def __init__(self, classes: Optional[Mapping[str, type]] = None) -> None: + self.serialize_type = { + "iso-8601": Serializer.serialize_iso, + "rfc-1123": Serializer.serialize_rfc, + "unix-time": Serializer.serialize_unix, + "duration": Serializer.serialize_duration, + "date": Serializer.serialize_date, + "time": Serializer.serialize_time, + "decimal": Serializer.serialize_decimal, + "long": Serializer.serialize_long, + "bytearray": Serializer.serialize_bytearray, + "base64": Serializer.serialize_base64, + "object": self.serialize_object, + "[]": self.serialize_iter, + "{}": self.serialize_dict, + } + self.dependencies: Dict[str, type] = dict(classes) if classes else {} + self.key_transformer = full_restapi_key_transformer + self.client_side_validation = True + + def _serialize( # pylint: disable=too-many-nested-blocks, too-many-branches, too-many-statements, too-many-locals + self, target_obj, data_type=None, **kwargs + ): + """Serialize data into a string according to type. + + :param object target_obj: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str, dict + :raises SerializationError: if serialization fails. + :returns: The serialized data. + """ + key_transformer = kwargs.get("key_transformer", self.key_transformer) + keep_readonly = kwargs.get("keep_readonly", False) + if target_obj is None: + return None + + attr_name = None + class_name = target_obj.__class__.__name__ + + if data_type: + return self.serialize_data(target_obj, data_type, **kwargs) + + if not hasattr(target_obj, "_attribute_map"): + data_type = type(target_obj).__name__ + if data_type in self.basic_types.values(): + return self.serialize_data(target_obj, data_type, **kwargs) + + # Force "is_xml" kwargs if we detect a XML model + try: + is_xml_model_serialization = kwargs["is_xml"] + except KeyError: + is_xml_model_serialization = kwargs.setdefault("is_xml", target_obj.is_xml_model()) + + serialized = {} + if is_xml_model_serialization: + serialized = target_obj._create_xml_node() # pylint: disable=protected-access + try: + attributes = target_obj._attribute_map # pylint: disable=protected-access + for attr, attr_desc in attributes.items(): + attr_name = attr + if not keep_readonly and target_obj._validation.get( # pylint: disable=protected-access + attr_name, {} + ).get("readonly", False): + continue + + if attr_name == "additional_properties" and attr_desc["key"] == "": + if target_obj.additional_properties is not None: + serialized.update(target_obj.additional_properties) + continue + try: + + orig_attr = getattr(target_obj, attr) + if is_xml_model_serialization: + pass # Don't provide "transformer" for XML for now. Keep "orig_attr" + else: # JSON + keys, orig_attr = key_transformer(attr, attr_desc.copy(), orig_attr) + keys = keys if isinstance(keys, list) else [keys] + + kwargs["serialization_ctxt"] = attr_desc + new_attr = self.serialize_data(orig_attr, attr_desc["type"], **kwargs) + + if is_xml_model_serialization: + xml_desc = attr_desc.get("xml", {}) + xml_name = xml_desc.get("name", attr_desc["key"]) + xml_prefix = xml_desc.get("prefix", None) + xml_ns = xml_desc.get("ns", None) + if xml_desc.get("attr", False): + if xml_ns: + ET.register_namespace(xml_prefix, xml_ns) + xml_name = "{{{}}}{}".format(xml_ns, xml_name) + serialized.set(xml_name, new_attr) # type: ignore + continue + if xml_desc.get("text", False): + serialized.text = new_attr # type: ignore + continue + if isinstance(new_attr, list): + serialized.extend(new_attr) # type: ignore + elif isinstance(new_attr, ET.Element): + # If the down XML has no XML/Name, + # we MUST replace the tag with the local tag. But keeping the namespaces. + if "name" not in getattr(orig_attr, "_xml_map", {}): + splitted_tag = new_attr.tag.split("}") + if len(splitted_tag) == 2: # Namespace + new_attr.tag = "}".join([splitted_tag[0], xml_name]) + else: + new_attr.tag = xml_name + serialized.append(new_attr) # type: ignore + else: # That's a basic type + # Integrate namespace if necessary + local_node = _create_xml_node(xml_name, xml_prefix, xml_ns) + local_node.text = str(new_attr) + serialized.append(local_node) # type: ignore + else: # JSON + for k in reversed(keys): # type: ignore + new_attr = {k: new_attr} + + _new_attr = new_attr + _serialized = serialized + for k in keys: # type: ignore + if k not in _serialized: + _serialized.update(_new_attr) # type: ignore + _new_attr = _new_attr[k] # type: ignore + _serialized = _serialized[k] + except ValueError as err: + if isinstance(err, SerializationError): + raise + + except (AttributeError, KeyError, TypeError) as err: + msg = "Attribute {} in object {} cannot be serialized.\n{}".format(attr_name, class_name, str(target_obj)) + raise SerializationError(msg) from err + return serialized + + def body(self, data, data_type, **kwargs): + """Serialize data intended for a request body. + + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: dict + :raises SerializationError: if serialization fails. + :raises ValueError: if data is None + :returns: The serialized request body + """ + + # Just in case this is a dict + internal_data_type_str = data_type.strip("[]{}") + internal_data_type = self.dependencies.get(internal_data_type_str, None) + try: + is_xml_model_serialization = kwargs["is_xml"] + except KeyError: + if internal_data_type and issubclass(internal_data_type, Model): + is_xml_model_serialization = kwargs.setdefault("is_xml", internal_data_type.is_xml_model()) + else: + is_xml_model_serialization = False + if internal_data_type and not isinstance(internal_data_type, Enum): + try: + deserializer = Deserializer(self.dependencies) + # Since it's on serialization, it's almost sure that format is not JSON REST + # We're not able to deal with additional properties for now. + deserializer.additional_properties_detection = False + if is_xml_model_serialization: + deserializer.key_extractors = [ # type: ignore + attribute_key_case_insensitive_extractor, + ] + else: + deserializer.key_extractors = [ + rest_key_case_insensitive_extractor, + attribute_key_case_insensitive_extractor, + last_rest_key_case_insensitive_extractor, + ] + data = deserializer._deserialize(data_type, data) # pylint: disable=protected-access + except DeserializationError as err: + raise SerializationError("Unable to build a model: " + str(err)) from err + + return self._serialize(data, data_type, **kwargs) + + def url(self, name, data, data_type, **kwargs): + """Serialize data intended for a URL path. + + :param str name: The name of the URL path parameter. + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str + :returns: The serialized URL path + :raises TypeError: if serialization fails. + :raises ValueError: if data is None + """ + try: + output = self.serialize_data(data, data_type, **kwargs) + if data_type == "bool": + output = json.dumps(output) + + if kwargs.get("skip_quote") is True: + output = str(output) + output = output.replace("{", quote("{")).replace("}", quote("}")) + else: + output = quote(str(output), safe="") + except SerializationError as exc: + raise TypeError("{} must be type {}.".format(name, data_type)) from exc + return output + + def query(self, name, data, data_type, **kwargs): + """Serialize data intended for a URL query. + + :param str name: The name of the query parameter. + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str, list + :raises TypeError: if serialization fails. + :raises ValueError: if data is None + :returns: The serialized query parameter + """ + try: + # Treat the list aside, since we don't want to encode the div separator + if data_type.startswith("["): + internal_data_type = data_type[1:-1] + do_quote = not kwargs.get("skip_quote", False) + return self.serialize_iter(data, internal_data_type, do_quote=do_quote, **kwargs) + + # Not a list, regular serialization + output = self.serialize_data(data, data_type, **kwargs) + if data_type == "bool": + output = json.dumps(output) + if kwargs.get("skip_quote") is True: + output = str(output) + else: + output = quote(str(output), safe="") + except SerializationError as exc: + raise TypeError("{} must be type {}.".format(name, data_type)) from exc + return str(output) + + def header(self, name, data, data_type, **kwargs): + """Serialize data intended for a request header. + + :param str name: The name of the header. + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str + :raises TypeError: if serialization fails. + :raises ValueError: if data is None + :returns: The serialized header + """ + try: + if data_type in ["[str]"]: + data = ["" if d is None else d for d in data] + + output = self.serialize_data(data, data_type, **kwargs) + if data_type == "bool": + output = json.dumps(output) + except SerializationError as exc: + raise TypeError("{} must be type {}.".format(name, data_type)) from exc + return str(output) + + def serialize_data(self, data, data_type, **kwargs): + """Serialize generic data according to supplied data type. + + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :raises AttributeError: if required data is None. + :raises ValueError: if data is None + :raises SerializationError: if serialization fails. + :returns: The serialized data. + :rtype: str, int, float, bool, dict, list + """ + if data is None: + raise ValueError("No value for given attribute") + + try: + if data is CoreNull: + return None + if data_type in self.basic_types.values(): + return self.serialize_basic(data, data_type, **kwargs) + + if data_type in self.serialize_type: + return self.serialize_type[data_type](data, **kwargs) + + # If dependencies is empty, try with current data class + # It has to be a subclass of Enum anyway + enum_type = self.dependencies.get(data_type, data.__class__) + if issubclass(enum_type, Enum): + return Serializer.serialize_enum(data, enum_obj=enum_type) + + iter_type = data_type[0] + data_type[-1] + if iter_type in self.serialize_type: + return self.serialize_type[iter_type](data, data_type[1:-1], **kwargs) + + except (ValueError, TypeError) as err: + msg = "Unable to serialize value: {!r} as type: {!r}." + raise SerializationError(msg.format(data, data_type)) from err + return self._serialize(data, **kwargs) + + @classmethod + def _get_custom_serializers(cls, data_type, **kwargs): # pylint: disable=inconsistent-return-statements + custom_serializer = kwargs.get("basic_types_serializers", {}).get(data_type) + if custom_serializer: + return custom_serializer + if kwargs.get("is_xml", False): + return cls._xml_basic_types_serializers.get(data_type) + + @classmethod + def serialize_basic(cls, data, data_type, **kwargs): + """Serialize basic builting data type. + Serializes objects to str, int, float or bool. + + Possible kwargs: + - basic_types_serializers dict[str, callable] : If set, use the callable as serializer + - is_xml bool : If set, use xml_basic_types_serializers + + :param obj data: Object to be serialized. + :param str data_type: Type of object in the iterable. + :rtype: str, int, float, bool + :return: serialized object + """ + custom_serializer = cls._get_custom_serializers(data_type, **kwargs) + if custom_serializer: + return custom_serializer(data) + if data_type == "str": + return cls.serialize_unicode(data) + return eval(data_type)(data) # nosec # pylint: disable=eval-used + + @classmethod + def serialize_unicode(cls, data): + """Special handling for serializing unicode strings in Py2. + Encode to UTF-8 if unicode, otherwise handle as a str. + + :param str data: Object to be serialized. + :rtype: str + :return: serialized object + """ + try: # If I received an enum, return its value + return data.value + except AttributeError: + pass + + try: + if isinstance(data, unicode): # type: ignore + # Don't change it, JSON and XML ElementTree are totally able + # to serialize correctly u'' strings + return data + except NameError: + return str(data) + return str(data) + + def serialize_iter(self, data, iter_type, div=None, **kwargs): + """Serialize iterable. + + Supported kwargs: + - serialization_ctxt dict : The current entry of _attribute_map, or same format. + serialization_ctxt['type'] should be same as data_type. + - is_xml bool : If set, serialize as XML + + :param list data: Object to be serialized. + :param str iter_type: Type of object in the iterable. + :param str div: If set, this str will be used to combine the elements + in the iterable into a combined string. Default is 'None'. + Defaults to False. + :rtype: list, str + :return: serialized iterable + """ + if isinstance(data, str): + raise SerializationError("Refuse str type as a valid iter type.") + + serialization_ctxt = kwargs.get("serialization_ctxt", {}) + is_xml = kwargs.get("is_xml", False) + + serialized = [] + for d in data: + try: + serialized.append(self.serialize_data(d, iter_type, **kwargs)) + except ValueError as err: + if isinstance(err, SerializationError): + raise + serialized.append(None) + + if kwargs.get("do_quote", False): + serialized = ["" if s is None else quote(str(s), safe="") for s in serialized] + + if div: + serialized = ["" if s is None else str(s) for s in serialized] + serialized = div.join(serialized) + + if "xml" in serialization_ctxt or is_xml: + # XML serialization is more complicated + xml_desc = serialization_ctxt.get("xml", {}) + xml_name = xml_desc.get("name") + if not xml_name: + xml_name = serialization_ctxt["key"] + + # Create a wrap node if necessary (use the fact that Element and list have "append") + is_wrapped = xml_desc.get("wrapped", False) + node_name = xml_desc.get("itemsName", xml_name) + if is_wrapped: + final_result = _create_xml_node(xml_name, xml_desc.get("prefix", None), xml_desc.get("ns", None)) + else: + final_result = [] + # All list elements to "local_node" + for el in serialized: + if isinstance(el, ET.Element): + el_node = el + else: + el_node = _create_xml_node(node_name, xml_desc.get("prefix", None), xml_desc.get("ns", None)) + if el is not None: # Otherwise it writes "None" :-p + el_node.text = str(el) + final_result.append(el_node) + return final_result + return serialized + + def serialize_dict(self, attr, dict_type, **kwargs): + """Serialize a dictionary of objects. + + :param dict attr: Object to be serialized. + :param str dict_type: Type of object in the dictionary. + :rtype: dict + :return: serialized dictionary + """ + serialization_ctxt = kwargs.get("serialization_ctxt", {}) + serialized = {} + for key, value in attr.items(): + try: + serialized[self.serialize_unicode(key)] = self.serialize_data(value, dict_type, **kwargs) + except ValueError as err: + if isinstance(err, SerializationError): + raise + serialized[self.serialize_unicode(key)] = None + + if "xml" in serialization_ctxt: + # XML serialization is more complicated + xml_desc = serialization_ctxt["xml"] + xml_name = xml_desc["name"] + + final_result = _create_xml_node(xml_name, xml_desc.get("prefix", None), xml_desc.get("ns", None)) + for key, value in serialized.items(): + ET.SubElement(final_result, key).text = value + return final_result + + return serialized + + def serialize_object(self, attr, **kwargs): # pylint: disable=too-many-return-statements + """Serialize a generic object. + This will be handled as a dictionary. If object passed in is not + a basic type (str, int, float, dict, list) it will simply be + cast to str. + + :param dict attr: Object to be serialized. + :rtype: dict or str + :return: serialized object + """ + if attr is None: + return None + if isinstance(attr, ET.Element): + return attr + obj_type = type(attr) + if obj_type in self.basic_types: + return self.serialize_basic(attr, self.basic_types[obj_type], **kwargs) + if obj_type is _long_type: + return self.serialize_long(attr) + if obj_type is str: + return self.serialize_unicode(attr) + if obj_type is datetime.datetime: + return self.serialize_iso(attr) + if obj_type is datetime.date: + return self.serialize_date(attr) + if obj_type is datetime.time: + return self.serialize_time(attr) + if obj_type is datetime.timedelta: + return self.serialize_duration(attr) + if obj_type is decimal.Decimal: + return self.serialize_decimal(attr) + + # If it's a model or I know this dependency, serialize as a Model + if obj_type in self.dependencies.values() or isinstance(attr, Model): + return self._serialize(attr) + + if obj_type == dict: + serialized = {} + for key, value in attr.items(): + try: + serialized[self.serialize_unicode(key)] = self.serialize_object(value, **kwargs) + except ValueError: + serialized[self.serialize_unicode(key)] = None + return serialized + + if obj_type == list: + serialized = [] + for obj in attr: + try: + serialized.append(self.serialize_object(obj, **kwargs)) + except ValueError: + pass + return serialized + return str(attr) + + @staticmethod + def serialize_enum(attr, enum_obj=None): + try: + result = attr.value + except AttributeError: + result = attr + try: + enum_obj(result) # type: ignore + return result + except ValueError as exc: + for enum_value in enum_obj: # type: ignore + if enum_value.value.lower() == str(attr).lower(): + return enum_value.value + error = "{!r} is not valid value for enum {!r}" + raise SerializationError(error.format(attr, enum_obj)) from exc + + @staticmethod + def serialize_bytearray(attr, **kwargs): # pylint: disable=unused-argument + """Serialize bytearray into base-64 string. + + :param str attr: Object to be serialized. + :rtype: str + :return: serialized base64 + """ + return b64encode(attr).decode() + + @staticmethod + def serialize_base64(attr, **kwargs): # pylint: disable=unused-argument + """Serialize str into base-64 string. + + :param str attr: Object to be serialized. + :rtype: str + :return: serialized base64 + """ + encoded = b64encode(attr).decode("ascii") + return encoded.strip("=").replace("+", "-").replace("/", "_") + + @staticmethod + def serialize_decimal(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Decimal object to float. + + :param decimal attr: Object to be serialized. + :rtype: float + :return: serialized decimal + """ + return float(attr) + + @staticmethod + def serialize_long(attr, **kwargs): # pylint: disable=unused-argument + """Serialize long (Py2) or int (Py3). + + :param int attr: Object to be serialized. + :rtype: int/long + :return: serialized long + """ + return _long_type(attr) + + @staticmethod + def serialize_date(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Date object into ISO-8601 formatted string. + + :param Date attr: Object to be serialized. + :rtype: str + :return: serialized date + """ + if isinstance(attr, str): + attr = isodate.parse_date(attr) + t = "{:04}-{:02}-{:02}".format(attr.year, attr.month, attr.day) + return t + + @staticmethod + def serialize_time(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Time object into ISO-8601 formatted string. + + :param datetime.time attr: Object to be serialized. + :rtype: str + :return: serialized time + """ + if isinstance(attr, str): + attr = isodate.parse_time(attr) + t = "{:02}:{:02}:{:02}".format(attr.hour, attr.minute, attr.second) + if attr.microsecond: + t += ".{:02}".format(attr.microsecond) + return t + + @staticmethod + def serialize_duration(attr, **kwargs): # pylint: disable=unused-argument + """Serialize TimeDelta object into ISO-8601 formatted string. + + :param TimeDelta attr: Object to be serialized. + :rtype: str + :return: serialized duration + """ + if isinstance(attr, str): + attr = isodate.parse_duration(attr) + return isodate.duration_isoformat(attr) + + @staticmethod + def serialize_rfc(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Datetime object into RFC-1123 formatted string. + + :param Datetime attr: Object to be serialized. + :rtype: str + :raises TypeError: if format invalid. + :return: serialized rfc + """ + try: + if not attr.tzinfo: + _LOGGER.warning("Datetime with no tzinfo will be considered UTC.") + utc = attr.utctimetuple() + except AttributeError as exc: + raise TypeError("RFC1123 object must be valid Datetime object.") from exc + + return "{}, {:02} {} {:04} {:02}:{:02}:{:02} GMT".format( + Serializer.days[utc.tm_wday], + utc.tm_mday, + Serializer.months[utc.tm_mon], + utc.tm_year, + utc.tm_hour, + utc.tm_min, + utc.tm_sec, + ) + + @staticmethod + def serialize_iso(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Datetime object into ISO-8601 formatted string. + + :param Datetime attr: Object to be serialized. + :rtype: str + :raises SerializationError: if format invalid. + :return: serialized iso + """ + if isinstance(attr, str): + attr = isodate.parse_datetime(attr) + try: + if not attr.tzinfo: + _LOGGER.warning("Datetime with no tzinfo will be considered UTC.") + utc = attr.utctimetuple() + if utc.tm_year > 9999 or utc.tm_year < 1: + raise OverflowError("Hit max or min date") + + microseconds = str(attr.microsecond).rjust(6, "0").rstrip("0").ljust(3, "0") + if microseconds: + microseconds = "." + microseconds + date = "{:04}-{:02}-{:02}T{:02}:{:02}:{:02}".format( + utc.tm_year, utc.tm_mon, utc.tm_mday, utc.tm_hour, utc.tm_min, utc.tm_sec + ) + return date + microseconds + "Z" + except (ValueError, OverflowError) as err: + msg = "Unable to serialize datetime object." + raise SerializationError(msg) from err + except AttributeError as err: + msg = "ISO-8601 object must be valid Datetime object." + raise TypeError(msg) from err + + @staticmethod + def serialize_unix(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Datetime object into IntTime format. + This is represented as seconds. + + :param Datetime attr: Object to be serialized. + :rtype: int + :raises SerializationError: if format invalid + :return: serialied unix + """ + if isinstance(attr, int): + return attr + try: + if not attr.tzinfo: + _LOGGER.warning("Datetime with no tzinfo will be considered UTC.") + return int(calendar.timegm(attr.utctimetuple())) + except AttributeError as exc: + raise TypeError("Unix time object must be valid Datetime object.") from exc + + +def rest_key_extractor(attr, attr_desc, data): # pylint: disable=unused-argument + key = attr_desc["key"] + working_data = data + + while "." in key: + # Need the cast, as for some reasons "split" is typed as list[str | Any] + dict_keys = cast(List[str], _FLATTEN.split(key)) + if len(dict_keys) == 1: + key = _decode_attribute_map_key(dict_keys[0]) + break + working_key = _decode_attribute_map_key(dict_keys[0]) + working_data = working_data.get(working_key, data) + if working_data is None: + # If at any point while following flatten JSON path see None, it means + # that all properties under are None as well + return None + key = ".".join(dict_keys[1:]) + + return working_data.get(key) + + +def rest_key_case_insensitive_extractor( # pylint: disable=unused-argument, inconsistent-return-statements + attr, attr_desc, data +): + key = attr_desc["key"] + working_data = data + + while "." in key: + dict_keys = _FLATTEN.split(key) + if len(dict_keys) == 1: + key = _decode_attribute_map_key(dict_keys[0]) + break + working_key = _decode_attribute_map_key(dict_keys[0]) + working_data = attribute_key_case_insensitive_extractor(working_key, None, working_data) + if working_data is None: + # If at any point while following flatten JSON path see None, it means + # that all properties under are None as well + return None + key = ".".join(dict_keys[1:]) + + if working_data: + return attribute_key_case_insensitive_extractor(key, None, working_data) + + +def last_rest_key_extractor(attr, attr_desc, data): # pylint: disable=unused-argument + """Extract the attribute in "data" based on the last part of the JSON path key. + + :param str attr: The attribute to extract + :param dict attr_desc: The attribute description + :param dict data: The data to extract from + :rtype: object + :returns: The extracted attribute + """ + key = attr_desc["key"] + dict_keys = _FLATTEN.split(key) + return attribute_key_extractor(dict_keys[-1], None, data) + + +def last_rest_key_case_insensitive_extractor(attr, attr_desc, data): # pylint: disable=unused-argument + """Extract the attribute in "data" based on the last part of the JSON path key. + + This is the case insensitive version of "last_rest_key_extractor" + :param str attr: The attribute to extract + :param dict attr_desc: The attribute description + :param dict data: The data to extract from + :rtype: object + :returns: The extracted attribute + """ + key = attr_desc["key"] + dict_keys = _FLATTEN.split(key) + return attribute_key_case_insensitive_extractor(dict_keys[-1], None, data) + + +def attribute_key_extractor(attr, _, data): + return data.get(attr) + + +def attribute_key_case_insensitive_extractor(attr, _, data): + found_key = None + lower_attr = attr.lower() + for key in data: + if lower_attr == key.lower(): + found_key = key + break + + return data.get(found_key) + + +def _extract_name_from_internal_type(internal_type): + """Given an internal type XML description, extract correct XML name with namespace. + + :param dict internal_type: An model type + :rtype: tuple + :returns: A tuple XML name + namespace dict + """ + internal_type_xml_map = getattr(internal_type, "_xml_map", {}) + xml_name = internal_type_xml_map.get("name", internal_type.__name__) + xml_ns = internal_type_xml_map.get("ns", None) + if xml_ns: + xml_name = "{{{}}}{}".format(xml_ns, xml_name) + return xml_name + + +def xml_key_extractor(attr, attr_desc, data): # pylint: disable=unused-argument,too-many-return-statements + if isinstance(data, dict): + return None + + # Test if this model is XML ready first + if not isinstance(data, ET.Element): + return None + + xml_desc = attr_desc.get("xml", {}) + xml_name = xml_desc.get("name", attr_desc["key"]) + + # Look for a children + is_iter_type = attr_desc["type"].startswith("[") + is_wrapped = xml_desc.get("wrapped", False) + internal_type = attr_desc.get("internalType", None) + internal_type_xml_map = getattr(internal_type, "_xml_map", {}) + + # Integrate namespace if necessary + xml_ns = xml_desc.get("ns", internal_type_xml_map.get("ns", None)) + if xml_ns: + xml_name = "{{{}}}{}".format(xml_ns, xml_name) + + # If it's an attribute, that's simple + if xml_desc.get("attr", False): + return data.get(xml_name) + + # If it's x-ms-text, that's simple too + if xml_desc.get("text", False): + return data.text + + # Scenario where I take the local name: + # - Wrapped node + # - Internal type is an enum (considered basic types) + # - Internal type has no XML/Name node + if is_wrapped or (internal_type and (issubclass(internal_type, Enum) or "name" not in internal_type_xml_map)): + children = data.findall(xml_name) + # If internal type has a local name and it's not a list, I use that name + elif not is_iter_type and internal_type and "name" in internal_type_xml_map: + xml_name = _extract_name_from_internal_type(internal_type) + children = data.findall(xml_name) + # That's an array + else: + if internal_type: # Complex type, ignore itemsName and use the complex type name + items_name = _extract_name_from_internal_type(internal_type) + else: + items_name = xml_desc.get("itemsName", xml_name) + children = data.findall(items_name) + + if len(children) == 0: + if is_iter_type: + if is_wrapped: + return None # is_wrapped no node, we want None + return [] # not wrapped, assume empty list + return None # Assume it's not there, maybe an optional node. + + # If is_iter_type and not wrapped, return all found children + if is_iter_type: + if not is_wrapped: + return children + # Iter and wrapped, should have found one node only (the wrap one) + if len(children) != 1: + raise DeserializationError( + "Tried to deserialize an array not wrapped, and found several nodes '{}'. Maybe you should declare this array as wrapped?".format( + xml_name + ) + ) + return list(children[0]) # Might be empty list and that's ok. + + # Here it's not a itertype, we should have found one element only or empty + if len(children) > 1: + raise DeserializationError("Find several XML '{}' where it was not expected".format(xml_name)) + return children[0] + + +class Deserializer: + """Response object model deserializer. + + :param dict classes: Class type dictionary for deserializing complex types. + :ivar list key_extractors: Ordered list of extractors to be used by this deserializer. + """ + + basic_types = {str: "str", int: "int", bool: "bool", float: "float"} + + valid_date = re.compile(r"\d{4}[-]\d{2}[-]\d{2}T\d{2}:\d{2}:\d{2}\.?\d*Z?[-+]?[\d{2}]?:?[\d{2}]?") + + def __init__(self, classes: Optional[Mapping[str, type]] = None) -> None: + self.deserialize_type = { + "iso-8601": Deserializer.deserialize_iso, + "rfc-1123": Deserializer.deserialize_rfc, + "unix-time": Deserializer.deserialize_unix, + "duration": Deserializer.deserialize_duration, + "date": Deserializer.deserialize_date, + "time": Deserializer.deserialize_time, + "decimal": Deserializer.deserialize_decimal, + "long": Deserializer.deserialize_long, + "bytearray": Deserializer.deserialize_bytearray, + "base64": Deserializer.deserialize_base64, + "object": self.deserialize_object, + "[]": self.deserialize_iter, + "{}": self.deserialize_dict, + } + self.deserialize_expected_types = { + "duration": (isodate.Duration, datetime.timedelta), + "iso-8601": (datetime.datetime), + } + self.dependencies: Dict[str, type] = dict(classes) if classes else {} + self.key_extractors = [rest_key_extractor, xml_key_extractor] + # Additional properties only works if the "rest_key_extractor" is used to + # extract the keys. Making it to work whatever the key extractor is too much + # complicated, with no real scenario for now. + # So adding a flag to disable additional properties detection. This flag should be + # used if your expect the deserialization to NOT come from a JSON REST syntax. + # Otherwise, result are unexpected + self.additional_properties_detection = True + + def __call__(self, target_obj, response_data, content_type=None): + """Call the deserializer to process a REST response. + + :param str target_obj: Target data type to deserialize to. + :param requests.Response response_data: REST response object. + :param str content_type: Swagger "produces" if available. + :raises DeserializationError: if deserialization fails. + :return: Deserialized object. + :rtype: object + """ + data = self._unpack_content(response_data, content_type) + return self._deserialize(target_obj, data) + + def _deserialize(self, target_obj, data): # pylint: disable=inconsistent-return-statements + """Call the deserializer on a model. + + Data needs to be already deserialized as JSON or XML ElementTree + + :param str target_obj: Target data type to deserialize to. + :param object data: Object to deserialize. + :raises DeserializationError: if deserialization fails. + :return: Deserialized object. + :rtype: object + """ + # This is already a model, go recursive just in case + if hasattr(data, "_attribute_map"): + constants = [name for name, config in getattr(data, "_validation", {}).items() if config.get("constant")] + try: + for attr, mapconfig in data._attribute_map.items(): # pylint: disable=protected-access + if attr in constants: + continue + value = getattr(data, attr) + if value is None: + continue + local_type = mapconfig["type"] + internal_data_type = local_type.strip("[]{}") + if internal_data_type not in self.dependencies or isinstance(internal_data_type, Enum): + continue + setattr(data, attr, self._deserialize(local_type, value)) + return data + except AttributeError: + return + + response, class_name = self._classify_target(target_obj, data) + + if isinstance(response, str): + return self.deserialize_data(data, response) + if isinstance(response, type) and issubclass(response, Enum): + return self.deserialize_enum(data, response) + + if data is None or data is CoreNull: + return data + try: + attributes = response._attribute_map # type: ignore # pylint: disable=protected-access + d_attrs = {} + for attr, attr_desc in attributes.items(): + # Check empty string. If it's not empty, someone has a real "additionalProperties"... + if attr == "additional_properties" and attr_desc["key"] == "": + continue + raw_value = None + # Enhance attr_desc with some dynamic data + attr_desc = attr_desc.copy() # Do a copy, do not change the real one + internal_data_type = attr_desc["type"].strip("[]{}") + if internal_data_type in self.dependencies: + attr_desc["internalType"] = self.dependencies[internal_data_type] + + for key_extractor in self.key_extractors: + found_value = key_extractor(attr, attr_desc, data) + if found_value is not None: + if raw_value is not None and raw_value != found_value: + msg = ( + "Ignoring extracted value '%s' from %s for key '%s'" + " (duplicate extraction, follow extractors order)" + ) + _LOGGER.warning(msg, found_value, key_extractor, attr) + continue + raw_value = found_value + + value = self.deserialize_data(raw_value, attr_desc["type"]) + d_attrs[attr] = value + except (AttributeError, TypeError, KeyError) as err: + msg = "Unable to deserialize to object: " + class_name # type: ignore + raise DeserializationError(msg) from err + additional_properties = self._build_additional_properties(attributes, data) + return self._instantiate_model(response, d_attrs, additional_properties) + + def _build_additional_properties(self, attribute_map, data): + if not self.additional_properties_detection: + return None + if "additional_properties" in attribute_map and attribute_map.get("additional_properties", {}).get("key") != "": + # Check empty string. If it's not empty, someone has a real "additionalProperties" + return None + if isinstance(data, ET.Element): + data = {el.tag: el.text for el in data} + + known_keys = { + _decode_attribute_map_key(_FLATTEN.split(desc["key"])[0]) + for desc in attribute_map.values() + if desc["key"] != "" + } + present_keys = set(data.keys()) + missing_keys = present_keys - known_keys + return {key: data[key] for key in missing_keys} + + def _classify_target(self, target, data): + """Check to see whether the deserialization target object can + be classified into a subclass. + Once classification has been determined, initialize object. + + :param str target: The target object type to deserialize to. + :param str/dict data: The response data to deserialize. + :return: The classified target object and its class name. + :rtype: tuple + """ + if target is None: + return None, None + + if isinstance(target, str): + try: + target = self.dependencies[target] + except KeyError: + return target, target + + try: + target = target._classify(data, self.dependencies) # type: ignore # pylint: disable=protected-access + except AttributeError: + pass # Target is not a Model, no classify + return target, target.__class__.__name__ # type: ignore + + def failsafe_deserialize(self, target_obj, data, content_type=None): + """Ignores any errors encountered in deserialization, + and falls back to not deserializing the object. Recommended + for use in error deserialization, as we want to return the + HttpResponseError to users, and not have them deal with + a deserialization error. + + :param str target_obj: The target object type to deserialize to. + :param str/dict data: The response data to deserialize. + :param str content_type: Swagger "produces" if available. + :return: Deserialized object. + :rtype: object + """ + try: + return self(target_obj, data, content_type=content_type) + except: # pylint: disable=bare-except + _LOGGER.debug( + "Ran into a deserialization error. Ignoring since this is failsafe deserialization", exc_info=True + ) + return None + + @staticmethod + def _unpack_content(raw_data, content_type=None): + """Extract the correct structure for deserialization. + + If raw_data is a PipelineResponse, try to extract the result of RawDeserializer. + if we can't, raise. Your Pipeline should have a RawDeserializer. + + If not a pipeline response and raw_data is bytes or string, use content-type + to decode it. If no content-type, try JSON. + + If raw_data is something else, bypass all logic and return it directly. + + :param obj raw_data: Data to be processed. + :param str content_type: How to parse if raw_data is a string/bytes. + :raises JSONDecodeError: If JSON is requested and parsing is impossible. + :raises UnicodeDecodeError: If bytes is not UTF8 + :rtype: object + :return: Unpacked content. + """ + # Assume this is enough to detect a Pipeline Response without importing it + context = getattr(raw_data, "context", {}) + if context: + if RawDeserializer.CONTEXT_NAME in context: + return context[RawDeserializer.CONTEXT_NAME] + raise ValueError("This pipeline didn't have the RawDeserializer policy; can't deserialize") + + # Assume this is enough to recognize universal_http.ClientResponse without importing it + if hasattr(raw_data, "body"): + return RawDeserializer.deserialize_from_http_generics(raw_data.text(), raw_data.headers) + + # Assume this enough to recognize requests.Response without importing it. + if hasattr(raw_data, "_content_consumed"): + return RawDeserializer.deserialize_from_http_generics(raw_data.text, raw_data.headers) + + if isinstance(raw_data, (str, bytes)) or hasattr(raw_data, "read"): + return RawDeserializer.deserialize_from_text(raw_data, content_type) # type: ignore + return raw_data + + def _instantiate_model(self, response, attrs, additional_properties=None): + """Instantiate a response model passing in deserialized args. + + :param Response response: The response model class. + :param dict attrs: The deserialized response attributes. + :param dict additional_properties: Additional properties to be set. + :rtype: Response + :return: The instantiated response model. + """ + if callable(response): + subtype = getattr(response, "_subtype_map", {}) + try: + readonly = [ + k + for k, v in response._validation.items() # pylint: disable=protected-access # type: ignore + if v.get("readonly") + ] + const = [ + k + for k, v in response._validation.items() # pylint: disable=protected-access # type: ignore + if v.get("constant") + ] + kwargs = {k: v for k, v in attrs.items() if k not in subtype and k not in readonly + const} + response_obj = response(**kwargs) + for attr in readonly: + setattr(response_obj, attr, attrs.get(attr)) + if additional_properties: + response_obj.additional_properties = additional_properties # type: ignore + return response_obj + except TypeError as err: + msg = "Unable to deserialize {} into model {}. ".format(kwargs, response) # type: ignore + raise DeserializationError(msg + str(err)) from err + else: + try: + for attr, value in attrs.items(): + setattr(response, attr, value) + return response + except Exception as exp: + msg = "Unable to populate response model. " + msg += "Type: {}, Error: {}".format(type(response), exp) + raise DeserializationError(msg) from exp + + def deserialize_data(self, data, data_type): # pylint: disable=too-many-return-statements + """Process data for deserialization according to data type. + + :param str data: The response string to be deserialized. + :param str data_type: The type to deserialize to. + :raises DeserializationError: if deserialization fails. + :return: Deserialized object. + :rtype: object + """ + if data is None: + return data + + try: + if not data_type: + return data + if data_type in self.basic_types.values(): + return self.deserialize_basic(data, data_type) + if data_type in self.deserialize_type: + if isinstance(data, self.deserialize_expected_types.get(data_type, tuple())): + return data + + is_a_text_parsing_type = lambda x: x not in [ # pylint: disable=unnecessary-lambda-assignment + "object", + "[]", + r"{}", + ] + if isinstance(data, ET.Element) and is_a_text_parsing_type(data_type) and not data.text: + return None + data_val = self.deserialize_type[data_type](data) + return data_val + + iter_type = data_type[0] + data_type[-1] + if iter_type in self.deserialize_type: + return self.deserialize_type[iter_type](data, data_type[1:-1]) + + obj_type = self.dependencies[data_type] + if issubclass(obj_type, Enum): + if isinstance(data, ET.Element): + data = data.text + return self.deserialize_enum(data, obj_type) + + except (ValueError, TypeError, AttributeError) as err: + msg = "Unable to deserialize response data." + msg += " Data: {}, {}".format(data, data_type) + raise DeserializationError(msg) from err + return self._deserialize(obj_type, data) + + def deserialize_iter(self, attr, iter_type): + """Deserialize an iterable. + + :param list attr: Iterable to be deserialized. + :param str iter_type: The type of object in the iterable. + :return: Deserialized iterable. + :rtype: list + """ + if attr is None: + return None + if isinstance(attr, ET.Element): # If I receive an element here, get the children + attr = list(attr) + if not isinstance(attr, (list, set)): + raise DeserializationError("Cannot deserialize as [{}] an object of type {}".format(iter_type, type(attr))) + return [self.deserialize_data(a, iter_type) for a in attr] + + def deserialize_dict(self, attr, dict_type): + """Deserialize a dictionary. + + :param dict/list attr: Dictionary to be deserialized. Also accepts + a list of key, value pairs. + :param str dict_type: The object type of the items in the dictionary. + :return: Deserialized dictionary. + :rtype: dict + """ + if isinstance(attr, list): + return {x["key"]: self.deserialize_data(x["value"], dict_type) for x in attr} + + if isinstance(attr, ET.Element): + # Transform value into {"Key": "value"} + attr = {el.tag: el.text for el in attr} + return {k: self.deserialize_data(v, dict_type) for k, v in attr.items()} + + def deserialize_object(self, attr, **kwargs): # pylint: disable=too-many-return-statements + """Deserialize a generic object. + This will be handled as a dictionary. + + :param dict attr: Dictionary to be deserialized. + :return: Deserialized object. + :rtype: dict + :raises TypeError: if non-builtin datatype encountered. + """ + if attr is None: + return None + if isinstance(attr, ET.Element): + # Do no recurse on XML, just return the tree as-is + return attr + if isinstance(attr, str): + return self.deserialize_basic(attr, "str") + obj_type = type(attr) + if obj_type in self.basic_types: + return self.deserialize_basic(attr, self.basic_types[obj_type]) + if obj_type is _long_type: + return self.deserialize_long(attr) + + if obj_type == dict: + deserialized = {} + for key, value in attr.items(): + try: + deserialized[key] = self.deserialize_object(value, **kwargs) + except ValueError: + deserialized[key] = None + return deserialized + + if obj_type == list: + deserialized = [] + for obj in attr: + try: + deserialized.append(self.deserialize_object(obj, **kwargs)) + except ValueError: + pass + return deserialized + + error = "Cannot deserialize generic object with type: " + raise TypeError(error + str(obj_type)) + + def deserialize_basic(self, attr, data_type): # pylint: disable=too-many-return-statements + """Deserialize basic builtin data type from string. + Will attempt to convert to str, int, float and bool. + This function will also accept '1', '0', 'true' and 'false' as + valid bool values. + + :param str attr: response string to be deserialized. + :param str data_type: deserialization data type. + :return: Deserialized basic type. + :rtype: str, int, float or bool + :raises TypeError: if string format is not valid. + """ + # If we're here, data is supposed to be a basic type. + # If it's still an XML node, take the text + if isinstance(attr, ET.Element): + attr = attr.text + if not attr: + if data_type == "str": + # None or '', node is empty string. + return "" + # None or '', node with a strong type is None. + # Don't try to model "empty bool" or "empty int" + return None + + if data_type == "bool": + if attr in [True, False, 1, 0]: + return bool(attr) + if isinstance(attr, str): + if attr.lower() in ["true", "1"]: + return True + if attr.lower() in ["false", "0"]: + return False + raise TypeError("Invalid boolean value: {}".format(attr)) + + if data_type == "str": + return self.deserialize_unicode(attr) + return eval(data_type)(attr) # nosec # pylint: disable=eval-used + + @staticmethod + def deserialize_unicode(data): + """Preserve unicode objects in Python 2, otherwise return data + as a string. + + :param str data: response string to be deserialized. + :return: Deserialized string. + :rtype: str or unicode + """ + # We might be here because we have an enum modeled as string, + # and we try to deserialize a partial dict with enum inside + if isinstance(data, Enum): + return data + + # Consider this is real string + try: + if isinstance(data, unicode): # type: ignore + return data + except NameError: + return str(data) + return str(data) + + @staticmethod + def deserialize_enum(data, enum_obj): + """Deserialize string into enum object. + + If the string is not a valid enum value it will be returned as-is + and a warning will be logged. + + :param str data: Response string to be deserialized. If this value is + None or invalid it will be returned as-is. + :param Enum enum_obj: Enum object to deserialize to. + :return: Deserialized enum object. + :rtype: Enum + """ + if isinstance(data, enum_obj) or data is None: + return data + if isinstance(data, Enum): + data = data.value + if isinstance(data, int): + # Workaround. We might consider remove it in the future. + try: + return list(enum_obj.__members__.values())[data] + except IndexError as exc: + error = "{!r} is not a valid index for enum {!r}" + raise DeserializationError(error.format(data, enum_obj)) from exc + try: + return enum_obj(str(data)) + except ValueError: + for enum_value in enum_obj: + if enum_value.value.lower() == str(data).lower(): + return enum_value + # We don't fail anymore for unknown value, we deserialize as a string + _LOGGER.warning("Deserializer is not able to find %s as valid enum in %s", data, enum_obj) + return Deserializer.deserialize_unicode(data) + + @staticmethod + def deserialize_bytearray(attr): + """Deserialize string into bytearray. + + :param str attr: response string to be deserialized. + :return: Deserialized bytearray + :rtype: bytearray + :raises TypeError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + return bytearray(b64decode(attr)) # type: ignore + + @staticmethod + def deserialize_base64(attr): + """Deserialize base64 encoded string into string. + + :param str attr: response string to be deserialized. + :return: Deserialized base64 string + :rtype: bytearray + :raises TypeError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + padding = "=" * (3 - (len(attr) + 3) % 4) # type: ignore + attr = attr + padding # type: ignore + encoded = attr.replace("-", "+").replace("_", "/") + return b64decode(encoded) + + @staticmethod + def deserialize_decimal(attr): + """Deserialize string into Decimal object. + + :param str attr: response string to be deserialized. + :return: Deserialized decimal + :raises DeserializationError: if string format invalid. + :rtype: decimal + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + return decimal.Decimal(str(attr)) # type: ignore + except decimal.DecimalException as err: + msg = "Invalid decimal {}".format(attr) + raise DeserializationError(msg) from err + + @staticmethod + def deserialize_long(attr): + """Deserialize string into long (Py2) or int (Py3). + + :param str attr: response string to be deserialized. + :return: Deserialized int + :rtype: long or int + :raises ValueError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + return _long_type(attr) # type: ignore + + @staticmethod + def deserialize_duration(attr): + """Deserialize ISO-8601 formatted string into TimeDelta object. + + :param str attr: response string to be deserialized. + :return: Deserialized duration + :rtype: TimeDelta + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + duration = isodate.parse_duration(attr) + except (ValueError, OverflowError, AttributeError) as err: + msg = "Cannot deserialize duration object." + raise DeserializationError(msg) from err + return duration + + @staticmethod + def deserialize_date(attr): + """Deserialize ISO-8601 formatted string into Date object. + + :param str attr: response string to be deserialized. + :return: Deserialized date + :rtype: Date + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + if re.search(r"[^\W\d_]", attr, re.I + re.U): # type: ignore + raise DeserializationError("Date must have only digits and -. Received: %s" % attr) + # This must NOT use defaultmonth/defaultday. Using None ensure this raises an exception. + return isodate.parse_date(attr, defaultmonth=0, defaultday=0) + + @staticmethod + def deserialize_time(attr): + """Deserialize ISO-8601 formatted string into time object. + + :param str attr: response string to be deserialized. + :return: Deserialized time + :rtype: datetime.time + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + if re.search(r"[^\W\d_]", attr, re.I + re.U): # type: ignore + raise DeserializationError("Date must have only digits and -. Received: %s" % attr) + return isodate.parse_time(attr) + + @staticmethod + def deserialize_rfc(attr): + """Deserialize RFC-1123 formatted string into Datetime object. + + :param str attr: response string to be deserialized. + :return: Deserialized RFC datetime + :rtype: Datetime + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + parsed_date = email.utils.parsedate_tz(attr) # type: ignore + date_obj = datetime.datetime( + *parsed_date[:6], tzinfo=datetime.timezone(datetime.timedelta(minutes=(parsed_date[9] or 0) / 60)) + ) + if not date_obj.tzinfo: + date_obj = date_obj.astimezone(tz=TZ_UTC) + except ValueError as err: + msg = "Cannot deserialize to rfc datetime object." + raise DeserializationError(msg) from err + return date_obj + + @staticmethod + def deserialize_iso(attr): + """Deserialize ISO-8601 formatted string into Datetime object. + + :param str attr: response string to be deserialized. + :return: Deserialized ISO datetime + :rtype: Datetime + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + attr = attr.upper() # type: ignore + match = Deserializer.valid_date.match(attr) + if not match: + raise ValueError("Invalid datetime string: " + attr) + + check_decimal = attr.split(".") + if len(check_decimal) > 1: + decimal_str = "" + for digit in check_decimal[1]: + if digit.isdigit(): + decimal_str += digit + else: + break + if len(decimal_str) > 6: + attr = attr.replace(decimal_str, decimal_str[0:6]) + + date_obj = isodate.parse_datetime(attr) + test_utc = date_obj.utctimetuple() + if test_utc.tm_year > 9999 or test_utc.tm_year < 1: + raise OverflowError("Hit max or min date") + except (ValueError, OverflowError, AttributeError) as err: + msg = "Cannot deserialize datetime object." + raise DeserializationError(msg) from err + return date_obj + + @staticmethod + def deserialize_unix(attr): + """Serialize Datetime object into IntTime format. + This is represented as seconds. + + :param int attr: Object to be serialized. + :return: Deserialized datetime + :rtype: Datetime + :raises DeserializationError: if format invalid + """ + if isinstance(attr, ET.Element): + attr = int(attr.text) # type: ignore + try: + attr = int(attr) + date_obj = datetime.datetime.fromtimestamp(attr, TZ_UTC) + except ValueError as err: + msg = "Cannot deserialize to unix datetime object." + raise DeserializationError(msg) from err + return date_obj diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/CustomBaseUriMoreOptionsVersionTolerant/custombaseurlmoreoptionsversiontolerant/aio/_client.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/CustomBaseUriMoreOptionsVersionTolerant/custombaseurlmoreoptionsversiontolerant/aio/_client.py index 336c6817187..970ff247152 100644 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/CustomBaseUriMoreOptionsVersionTolerant/custombaseurlmoreoptionsversiontolerant/aio/_client.py +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/CustomBaseUriMoreOptionsVersionTolerant/custombaseurlmoreoptionsversiontolerant/aio/_client.py @@ -14,7 +14,7 @@ from azure.core.pipeline import policies from azure.core.rest import AsyncHttpResponse, HttpRequest -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import AutoRestParameterizedCustomHostTestClientConfiguration from .operations import PathsOperations diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/CustomBaseUriMoreOptionsVersionTolerant/custombaseurlmoreoptionsversiontolerant/aio/operations/_operations.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/CustomBaseUriMoreOptionsVersionTolerant/custombaseurlmoreoptionsversiontolerant/aio/operations/_operations.py index 41b57cffcce..835e0bc3b57 100644 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/CustomBaseUriMoreOptionsVersionTolerant/custombaseurlmoreoptionsversiontolerant/aio/operations/_operations.py +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/CustomBaseUriMoreOptionsVersionTolerant/custombaseurlmoreoptionsversiontolerant/aio/operations/_operations.py @@ -21,7 +21,7 @@ from azure.core.rest import AsyncHttpResponse, HttpRequest from azure.core.tracing.decorator_async import distributed_trace_async -from ..._serialization import Deserializer, Serializer +from ..._utils.serialization import Deserializer, Serializer from ...operations._operations import build_paths_get_empty_request from .._configuration import AutoRestParameterizedCustomHostTestClientConfiguration diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/CustomBaseUriMoreOptionsVersionTolerant/custombaseurlmoreoptionsversiontolerant/operations/_operations.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/CustomBaseUriMoreOptionsVersionTolerant/custombaseurlmoreoptionsversiontolerant/operations/_operations.py index 82793f83ed9..ccab0d27ebf 100644 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/CustomBaseUriMoreOptionsVersionTolerant/custombaseurlmoreoptionsversiontolerant/operations/_operations.py +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/CustomBaseUriMoreOptionsVersionTolerant/custombaseurlmoreoptionsversiontolerant/operations/_operations.py @@ -23,7 +23,7 @@ from azure.core.utils import case_insensitive_dict from .._configuration import AutoRestParameterizedCustomHostTestClientConfiguration -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/CustomBaseUriVersionTolerant/custombaseurlversiontolerant/_client.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/CustomBaseUriVersionTolerant/custombaseurlversiontolerant/_client.py index 2e2922eb871..ef2e3db6534 100644 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/CustomBaseUriVersionTolerant/custombaseurlversiontolerant/_client.py +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/CustomBaseUriVersionTolerant/custombaseurlversiontolerant/_client.py @@ -15,7 +15,7 @@ from azure.core.rest import HttpRequest, HttpResponse from ._configuration import AutoRestParameterizedHostTestClientConfiguration -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer from .operations import PathsOperations diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/CustomBaseUriVersionTolerant/custombaseurlversiontolerant/_utils/__init__.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/CustomBaseUriVersionTolerant/custombaseurlversiontolerant/_utils/__init__.py new file mode 100644 index 00000000000..0af9b28f660 --- /dev/null +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/CustomBaseUriVersionTolerant/custombaseurlversiontolerant/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/CustomBaseUriVersionTolerant/custombaseurlversiontolerant/_utils/serialization.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/CustomBaseUriVersionTolerant/custombaseurlversiontolerant/_utils/serialization.py new file mode 100644 index 00000000000..f5187701d7b --- /dev/null +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/CustomBaseUriVersionTolerant/custombaseurlversiontolerant/_utils/serialization.py @@ -0,0 +1,2032 @@ +# pylint: disable=line-too-long,useless-suppression,too-many-lines +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +# pyright: reportUnnecessaryTypeIgnoreComment=false + +from base64 import b64decode, b64encode +import calendar +import datetime +import decimal +import email +from enum import Enum +import json +import logging +import re +import sys +import codecs +from typing import ( + Dict, + Any, + cast, + Optional, + Union, + AnyStr, + IO, + Mapping, + Callable, + MutableMapping, + List, +) + +try: + from urllib import quote # type: ignore +except ImportError: + from urllib.parse import quote +import xml.etree.ElementTree as ET + +import isodate # type: ignore +from typing_extensions import Self + +from azure.core.exceptions import DeserializationError, SerializationError +from azure.core.serialization import NULL as CoreNull + +_BOM = codecs.BOM_UTF8.decode(encoding="utf-8") + +JSON = MutableMapping[str, Any] + + +class RawDeserializer: + + # Accept "text" because we're open minded people... + JSON_REGEXP = re.compile(r"^(application|text)/([a-z+.]+\+)?json$") + + # Name used in context + CONTEXT_NAME = "deserialized_data" + + @classmethod + def deserialize_from_text(cls, data: Optional[Union[AnyStr, IO]], content_type: Optional[str] = None) -> Any: + """Decode data according to content-type. + + Accept a stream of data as well, but will be load at once in memory for now. + + If no content-type, will return the string version (not bytes, not stream) + + :param data: Input, could be bytes or stream (will be decoded with UTF8) or text + :type data: str or bytes or IO + :param str content_type: The content type. + :return: The deserialized data. + :rtype: object + """ + if hasattr(data, "read"): + # Assume a stream + data = cast(IO, data).read() + + if isinstance(data, bytes): + data_as_str = data.decode(encoding="utf-8-sig") + else: + # Explain to mypy the correct type. + data_as_str = cast(str, data) + + # Remove Byte Order Mark if present in string + data_as_str = data_as_str.lstrip(_BOM) + + if content_type is None: + return data + + if cls.JSON_REGEXP.match(content_type): + try: + return json.loads(data_as_str) + except ValueError as err: + raise DeserializationError("JSON is invalid: {}".format(err), err) from err + elif "xml" in (content_type or []): + try: + + try: + if isinstance(data, unicode): # type: ignore + # If I'm Python 2.7 and unicode XML will scream if I try a "fromstring" on unicode string + data_as_str = data_as_str.encode(encoding="utf-8") # type: ignore + except NameError: + pass + + return ET.fromstring(data_as_str) # nosec + except ET.ParseError as err: + # It might be because the server has an issue, and returned JSON with + # content-type XML.... + # So let's try a JSON load, and if it's still broken + # let's flow the initial exception + def _json_attemp(data): + try: + return True, json.loads(data) + except ValueError: + return False, None # Don't care about this one + + success, json_result = _json_attemp(data) + if success: + return json_result + # If i'm here, it's not JSON, it's not XML, let's scream + # and raise the last context in this block (the XML exception) + # The function hack is because Py2.7 messes up with exception + # context otherwise. + _LOGGER.critical("Wasn't XML not JSON, failing") + raise DeserializationError("XML is invalid") from err + elif content_type.startswith("text/"): + return data_as_str + raise DeserializationError("Cannot deserialize content-type: {}".format(content_type)) + + @classmethod + def deserialize_from_http_generics(cls, body_bytes: Optional[Union[AnyStr, IO]], headers: Mapping) -> Any: + """Deserialize from HTTP response. + + Use bytes and headers to NOT use any requests/aiohttp or whatever + specific implementation. + Headers will tested for "content-type" + + :param bytes body_bytes: The body of the response. + :param dict headers: The headers of the response. + :returns: The deserialized data. + :rtype: object + """ + # Try to use content-type from headers if available + content_type = None + if "content-type" in headers: + content_type = headers["content-type"].split(";")[0].strip().lower() + # Ouch, this server did not declare what it sent... + # Let's guess it's JSON... + # Also, since Autorest was considering that an empty body was a valid JSON, + # need that test as well.... + else: + content_type = "application/json" + + if body_bytes: + return cls.deserialize_from_text(body_bytes, content_type) + return None + + +_LOGGER = logging.getLogger(__name__) + +try: + _long_type = long # type: ignore +except NameError: + _long_type = int + +TZ_UTC = datetime.timezone.utc + +_FLATTEN = re.compile(r"(? None: + self.additional_properties: Optional[Dict[str, Any]] = {} + for k in kwargs: # pylint: disable=consider-using-dict-items + if k not in self._attribute_map: + _LOGGER.warning("%s is not a known attribute of class %s and will be ignored", k, self.__class__) + elif k in self._validation and self._validation[k].get("readonly", False): + _LOGGER.warning("Readonly attribute %s will be ignored in class %s", k, self.__class__) + else: + setattr(self, k, kwargs[k]) + + def __eq__(self, other: Any) -> bool: + """Compare objects by comparing all attributes. + + :param object other: The object to compare + :returns: True if objects are equal + :rtype: bool + """ + if isinstance(other, self.__class__): + return self.__dict__ == other.__dict__ + return False + + def __ne__(self, other: Any) -> bool: + """Compare objects by comparing all attributes. + + :param object other: The object to compare + :returns: True if objects are not equal + :rtype: bool + """ + return not self.__eq__(other) + + def __str__(self) -> str: + return str(self.__dict__) + + @classmethod + def enable_additional_properties_sending(cls) -> None: + cls._attribute_map["additional_properties"] = {"key": "", "type": "{object}"} + + @classmethod + def is_xml_model(cls) -> bool: + try: + cls._xml_map # type: ignore + except AttributeError: + return False + return True + + @classmethod + def _create_xml_node(cls): + """Create XML node. + + :returns: The XML node + :rtype: xml.etree.ElementTree.Element + """ + try: + xml_map = cls._xml_map # type: ignore + except AttributeError: + xml_map = {} + + return _create_xml_node(xml_map.get("name", cls.__name__), xml_map.get("prefix", None), xml_map.get("ns", None)) + + def serialize(self, keep_readonly: bool = False, **kwargs: Any) -> JSON: + """Return the JSON that would be sent to server from this model. + + This is an alias to `as_dict(full_restapi_key_transformer, keep_readonly=False)`. + + If you want XML serialization, you can pass the kwargs is_xml=True. + + :param bool keep_readonly: If you want to serialize the readonly attributes + :returns: A dict JSON compatible object + :rtype: dict + """ + serializer = Serializer(self._infer_class_models()) + return serializer._serialize( # type: ignore # pylint: disable=protected-access + self, keep_readonly=keep_readonly, **kwargs + ) + + def as_dict( + self, + keep_readonly: bool = True, + key_transformer: Callable[[str, Dict[str, Any], Any], Any] = attribute_transformer, + **kwargs: Any + ) -> JSON: + """Return a dict that can be serialized using json.dump. + + Advanced usage might optionally use a callback as parameter: + + .. code::python + + def my_key_transformer(key, attr_desc, value): + return key + + Key is the attribute name used in Python. Attr_desc + is a dict of metadata. Currently contains 'type' with the + msrest type and 'key' with the RestAPI encoded key. + Value is the current value in this object. + + The string returned will be used to serialize the key. + If the return type is a list, this is considered hierarchical + result dict. + + See the three examples in this file: + + - attribute_transformer + - full_restapi_key_transformer + - last_restapi_key_transformer + + If you want XML serialization, you can pass the kwargs is_xml=True. + + :param bool keep_readonly: If you want to serialize the readonly attributes + :param function key_transformer: A key transformer function. + :returns: A dict JSON compatible object + :rtype: dict + """ + serializer = Serializer(self._infer_class_models()) + return serializer._serialize( # type: ignore # pylint: disable=protected-access + self, key_transformer=key_transformer, keep_readonly=keep_readonly, **kwargs + ) + + @classmethod + def _infer_class_models(cls): + try: + str_models = cls.__module__.rsplit(".", 1)[0] + models = sys.modules[str_models] + client_models = {k: v for k, v in models.__dict__.items() if isinstance(v, type)} + if cls.__name__ not in client_models: + raise ValueError("Not Autorest generated code") + except Exception: # pylint: disable=broad-exception-caught + # Assume it's not Autorest generated (tests?). Add ourselves as dependencies. + client_models = {cls.__name__: cls} + return client_models + + @classmethod + def deserialize(cls, data: Any, content_type: Optional[str] = None) -> Self: + """Parse a str using the RestAPI syntax and return a model. + + :param str data: A str using RestAPI structure. JSON by default. + :param str content_type: JSON by default, set application/xml if XML. + :returns: An instance of this model + :raises DeserializationError: if something went wrong + :rtype: Self + """ + deserializer = Deserializer(cls._infer_class_models()) + return deserializer(cls.__name__, data, content_type=content_type) # type: ignore + + @classmethod + def from_dict( + cls, + data: Any, + key_extractors: Optional[Callable[[str, Dict[str, Any], Any], Any]] = None, + content_type: Optional[str] = None, + ) -> Self: + """Parse a dict using given key extractor return a model. + + By default consider key + extractors (rest_key_case_insensitive_extractor, attribute_key_case_insensitive_extractor + and last_rest_key_case_insensitive_extractor) + + :param dict data: A dict using RestAPI structure + :param function key_extractors: A key extractor function. + :param str content_type: JSON by default, set application/xml if XML. + :returns: An instance of this model + :raises DeserializationError: if something went wrong + :rtype: Self + """ + deserializer = Deserializer(cls._infer_class_models()) + deserializer.key_extractors = ( # type: ignore + [ # type: ignore + attribute_key_case_insensitive_extractor, + rest_key_case_insensitive_extractor, + last_rest_key_case_insensitive_extractor, + ] + if key_extractors is None + else key_extractors + ) + return deserializer(cls.__name__, data, content_type=content_type) # type: ignore + + @classmethod + def _flatten_subtype(cls, key, objects): + if "_subtype_map" not in cls.__dict__: + return {} + result = dict(cls._subtype_map[key]) + for valuetype in cls._subtype_map[key].values(): + result.update(objects[valuetype]._flatten_subtype(key, objects)) # pylint: disable=protected-access + return result + + @classmethod + def _classify(cls, response, objects): + """Check the class _subtype_map for any child classes. + We want to ignore any inherited _subtype_maps. + + :param dict response: The initial data + :param dict objects: The class objects + :returns: The class to be used + :rtype: class + """ + for subtype_key in cls.__dict__.get("_subtype_map", {}).keys(): + subtype_value = None + + if not isinstance(response, ET.Element): + rest_api_response_key = cls._get_rest_key_parts(subtype_key)[-1] + subtype_value = response.get(rest_api_response_key, None) or response.get(subtype_key, None) + else: + subtype_value = xml_key_extractor(subtype_key, cls._attribute_map[subtype_key], response) + if subtype_value: + # Try to match base class. Can be class name only + # (bug to fix in Autorest to support x-ms-discriminator-name) + if cls.__name__ == subtype_value: + return cls + flatten_mapping_type = cls._flatten_subtype(subtype_key, objects) + try: + return objects[flatten_mapping_type[subtype_value]] # type: ignore + except KeyError: + _LOGGER.warning( + "Subtype value %s has no mapping, use base class %s.", + subtype_value, + cls.__name__, + ) + break + else: + _LOGGER.warning("Discriminator %s is absent or null, use base class %s.", subtype_key, cls.__name__) + break + return cls + + @classmethod + def _get_rest_key_parts(cls, attr_key): + """Get the RestAPI key of this attr, split it and decode part + :param str attr_key: Attribute key must be in attribute_map. + :returns: A list of RestAPI part + :rtype: list + """ + rest_split_key = _FLATTEN.split(cls._attribute_map[attr_key]["key"]) + return [_decode_attribute_map_key(key_part) for key_part in rest_split_key] + + +def _decode_attribute_map_key(key): + """This decode a key in an _attribute_map to the actual key we want to look at + inside the received data. + + :param str key: A key string from the generated code + :returns: The decoded key + :rtype: str + """ + return key.replace("\\.", ".") + + +class Serializer: # pylint: disable=too-many-public-methods + """Request object model serializer.""" + + basic_types = {str: "str", int: "int", bool: "bool", float: "float"} + + _xml_basic_types_serializers = {"bool": lambda x: str(x).lower()} + days = {0: "Mon", 1: "Tue", 2: "Wed", 3: "Thu", 4: "Fri", 5: "Sat", 6: "Sun"} + months = { + 1: "Jan", + 2: "Feb", + 3: "Mar", + 4: "Apr", + 5: "May", + 6: "Jun", + 7: "Jul", + 8: "Aug", + 9: "Sep", + 10: "Oct", + 11: "Nov", + 12: "Dec", + } + validation = { + "min_length": lambda x, y: len(x) < y, + "max_length": lambda x, y: len(x) > y, + "minimum": lambda x, y: x < y, + "maximum": lambda x, y: x > y, + "minimum_ex": lambda x, y: x <= y, + "maximum_ex": lambda x, y: x >= y, + "min_items": lambda x, y: len(x) < y, + "max_items": lambda x, y: len(x) > y, + "pattern": lambda x, y: not re.match(y, x, re.UNICODE), + "unique": lambda x, y: len(x) != len(set(x)), + "multiple": lambda x, y: x % y != 0, + } + + def __init__(self, classes: Optional[Mapping[str, type]] = None) -> None: + self.serialize_type = { + "iso-8601": Serializer.serialize_iso, + "rfc-1123": Serializer.serialize_rfc, + "unix-time": Serializer.serialize_unix, + "duration": Serializer.serialize_duration, + "date": Serializer.serialize_date, + "time": Serializer.serialize_time, + "decimal": Serializer.serialize_decimal, + "long": Serializer.serialize_long, + "bytearray": Serializer.serialize_bytearray, + "base64": Serializer.serialize_base64, + "object": self.serialize_object, + "[]": self.serialize_iter, + "{}": self.serialize_dict, + } + self.dependencies: Dict[str, type] = dict(classes) if classes else {} + self.key_transformer = full_restapi_key_transformer + self.client_side_validation = True + + def _serialize( # pylint: disable=too-many-nested-blocks, too-many-branches, too-many-statements, too-many-locals + self, target_obj, data_type=None, **kwargs + ): + """Serialize data into a string according to type. + + :param object target_obj: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str, dict + :raises SerializationError: if serialization fails. + :returns: The serialized data. + """ + key_transformer = kwargs.get("key_transformer", self.key_transformer) + keep_readonly = kwargs.get("keep_readonly", False) + if target_obj is None: + return None + + attr_name = None + class_name = target_obj.__class__.__name__ + + if data_type: + return self.serialize_data(target_obj, data_type, **kwargs) + + if not hasattr(target_obj, "_attribute_map"): + data_type = type(target_obj).__name__ + if data_type in self.basic_types.values(): + return self.serialize_data(target_obj, data_type, **kwargs) + + # Force "is_xml" kwargs if we detect a XML model + try: + is_xml_model_serialization = kwargs["is_xml"] + except KeyError: + is_xml_model_serialization = kwargs.setdefault("is_xml", target_obj.is_xml_model()) + + serialized = {} + if is_xml_model_serialization: + serialized = target_obj._create_xml_node() # pylint: disable=protected-access + try: + attributes = target_obj._attribute_map # pylint: disable=protected-access + for attr, attr_desc in attributes.items(): + attr_name = attr + if not keep_readonly and target_obj._validation.get( # pylint: disable=protected-access + attr_name, {} + ).get("readonly", False): + continue + + if attr_name == "additional_properties" and attr_desc["key"] == "": + if target_obj.additional_properties is not None: + serialized.update(target_obj.additional_properties) + continue + try: + + orig_attr = getattr(target_obj, attr) + if is_xml_model_serialization: + pass # Don't provide "transformer" for XML for now. Keep "orig_attr" + else: # JSON + keys, orig_attr = key_transformer(attr, attr_desc.copy(), orig_attr) + keys = keys if isinstance(keys, list) else [keys] + + kwargs["serialization_ctxt"] = attr_desc + new_attr = self.serialize_data(orig_attr, attr_desc["type"], **kwargs) + + if is_xml_model_serialization: + xml_desc = attr_desc.get("xml", {}) + xml_name = xml_desc.get("name", attr_desc["key"]) + xml_prefix = xml_desc.get("prefix", None) + xml_ns = xml_desc.get("ns", None) + if xml_desc.get("attr", False): + if xml_ns: + ET.register_namespace(xml_prefix, xml_ns) + xml_name = "{{{}}}{}".format(xml_ns, xml_name) + serialized.set(xml_name, new_attr) # type: ignore + continue + if xml_desc.get("text", False): + serialized.text = new_attr # type: ignore + continue + if isinstance(new_attr, list): + serialized.extend(new_attr) # type: ignore + elif isinstance(new_attr, ET.Element): + # If the down XML has no XML/Name, + # we MUST replace the tag with the local tag. But keeping the namespaces. + if "name" not in getattr(orig_attr, "_xml_map", {}): + splitted_tag = new_attr.tag.split("}") + if len(splitted_tag) == 2: # Namespace + new_attr.tag = "}".join([splitted_tag[0], xml_name]) + else: + new_attr.tag = xml_name + serialized.append(new_attr) # type: ignore + else: # That's a basic type + # Integrate namespace if necessary + local_node = _create_xml_node(xml_name, xml_prefix, xml_ns) + local_node.text = str(new_attr) + serialized.append(local_node) # type: ignore + else: # JSON + for k in reversed(keys): # type: ignore + new_attr = {k: new_attr} + + _new_attr = new_attr + _serialized = serialized + for k in keys: # type: ignore + if k not in _serialized: + _serialized.update(_new_attr) # type: ignore + _new_attr = _new_attr[k] # type: ignore + _serialized = _serialized[k] + except ValueError as err: + if isinstance(err, SerializationError): + raise + + except (AttributeError, KeyError, TypeError) as err: + msg = "Attribute {} in object {} cannot be serialized.\n{}".format(attr_name, class_name, str(target_obj)) + raise SerializationError(msg) from err + return serialized + + def body(self, data, data_type, **kwargs): + """Serialize data intended for a request body. + + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: dict + :raises SerializationError: if serialization fails. + :raises ValueError: if data is None + :returns: The serialized request body + """ + + # Just in case this is a dict + internal_data_type_str = data_type.strip("[]{}") + internal_data_type = self.dependencies.get(internal_data_type_str, None) + try: + is_xml_model_serialization = kwargs["is_xml"] + except KeyError: + if internal_data_type and issubclass(internal_data_type, Model): + is_xml_model_serialization = kwargs.setdefault("is_xml", internal_data_type.is_xml_model()) + else: + is_xml_model_serialization = False + if internal_data_type and not isinstance(internal_data_type, Enum): + try: + deserializer = Deserializer(self.dependencies) + # Since it's on serialization, it's almost sure that format is not JSON REST + # We're not able to deal with additional properties for now. + deserializer.additional_properties_detection = False + if is_xml_model_serialization: + deserializer.key_extractors = [ # type: ignore + attribute_key_case_insensitive_extractor, + ] + else: + deserializer.key_extractors = [ + rest_key_case_insensitive_extractor, + attribute_key_case_insensitive_extractor, + last_rest_key_case_insensitive_extractor, + ] + data = deserializer._deserialize(data_type, data) # pylint: disable=protected-access + except DeserializationError as err: + raise SerializationError("Unable to build a model: " + str(err)) from err + + return self._serialize(data, data_type, **kwargs) + + def url(self, name, data, data_type, **kwargs): + """Serialize data intended for a URL path. + + :param str name: The name of the URL path parameter. + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str + :returns: The serialized URL path + :raises TypeError: if serialization fails. + :raises ValueError: if data is None + """ + try: + output = self.serialize_data(data, data_type, **kwargs) + if data_type == "bool": + output = json.dumps(output) + + if kwargs.get("skip_quote") is True: + output = str(output) + output = output.replace("{", quote("{")).replace("}", quote("}")) + else: + output = quote(str(output), safe="") + except SerializationError as exc: + raise TypeError("{} must be type {}.".format(name, data_type)) from exc + return output + + def query(self, name, data, data_type, **kwargs): + """Serialize data intended for a URL query. + + :param str name: The name of the query parameter. + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str, list + :raises TypeError: if serialization fails. + :raises ValueError: if data is None + :returns: The serialized query parameter + """ + try: + # Treat the list aside, since we don't want to encode the div separator + if data_type.startswith("["): + internal_data_type = data_type[1:-1] + do_quote = not kwargs.get("skip_quote", False) + return self.serialize_iter(data, internal_data_type, do_quote=do_quote, **kwargs) + + # Not a list, regular serialization + output = self.serialize_data(data, data_type, **kwargs) + if data_type == "bool": + output = json.dumps(output) + if kwargs.get("skip_quote") is True: + output = str(output) + else: + output = quote(str(output), safe="") + except SerializationError as exc: + raise TypeError("{} must be type {}.".format(name, data_type)) from exc + return str(output) + + def header(self, name, data, data_type, **kwargs): + """Serialize data intended for a request header. + + :param str name: The name of the header. + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str + :raises TypeError: if serialization fails. + :raises ValueError: if data is None + :returns: The serialized header + """ + try: + if data_type in ["[str]"]: + data = ["" if d is None else d for d in data] + + output = self.serialize_data(data, data_type, **kwargs) + if data_type == "bool": + output = json.dumps(output) + except SerializationError as exc: + raise TypeError("{} must be type {}.".format(name, data_type)) from exc + return str(output) + + def serialize_data(self, data, data_type, **kwargs): + """Serialize generic data according to supplied data type. + + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :raises AttributeError: if required data is None. + :raises ValueError: if data is None + :raises SerializationError: if serialization fails. + :returns: The serialized data. + :rtype: str, int, float, bool, dict, list + """ + if data is None: + raise ValueError("No value for given attribute") + + try: + if data is CoreNull: + return None + if data_type in self.basic_types.values(): + return self.serialize_basic(data, data_type, **kwargs) + + if data_type in self.serialize_type: + return self.serialize_type[data_type](data, **kwargs) + + # If dependencies is empty, try with current data class + # It has to be a subclass of Enum anyway + enum_type = self.dependencies.get(data_type, data.__class__) + if issubclass(enum_type, Enum): + return Serializer.serialize_enum(data, enum_obj=enum_type) + + iter_type = data_type[0] + data_type[-1] + if iter_type in self.serialize_type: + return self.serialize_type[iter_type](data, data_type[1:-1], **kwargs) + + except (ValueError, TypeError) as err: + msg = "Unable to serialize value: {!r} as type: {!r}." + raise SerializationError(msg.format(data, data_type)) from err + return self._serialize(data, **kwargs) + + @classmethod + def _get_custom_serializers(cls, data_type, **kwargs): # pylint: disable=inconsistent-return-statements + custom_serializer = kwargs.get("basic_types_serializers", {}).get(data_type) + if custom_serializer: + return custom_serializer + if kwargs.get("is_xml", False): + return cls._xml_basic_types_serializers.get(data_type) + + @classmethod + def serialize_basic(cls, data, data_type, **kwargs): + """Serialize basic builting data type. + Serializes objects to str, int, float or bool. + + Possible kwargs: + - basic_types_serializers dict[str, callable] : If set, use the callable as serializer + - is_xml bool : If set, use xml_basic_types_serializers + + :param obj data: Object to be serialized. + :param str data_type: Type of object in the iterable. + :rtype: str, int, float, bool + :return: serialized object + """ + custom_serializer = cls._get_custom_serializers(data_type, **kwargs) + if custom_serializer: + return custom_serializer(data) + if data_type == "str": + return cls.serialize_unicode(data) + return eval(data_type)(data) # nosec # pylint: disable=eval-used + + @classmethod + def serialize_unicode(cls, data): + """Special handling for serializing unicode strings in Py2. + Encode to UTF-8 if unicode, otherwise handle as a str. + + :param str data: Object to be serialized. + :rtype: str + :return: serialized object + """ + try: # If I received an enum, return its value + return data.value + except AttributeError: + pass + + try: + if isinstance(data, unicode): # type: ignore + # Don't change it, JSON and XML ElementTree are totally able + # to serialize correctly u'' strings + return data + except NameError: + return str(data) + return str(data) + + def serialize_iter(self, data, iter_type, div=None, **kwargs): + """Serialize iterable. + + Supported kwargs: + - serialization_ctxt dict : The current entry of _attribute_map, or same format. + serialization_ctxt['type'] should be same as data_type. + - is_xml bool : If set, serialize as XML + + :param list data: Object to be serialized. + :param str iter_type: Type of object in the iterable. + :param str div: If set, this str will be used to combine the elements + in the iterable into a combined string. Default is 'None'. + Defaults to False. + :rtype: list, str + :return: serialized iterable + """ + if isinstance(data, str): + raise SerializationError("Refuse str type as a valid iter type.") + + serialization_ctxt = kwargs.get("serialization_ctxt", {}) + is_xml = kwargs.get("is_xml", False) + + serialized = [] + for d in data: + try: + serialized.append(self.serialize_data(d, iter_type, **kwargs)) + except ValueError as err: + if isinstance(err, SerializationError): + raise + serialized.append(None) + + if kwargs.get("do_quote", False): + serialized = ["" if s is None else quote(str(s), safe="") for s in serialized] + + if div: + serialized = ["" if s is None else str(s) for s in serialized] + serialized = div.join(serialized) + + if "xml" in serialization_ctxt or is_xml: + # XML serialization is more complicated + xml_desc = serialization_ctxt.get("xml", {}) + xml_name = xml_desc.get("name") + if not xml_name: + xml_name = serialization_ctxt["key"] + + # Create a wrap node if necessary (use the fact that Element and list have "append") + is_wrapped = xml_desc.get("wrapped", False) + node_name = xml_desc.get("itemsName", xml_name) + if is_wrapped: + final_result = _create_xml_node(xml_name, xml_desc.get("prefix", None), xml_desc.get("ns", None)) + else: + final_result = [] + # All list elements to "local_node" + for el in serialized: + if isinstance(el, ET.Element): + el_node = el + else: + el_node = _create_xml_node(node_name, xml_desc.get("prefix", None), xml_desc.get("ns", None)) + if el is not None: # Otherwise it writes "None" :-p + el_node.text = str(el) + final_result.append(el_node) + return final_result + return serialized + + def serialize_dict(self, attr, dict_type, **kwargs): + """Serialize a dictionary of objects. + + :param dict attr: Object to be serialized. + :param str dict_type: Type of object in the dictionary. + :rtype: dict + :return: serialized dictionary + """ + serialization_ctxt = kwargs.get("serialization_ctxt", {}) + serialized = {} + for key, value in attr.items(): + try: + serialized[self.serialize_unicode(key)] = self.serialize_data(value, dict_type, **kwargs) + except ValueError as err: + if isinstance(err, SerializationError): + raise + serialized[self.serialize_unicode(key)] = None + + if "xml" in serialization_ctxt: + # XML serialization is more complicated + xml_desc = serialization_ctxt["xml"] + xml_name = xml_desc["name"] + + final_result = _create_xml_node(xml_name, xml_desc.get("prefix", None), xml_desc.get("ns", None)) + for key, value in serialized.items(): + ET.SubElement(final_result, key).text = value + return final_result + + return serialized + + def serialize_object(self, attr, **kwargs): # pylint: disable=too-many-return-statements + """Serialize a generic object. + This will be handled as a dictionary. If object passed in is not + a basic type (str, int, float, dict, list) it will simply be + cast to str. + + :param dict attr: Object to be serialized. + :rtype: dict or str + :return: serialized object + """ + if attr is None: + return None + if isinstance(attr, ET.Element): + return attr + obj_type = type(attr) + if obj_type in self.basic_types: + return self.serialize_basic(attr, self.basic_types[obj_type], **kwargs) + if obj_type is _long_type: + return self.serialize_long(attr) + if obj_type is str: + return self.serialize_unicode(attr) + if obj_type is datetime.datetime: + return self.serialize_iso(attr) + if obj_type is datetime.date: + return self.serialize_date(attr) + if obj_type is datetime.time: + return self.serialize_time(attr) + if obj_type is datetime.timedelta: + return self.serialize_duration(attr) + if obj_type is decimal.Decimal: + return self.serialize_decimal(attr) + + # If it's a model or I know this dependency, serialize as a Model + if obj_type in self.dependencies.values() or isinstance(attr, Model): + return self._serialize(attr) + + if obj_type == dict: + serialized = {} + for key, value in attr.items(): + try: + serialized[self.serialize_unicode(key)] = self.serialize_object(value, **kwargs) + except ValueError: + serialized[self.serialize_unicode(key)] = None + return serialized + + if obj_type == list: + serialized = [] + for obj in attr: + try: + serialized.append(self.serialize_object(obj, **kwargs)) + except ValueError: + pass + return serialized + return str(attr) + + @staticmethod + def serialize_enum(attr, enum_obj=None): + try: + result = attr.value + except AttributeError: + result = attr + try: + enum_obj(result) # type: ignore + return result + except ValueError as exc: + for enum_value in enum_obj: # type: ignore + if enum_value.value.lower() == str(attr).lower(): + return enum_value.value + error = "{!r} is not valid value for enum {!r}" + raise SerializationError(error.format(attr, enum_obj)) from exc + + @staticmethod + def serialize_bytearray(attr, **kwargs): # pylint: disable=unused-argument + """Serialize bytearray into base-64 string. + + :param str attr: Object to be serialized. + :rtype: str + :return: serialized base64 + """ + return b64encode(attr).decode() + + @staticmethod + def serialize_base64(attr, **kwargs): # pylint: disable=unused-argument + """Serialize str into base-64 string. + + :param str attr: Object to be serialized. + :rtype: str + :return: serialized base64 + """ + encoded = b64encode(attr).decode("ascii") + return encoded.strip("=").replace("+", "-").replace("/", "_") + + @staticmethod + def serialize_decimal(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Decimal object to float. + + :param decimal attr: Object to be serialized. + :rtype: float + :return: serialized decimal + """ + return float(attr) + + @staticmethod + def serialize_long(attr, **kwargs): # pylint: disable=unused-argument + """Serialize long (Py2) or int (Py3). + + :param int attr: Object to be serialized. + :rtype: int/long + :return: serialized long + """ + return _long_type(attr) + + @staticmethod + def serialize_date(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Date object into ISO-8601 formatted string. + + :param Date attr: Object to be serialized. + :rtype: str + :return: serialized date + """ + if isinstance(attr, str): + attr = isodate.parse_date(attr) + t = "{:04}-{:02}-{:02}".format(attr.year, attr.month, attr.day) + return t + + @staticmethod + def serialize_time(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Time object into ISO-8601 formatted string. + + :param datetime.time attr: Object to be serialized. + :rtype: str + :return: serialized time + """ + if isinstance(attr, str): + attr = isodate.parse_time(attr) + t = "{:02}:{:02}:{:02}".format(attr.hour, attr.minute, attr.second) + if attr.microsecond: + t += ".{:02}".format(attr.microsecond) + return t + + @staticmethod + def serialize_duration(attr, **kwargs): # pylint: disable=unused-argument + """Serialize TimeDelta object into ISO-8601 formatted string. + + :param TimeDelta attr: Object to be serialized. + :rtype: str + :return: serialized duration + """ + if isinstance(attr, str): + attr = isodate.parse_duration(attr) + return isodate.duration_isoformat(attr) + + @staticmethod + def serialize_rfc(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Datetime object into RFC-1123 formatted string. + + :param Datetime attr: Object to be serialized. + :rtype: str + :raises TypeError: if format invalid. + :return: serialized rfc + """ + try: + if not attr.tzinfo: + _LOGGER.warning("Datetime with no tzinfo will be considered UTC.") + utc = attr.utctimetuple() + except AttributeError as exc: + raise TypeError("RFC1123 object must be valid Datetime object.") from exc + + return "{}, {:02} {} {:04} {:02}:{:02}:{:02} GMT".format( + Serializer.days[utc.tm_wday], + utc.tm_mday, + Serializer.months[utc.tm_mon], + utc.tm_year, + utc.tm_hour, + utc.tm_min, + utc.tm_sec, + ) + + @staticmethod + def serialize_iso(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Datetime object into ISO-8601 formatted string. + + :param Datetime attr: Object to be serialized. + :rtype: str + :raises SerializationError: if format invalid. + :return: serialized iso + """ + if isinstance(attr, str): + attr = isodate.parse_datetime(attr) + try: + if not attr.tzinfo: + _LOGGER.warning("Datetime with no tzinfo will be considered UTC.") + utc = attr.utctimetuple() + if utc.tm_year > 9999 or utc.tm_year < 1: + raise OverflowError("Hit max or min date") + + microseconds = str(attr.microsecond).rjust(6, "0").rstrip("0").ljust(3, "0") + if microseconds: + microseconds = "." + microseconds + date = "{:04}-{:02}-{:02}T{:02}:{:02}:{:02}".format( + utc.tm_year, utc.tm_mon, utc.tm_mday, utc.tm_hour, utc.tm_min, utc.tm_sec + ) + return date + microseconds + "Z" + except (ValueError, OverflowError) as err: + msg = "Unable to serialize datetime object." + raise SerializationError(msg) from err + except AttributeError as err: + msg = "ISO-8601 object must be valid Datetime object." + raise TypeError(msg) from err + + @staticmethod + def serialize_unix(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Datetime object into IntTime format. + This is represented as seconds. + + :param Datetime attr: Object to be serialized. + :rtype: int + :raises SerializationError: if format invalid + :return: serialied unix + """ + if isinstance(attr, int): + return attr + try: + if not attr.tzinfo: + _LOGGER.warning("Datetime with no tzinfo will be considered UTC.") + return int(calendar.timegm(attr.utctimetuple())) + except AttributeError as exc: + raise TypeError("Unix time object must be valid Datetime object.") from exc + + +def rest_key_extractor(attr, attr_desc, data): # pylint: disable=unused-argument + key = attr_desc["key"] + working_data = data + + while "." in key: + # Need the cast, as for some reasons "split" is typed as list[str | Any] + dict_keys = cast(List[str], _FLATTEN.split(key)) + if len(dict_keys) == 1: + key = _decode_attribute_map_key(dict_keys[0]) + break + working_key = _decode_attribute_map_key(dict_keys[0]) + working_data = working_data.get(working_key, data) + if working_data is None: + # If at any point while following flatten JSON path see None, it means + # that all properties under are None as well + return None + key = ".".join(dict_keys[1:]) + + return working_data.get(key) + + +def rest_key_case_insensitive_extractor( # pylint: disable=unused-argument, inconsistent-return-statements + attr, attr_desc, data +): + key = attr_desc["key"] + working_data = data + + while "." in key: + dict_keys = _FLATTEN.split(key) + if len(dict_keys) == 1: + key = _decode_attribute_map_key(dict_keys[0]) + break + working_key = _decode_attribute_map_key(dict_keys[0]) + working_data = attribute_key_case_insensitive_extractor(working_key, None, working_data) + if working_data is None: + # If at any point while following flatten JSON path see None, it means + # that all properties under are None as well + return None + key = ".".join(dict_keys[1:]) + + if working_data: + return attribute_key_case_insensitive_extractor(key, None, working_data) + + +def last_rest_key_extractor(attr, attr_desc, data): # pylint: disable=unused-argument + """Extract the attribute in "data" based on the last part of the JSON path key. + + :param str attr: The attribute to extract + :param dict attr_desc: The attribute description + :param dict data: The data to extract from + :rtype: object + :returns: The extracted attribute + """ + key = attr_desc["key"] + dict_keys = _FLATTEN.split(key) + return attribute_key_extractor(dict_keys[-1], None, data) + + +def last_rest_key_case_insensitive_extractor(attr, attr_desc, data): # pylint: disable=unused-argument + """Extract the attribute in "data" based on the last part of the JSON path key. + + This is the case insensitive version of "last_rest_key_extractor" + :param str attr: The attribute to extract + :param dict attr_desc: The attribute description + :param dict data: The data to extract from + :rtype: object + :returns: The extracted attribute + """ + key = attr_desc["key"] + dict_keys = _FLATTEN.split(key) + return attribute_key_case_insensitive_extractor(dict_keys[-1], None, data) + + +def attribute_key_extractor(attr, _, data): + return data.get(attr) + + +def attribute_key_case_insensitive_extractor(attr, _, data): + found_key = None + lower_attr = attr.lower() + for key in data: + if lower_attr == key.lower(): + found_key = key + break + + return data.get(found_key) + + +def _extract_name_from_internal_type(internal_type): + """Given an internal type XML description, extract correct XML name with namespace. + + :param dict internal_type: An model type + :rtype: tuple + :returns: A tuple XML name + namespace dict + """ + internal_type_xml_map = getattr(internal_type, "_xml_map", {}) + xml_name = internal_type_xml_map.get("name", internal_type.__name__) + xml_ns = internal_type_xml_map.get("ns", None) + if xml_ns: + xml_name = "{{{}}}{}".format(xml_ns, xml_name) + return xml_name + + +def xml_key_extractor(attr, attr_desc, data): # pylint: disable=unused-argument,too-many-return-statements + if isinstance(data, dict): + return None + + # Test if this model is XML ready first + if not isinstance(data, ET.Element): + return None + + xml_desc = attr_desc.get("xml", {}) + xml_name = xml_desc.get("name", attr_desc["key"]) + + # Look for a children + is_iter_type = attr_desc["type"].startswith("[") + is_wrapped = xml_desc.get("wrapped", False) + internal_type = attr_desc.get("internalType", None) + internal_type_xml_map = getattr(internal_type, "_xml_map", {}) + + # Integrate namespace if necessary + xml_ns = xml_desc.get("ns", internal_type_xml_map.get("ns", None)) + if xml_ns: + xml_name = "{{{}}}{}".format(xml_ns, xml_name) + + # If it's an attribute, that's simple + if xml_desc.get("attr", False): + return data.get(xml_name) + + # If it's x-ms-text, that's simple too + if xml_desc.get("text", False): + return data.text + + # Scenario where I take the local name: + # - Wrapped node + # - Internal type is an enum (considered basic types) + # - Internal type has no XML/Name node + if is_wrapped or (internal_type and (issubclass(internal_type, Enum) or "name" not in internal_type_xml_map)): + children = data.findall(xml_name) + # If internal type has a local name and it's not a list, I use that name + elif not is_iter_type and internal_type and "name" in internal_type_xml_map: + xml_name = _extract_name_from_internal_type(internal_type) + children = data.findall(xml_name) + # That's an array + else: + if internal_type: # Complex type, ignore itemsName and use the complex type name + items_name = _extract_name_from_internal_type(internal_type) + else: + items_name = xml_desc.get("itemsName", xml_name) + children = data.findall(items_name) + + if len(children) == 0: + if is_iter_type: + if is_wrapped: + return None # is_wrapped no node, we want None + return [] # not wrapped, assume empty list + return None # Assume it's not there, maybe an optional node. + + # If is_iter_type and not wrapped, return all found children + if is_iter_type: + if not is_wrapped: + return children + # Iter and wrapped, should have found one node only (the wrap one) + if len(children) != 1: + raise DeserializationError( + "Tried to deserialize an array not wrapped, and found several nodes '{}'. Maybe you should declare this array as wrapped?".format( + xml_name + ) + ) + return list(children[0]) # Might be empty list and that's ok. + + # Here it's not a itertype, we should have found one element only or empty + if len(children) > 1: + raise DeserializationError("Find several XML '{}' where it was not expected".format(xml_name)) + return children[0] + + +class Deserializer: + """Response object model deserializer. + + :param dict classes: Class type dictionary for deserializing complex types. + :ivar list key_extractors: Ordered list of extractors to be used by this deserializer. + """ + + basic_types = {str: "str", int: "int", bool: "bool", float: "float"} + + valid_date = re.compile(r"\d{4}[-]\d{2}[-]\d{2}T\d{2}:\d{2}:\d{2}\.?\d*Z?[-+]?[\d{2}]?:?[\d{2}]?") + + def __init__(self, classes: Optional[Mapping[str, type]] = None) -> None: + self.deserialize_type = { + "iso-8601": Deserializer.deserialize_iso, + "rfc-1123": Deserializer.deserialize_rfc, + "unix-time": Deserializer.deserialize_unix, + "duration": Deserializer.deserialize_duration, + "date": Deserializer.deserialize_date, + "time": Deserializer.deserialize_time, + "decimal": Deserializer.deserialize_decimal, + "long": Deserializer.deserialize_long, + "bytearray": Deserializer.deserialize_bytearray, + "base64": Deserializer.deserialize_base64, + "object": self.deserialize_object, + "[]": self.deserialize_iter, + "{}": self.deserialize_dict, + } + self.deserialize_expected_types = { + "duration": (isodate.Duration, datetime.timedelta), + "iso-8601": (datetime.datetime), + } + self.dependencies: Dict[str, type] = dict(classes) if classes else {} + self.key_extractors = [rest_key_extractor, xml_key_extractor] + # Additional properties only works if the "rest_key_extractor" is used to + # extract the keys. Making it to work whatever the key extractor is too much + # complicated, with no real scenario for now. + # So adding a flag to disable additional properties detection. This flag should be + # used if your expect the deserialization to NOT come from a JSON REST syntax. + # Otherwise, result are unexpected + self.additional_properties_detection = True + + def __call__(self, target_obj, response_data, content_type=None): + """Call the deserializer to process a REST response. + + :param str target_obj: Target data type to deserialize to. + :param requests.Response response_data: REST response object. + :param str content_type: Swagger "produces" if available. + :raises DeserializationError: if deserialization fails. + :return: Deserialized object. + :rtype: object + """ + data = self._unpack_content(response_data, content_type) + return self._deserialize(target_obj, data) + + def _deserialize(self, target_obj, data): # pylint: disable=inconsistent-return-statements + """Call the deserializer on a model. + + Data needs to be already deserialized as JSON or XML ElementTree + + :param str target_obj: Target data type to deserialize to. + :param object data: Object to deserialize. + :raises DeserializationError: if deserialization fails. + :return: Deserialized object. + :rtype: object + """ + # This is already a model, go recursive just in case + if hasattr(data, "_attribute_map"): + constants = [name for name, config in getattr(data, "_validation", {}).items() if config.get("constant")] + try: + for attr, mapconfig in data._attribute_map.items(): # pylint: disable=protected-access + if attr in constants: + continue + value = getattr(data, attr) + if value is None: + continue + local_type = mapconfig["type"] + internal_data_type = local_type.strip("[]{}") + if internal_data_type not in self.dependencies or isinstance(internal_data_type, Enum): + continue + setattr(data, attr, self._deserialize(local_type, value)) + return data + except AttributeError: + return + + response, class_name = self._classify_target(target_obj, data) + + if isinstance(response, str): + return self.deserialize_data(data, response) + if isinstance(response, type) and issubclass(response, Enum): + return self.deserialize_enum(data, response) + + if data is None or data is CoreNull: + return data + try: + attributes = response._attribute_map # type: ignore # pylint: disable=protected-access + d_attrs = {} + for attr, attr_desc in attributes.items(): + # Check empty string. If it's not empty, someone has a real "additionalProperties"... + if attr == "additional_properties" and attr_desc["key"] == "": + continue + raw_value = None + # Enhance attr_desc with some dynamic data + attr_desc = attr_desc.copy() # Do a copy, do not change the real one + internal_data_type = attr_desc["type"].strip("[]{}") + if internal_data_type in self.dependencies: + attr_desc["internalType"] = self.dependencies[internal_data_type] + + for key_extractor in self.key_extractors: + found_value = key_extractor(attr, attr_desc, data) + if found_value is not None: + if raw_value is not None and raw_value != found_value: + msg = ( + "Ignoring extracted value '%s' from %s for key '%s'" + " (duplicate extraction, follow extractors order)" + ) + _LOGGER.warning(msg, found_value, key_extractor, attr) + continue + raw_value = found_value + + value = self.deserialize_data(raw_value, attr_desc["type"]) + d_attrs[attr] = value + except (AttributeError, TypeError, KeyError) as err: + msg = "Unable to deserialize to object: " + class_name # type: ignore + raise DeserializationError(msg) from err + additional_properties = self._build_additional_properties(attributes, data) + return self._instantiate_model(response, d_attrs, additional_properties) + + def _build_additional_properties(self, attribute_map, data): + if not self.additional_properties_detection: + return None + if "additional_properties" in attribute_map and attribute_map.get("additional_properties", {}).get("key") != "": + # Check empty string. If it's not empty, someone has a real "additionalProperties" + return None + if isinstance(data, ET.Element): + data = {el.tag: el.text for el in data} + + known_keys = { + _decode_attribute_map_key(_FLATTEN.split(desc["key"])[0]) + for desc in attribute_map.values() + if desc["key"] != "" + } + present_keys = set(data.keys()) + missing_keys = present_keys - known_keys + return {key: data[key] for key in missing_keys} + + def _classify_target(self, target, data): + """Check to see whether the deserialization target object can + be classified into a subclass. + Once classification has been determined, initialize object. + + :param str target: The target object type to deserialize to. + :param str/dict data: The response data to deserialize. + :return: The classified target object and its class name. + :rtype: tuple + """ + if target is None: + return None, None + + if isinstance(target, str): + try: + target = self.dependencies[target] + except KeyError: + return target, target + + try: + target = target._classify(data, self.dependencies) # type: ignore # pylint: disable=protected-access + except AttributeError: + pass # Target is not a Model, no classify + return target, target.__class__.__name__ # type: ignore + + def failsafe_deserialize(self, target_obj, data, content_type=None): + """Ignores any errors encountered in deserialization, + and falls back to not deserializing the object. Recommended + for use in error deserialization, as we want to return the + HttpResponseError to users, and not have them deal with + a deserialization error. + + :param str target_obj: The target object type to deserialize to. + :param str/dict data: The response data to deserialize. + :param str content_type: Swagger "produces" if available. + :return: Deserialized object. + :rtype: object + """ + try: + return self(target_obj, data, content_type=content_type) + except: # pylint: disable=bare-except + _LOGGER.debug( + "Ran into a deserialization error. Ignoring since this is failsafe deserialization", exc_info=True + ) + return None + + @staticmethod + def _unpack_content(raw_data, content_type=None): + """Extract the correct structure for deserialization. + + If raw_data is a PipelineResponse, try to extract the result of RawDeserializer. + if we can't, raise. Your Pipeline should have a RawDeserializer. + + If not a pipeline response and raw_data is bytes or string, use content-type + to decode it. If no content-type, try JSON. + + If raw_data is something else, bypass all logic and return it directly. + + :param obj raw_data: Data to be processed. + :param str content_type: How to parse if raw_data is a string/bytes. + :raises JSONDecodeError: If JSON is requested and parsing is impossible. + :raises UnicodeDecodeError: If bytes is not UTF8 + :rtype: object + :return: Unpacked content. + """ + # Assume this is enough to detect a Pipeline Response without importing it + context = getattr(raw_data, "context", {}) + if context: + if RawDeserializer.CONTEXT_NAME in context: + return context[RawDeserializer.CONTEXT_NAME] + raise ValueError("This pipeline didn't have the RawDeserializer policy; can't deserialize") + + # Assume this is enough to recognize universal_http.ClientResponse without importing it + if hasattr(raw_data, "body"): + return RawDeserializer.deserialize_from_http_generics(raw_data.text(), raw_data.headers) + + # Assume this enough to recognize requests.Response without importing it. + if hasattr(raw_data, "_content_consumed"): + return RawDeserializer.deserialize_from_http_generics(raw_data.text, raw_data.headers) + + if isinstance(raw_data, (str, bytes)) or hasattr(raw_data, "read"): + return RawDeserializer.deserialize_from_text(raw_data, content_type) # type: ignore + return raw_data + + def _instantiate_model(self, response, attrs, additional_properties=None): + """Instantiate a response model passing in deserialized args. + + :param Response response: The response model class. + :param dict attrs: The deserialized response attributes. + :param dict additional_properties: Additional properties to be set. + :rtype: Response + :return: The instantiated response model. + """ + if callable(response): + subtype = getattr(response, "_subtype_map", {}) + try: + readonly = [ + k + for k, v in response._validation.items() # pylint: disable=protected-access # type: ignore + if v.get("readonly") + ] + const = [ + k + for k, v in response._validation.items() # pylint: disable=protected-access # type: ignore + if v.get("constant") + ] + kwargs = {k: v for k, v in attrs.items() if k not in subtype and k not in readonly + const} + response_obj = response(**kwargs) + for attr in readonly: + setattr(response_obj, attr, attrs.get(attr)) + if additional_properties: + response_obj.additional_properties = additional_properties # type: ignore + return response_obj + except TypeError as err: + msg = "Unable to deserialize {} into model {}. ".format(kwargs, response) # type: ignore + raise DeserializationError(msg + str(err)) from err + else: + try: + for attr, value in attrs.items(): + setattr(response, attr, value) + return response + except Exception as exp: + msg = "Unable to populate response model. " + msg += "Type: {}, Error: {}".format(type(response), exp) + raise DeserializationError(msg) from exp + + def deserialize_data(self, data, data_type): # pylint: disable=too-many-return-statements + """Process data for deserialization according to data type. + + :param str data: The response string to be deserialized. + :param str data_type: The type to deserialize to. + :raises DeserializationError: if deserialization fails. + :return: Deserialized object. + :rtype: object + """ + if data is None: + return data + + try: + if not data_type: + return data + if data_type in self.basic_types.values(): + return self.deserialize_basic(data, data_type) + if data_type in self.deserialize_type: + if isinstance(data, self.deserialize_expected_types.get(data_type, tuple())): + return data + + is_a_text_parsing_type = lambda x: x not in [ # pylint: disable=unnecessary-lambda-assignment + "object", + "[]", + r"{}", + ] + if isinstance(data, ET.Element) and is_a_text_parsing_type(data_type) and not data.text: + return None + data_val = self.deserialize_type[data_type](data) + return data_val + + iter_type = data_type[0] + data_type[-1] + if iter_type in self.deserialize_type: + return self.deserialize_type[iter_type](data, data_type[1:-1]) + + obj_type = self.dependencies[data_type] + if issubclass(obj_type, Enum): + if isinstance(data, ET.Element): + data = data.text + return self.deserialize_enum(data, obj_type) + + except (ValueError, TypeError, AttributeError) as err: + msg = "Unable to deserialize response data." + msg += " Data: {}, {}".format(data, data_type) + raise DeserializationError(msg) from err + return self._deserialize(obj_type, data) + + def deserialize_iter(self, attr, iter_type): + """Deserialize an iterable. + + :param list attr: Iterable to be deserialized. + :param str iter_type: The type of object in the iterable. + :return: Deserialized iterable. + :rtype: list + """ + if attr is None: + return None + if isinstance(attr, ET.Element): # If I receive an element here, get the children + attr = list(attr) + if not isinstance(attr, (list, set)): + raise DeserializationError("Cannot deserialize as [{}] an object of type {}".format(iter_type, type(attr))) + return [self.deserialize_data(a, iter_type) for a in attr] + + def deserialize_dict(self, attr, dict_type): + """Deserialize a dictionary. + + :param dict/list attr: Dictionary to be deserialized. Also accepts + a list of key, value pairs. + :param str dict_type: The object type of the items in the dictionary. + :return: Deserialized dictionary. + :rtype: dict + """ + if isinstance(attr, list): + return {x["key"]: self.deserialize_data(x["value"], dict_type) for x in attr} + + if isinstance(attr, ET.Element): + # Transform value into {"Key": "value"} + attr = {el.tag: el.text for el in attr} + return {k: self.deserialize_data(v, dict_type) for k, v in attr.items()} + + def deserialize_object(self, attr, **kwargs): # pylint: disable=too-many-return-statements + """Deserialize a generic object. + This will be handled as a dictionary. + + :param dict attr: Dictionary to be deserialized. + :return: Deserialized object. + :rtype: dict + :raises TypeError: if non-builtin datatype encountered. + """ + if attr is None: + return None + if isinstance(attr, ET.Element): + # Do no recurse on XML, just return the tree as-is + return attr + if isinstance(attr, str): + return self.deserialize_basic(attr, "str") + obj_type = type(attr) + if obj_type in self.basic_types: + return self.deserialize_basic(attr, self.basic_types[obj_type]) + if obj_type is _long_type: + return self.deserialize_long(attr) + + if obj_type == dict: + deserialized = {} + for key, value in attr.items(): + try: + deserialized[key] = self.deserialize_object(value, **kwargs) + except ValueError: + deserialized[key] = None + return deserialized + + if obj_type == list: + deserialized = [] + for obj in attr: + try: + deserialized.append(self.deserialize_object(obj, **kwargs)) + except ValueError: + pass + return deserialized + + error = "Cannot deserialize generic object with type: " + raise TypeError(error + str(obj_type)) + + def deserialize_basic(self, attr, data_type): # pylint: disable=too-many-return-statements + """Deserialize basic builtin data type from string. + Will attempt to convert to str, int, float and bool. + This function will also accept '1', '0', 'true' and 'false' as + valid bool values. + + :param str attr: response string to be deserialized. + :param str data_type: deserialization data type. + :return: Deserialized basic type. + :rtype: str, int, float or bool + :raises TypeError: if string format is not valid. + """ + # If we're here, data is supposed to be a basic type. + # If it's still an XML node, take the text + if isinstance(attr, ET.Element): + attr = attr.text + if not attr: + if data_type == "str": + # None or '', node is empty string. + return "" + # None or '', node with a strong type is None. + # Don't try to model "empty bool" or "empty int" + return None + + if data_type == "bool": + if attr in [True, False, 1, 0]: + return bool(attr) + if isinstance(attr, str): + if attr.lower() in ["true", "1"]: + return True + if attr.lower() in ["false", "0"]: + return False + raise TypeError("Invalid boolean value: {}".format(attr)) + + if data_type == "str": + return self.deserialize_unicode(attr) + return eval(data_type)(attr) # nosec # pylint: disable=eval-used + + @staticmethod + def deserialize_unicode(data): + """Preserve unicode objects in Python 2, otherwise return data + as a string. + + :param str data: response string to be deserialized. + :return: Deserialized string. + :rtype: str or unicode + """ + # We might be here because we have an enum modeled as string, + # and we try to deserialize a partial dict with enum inside + if isinstance(data, Enum): + return data + + # Consider this is real string + try: + if isinstance(data, unicode): # type: ignore + return data + except NameError: + return str(data) + return str(data) + + @staticmethod + def deserialize_enum(data, enum_obj): + """Deserialize string into enum object. + + If the string is not a valid enum value it will be returned as-is + and a warning will be logged. + + :param str data: Response string to be deserialized. If this value is + None or invalid it will be returned as-is. + :param Enum enum_obj: Enum object to deserialize to. + :return: Deserialized enum object. + :rtype: Enum + """ + if isinstance(data, enum_obj) or data is None: + return data + if isinstance(data, Enum): + data = data.value + if isinstance(data, int): + # Workaround. We might consider remove it in the future. + try: + return list(enum_obj.__members__.values())[data] + except IndexError as exc: + error = "{!r} is not a valid index for enum {!r}" + raise DeserializationError(error.format(data, enum_obj)) from exc + try: + return enum_obj(str(data)) + except ValueError: + for enum_value in enum_obj: + if enum_value.value.lower() == str(data).lower(): + return enum_value + # We don't fail anymore for unknown value, we deserialize as a string + _LOGGER.warning("Deserializer is not able to find %s as valid enum in %s", data, enum_obj) + return Deserializer.deserialize_unicode(data) + + @staticmethod + def deserialize_bytearray(attr): + """Deserialize string into bytearray. + + :param str attr: response string to be deserialized. + :return: Deserialized bytearray + :rtype: bytearray + :raises TypeError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + return bytearray(b64decode(attr)) # type: ignore + + @staticmethod + def deserialize_base64(attr): + """Deserialize base64 encoded string into string. + + :param str attr: response string to be deserialized. + :return: Deserialized base64 string + :rtype: bytearray + :raises TypeError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + padding = "=" * (3 - (len(attr) + 3) % 4) # type: ignore + attr = attr + padding # type: ignore + encoded = attr.replace("-", "+").replace("_", "/") + return b64decode(encoded) + + @staticmethod + def deserialize_decimal(attr): + """Deserialize string into Decimal object. + + :param str attr: response string to be deserialized. + :return: Deserialized decimal + :raises DeserializationError: if string format invalid. + :rtype: decimal + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + return decimal.Decimal(str(attr)) # type: ignore + except decimal.DecimalException as err: + msg = "Invalid decimal {}".format(attr) + raise DeserializationError(msg) from err + + @staticmethod + def deserialize_long(attr): + """Deserialize string into long (Py2) or int (Py3). + + :param str attr: response string to be deserialized. + :return: Deserialized int + :rtype: long or int + :raises ValueError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + return _long_type(attr) # type: ignore + + @staticmethod + def deserialize_duration(attr): + """Deserialize ISO-8601 formatted string into TimeDelta object. + + :param str attr: response string to be deserialized. + :return: Deserialized duration + :rtype: TimeDelta + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + duration = isodate.parse_duration(attr) + except (ValueError, OverflowError, AttributeError) as err: + msg = "Cannot deserialize duration object." + raise DeserializationError(msg) from err + return duration + + @staticmethod + def deserialize_date(attr): + """Deserialize ISO-8601 formatted string into Date object. + + :param str attr: response string to be deserialized. + :return: Deserialized date + :rtype: Date + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + if re.search(r"[^\W\d_]", attr, re.I + re.U): # type: ignore + raise DeserializationError("Date must have only digits and -. Received: %s" % attr) + # This must NOT use defaultmonth/defaultday. Using None ensure this raises an exception. + return isodate.parse_date(attr, defaultmonth=0, defaultday=0) + + @staticmethod + def deserialize_time(attr): + """Deserialize ISO-8601 formatted string into time object. + + :param str attr: response string to be deserialized. + :return: Deserialized time + :rtype: datetime.time + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + if re.search(r"[^\W\d_]", attr, re.I + re.U): # type: ignore + raise DeserializationError("Date must have only digits and -. Received: %s" % attr) + return isodate.parse_time(attr) + + @staticmethod + def deserialize_rfc(attr): + """Deserialize RFC-1123 formatted string into Datetime object. + + :param str attr: response string to be deserialized. + :return: Deserialized RFC datetime + :rtype: Datetime + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + parsed_date = email.utils.parsedate_tz(attr) # type: ignore + date_obj = datetime.datetime( + *parsed_date[:6], tzinfo=datetime.timezone(datetime.timedelta(minutes=(parsed_date[9] or 0) / 60)) + ) + if not date_obj.tzinfo: + date_obj = date_obj.astimezone(tz=TZ_UTC) + except ValueError as err: + msg = "Cannot deserialize to rfc datetime object." + raise DeserializationError(msg) from err + return date_obj + + @staticmethod + def deserialize_iso(attr): + """Deserialize ISO-8601 formatted string into Datetime object. + + :param str attr: response string to be deserialized. + :return: Deserialized ISO datetime + :rtype: Datetime + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + attr = attr.upper() # type: ignore + match = Deserializer.valid_date.match(attr) + if not match: + raise ValueError("Invalid datetime string: " + attr) + + check_decimal = attr.split(".") + if len(check_decimal) > 1: + decimal_str = "" + for digit in check_decimal[1]: + if digit.isdigit(): + decimal_str += digit + else: + break + if len(decimal_str) > 6: + attr = attr.replace(decimal_str, decimal_str[0:6]) + + date_obj = isodate.parse_datetime(attr) + test_utc = date_obj.utctimetuple() + if test_utc.tm_year > 9999 or test_utc.tm_year < 1: + raise OverflowError("Hit max or min date") + except (ValueError, OverflowError, AttributeError) as err: + msg = "Cannot deserialize datetime object." + raise DeserializationError(msg) from err + return date_obj + + @staticmethod + def deserialize_unix(attr): + """Serialize Datetime object into IntTime format. + This is represented as seconds. + + :param int attr: Object to be serialized. + :return: Deserialized datetime + :rtype: Datetime + :raises DeserializationError: if format invalid + """ + if isinstance(attr, ET.Element): + attr = int(attr.text) # type: ignore + try: + attr = int(attr) + date_obj = datetime.datetime.fromtimestamp(attr, TZ_UTC) + except ValueError as err: + msg = "Cannot deserialize to unix datetime object." + raise DeserializationError(msg) from err + return date_obj diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/CustomBaseUriVersionTolerant/custombaseurlversiontolerant/aio/_client.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/CustomBaseUriVersionTolerant/custombaseurlversiontolerant/aio/_client.py index 24bc4d89166..0c857272e94 100644 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/CustomBaseUriVersionTolerant/custombaseurlversiontolerant/aio/_client.py +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/CustomBaseUriVersionTolerant/custombaseurlversiontolerant/aio/_client.py @@ -14,7 +14,7 @@ from azure.core.pipeline import policies from azure.core.rest import AsyncHttpResponse, HttpRequest -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import AutoRestParameterizedHostTestClientConfiguration from .operations import PathsOperations diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/CustomBaseUriVersionTolerant/custombaseurlversiontolerant/aio/operations/_operations.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/CustomBaseUriVersionTolerant/custombaseurlversiontolerant/aio/operations/_operations.py index c2f9d10d4e1..f22ba71db4f 100644 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/CustomBaseUriVersionTolerant/custombaseurlversiontolerant/aio/operations/_operations.py +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/CustomBaseUriVersionTolerant/custombaseurlversiontolerant/aio/operations/_operations.py @@ -21,7 +21,7 @@ from azure.core.rest import AsyncHttpResponse, HttpRequest from azure.core.tracing.decorator_async import distributed_trace_async -from ..._serialization import Deserializer, Serializer +from ..._utils.serialization import Deserializer, Serializer from ...operations._operations import build_paths_get_empty_request from .._configuration import AutoRestParameterizedHostTestClientConfiguration diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/CustomBaseUriVersionTolerant/custombaseurlversiontolerant/operations/_operations.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/CustomBaseUriVersionTolerant/custombaseurlversiontolerant/operations/_operations.py index d1ef42c250c..7a499bc8585 100644 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/CustomBaseUriVersionTolerant/custombaseurlversiontolerant/operations/_operations.py +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/CustomBaseUriVersionTolerant/custombaseurlversiontolerant/operations/_operations.py @@ -23,7 +23,7 @@ from azure.core.utils import case_insensitive_dict from .._configuration import AutoRestParameterizedHostTestClientConfiguration -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ErrorWithSecretsVersionTolerant/errorwithsecretsversiontolerant/_client.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ErrorWithSecretsVersionTolerant/errorwithsecretsversiontolerant/_client.py index 7b1d8fd9e30..26d09122cc1 100644 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ErrorWithSecretsVersionTolerant/errorwithsecretsversiontolerant/_client.py +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ErrorWithSecretsVersionTolerant/errorwithsecretsversiontolerant/_client.py @@ -16,7 +16,7 @@ from ._configuration import ErrorWithSecretsConfiguration from ._operations import ErrorWithSecretsOperationsMixin -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer class ErrorWithSecrets(ErrorWithSecretsOperationsMixin): # pylint: disable=client-accepts-api-version-keyword diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ErrorWithSecretsVersionTolerant/errorwithsecretsversiontolerant/_operations/_operations.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ErrorWithSecretsVersionTolerant/errorwithsecretsversiontolerant/_operations/_operations.py index cec94bdf07a..45774b6f724 100644 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ErrorWithSecretsVersionTolerant/errorwithsecretsversiontolerant/_operations/_operations.py +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ErrorWithSecretsVersionTolerant/errorwithsecretsversiontolerant/_operations/_operations.py @@ -8,6 +8,7 @@ from collections.abc import MutableMapping from typing import Any, Callable, Dict, Optional, TypeVar, cast +from azure.core import PipelineClient from azure.core.exceptions import ( ClientAuthenticationError, HttpResponseError, @@ -21,8 +22,9 @@ from azure.core.tracing.decorator import distributed_trace from azure.core.utils import case_insensitive_dict -from .._serialization import Serializer -from .._vendor import ErrorWithSecretsMixinABC +from .._configuration import ErrorWithSecretsConfiguration +from .._utils.serialization import Serializer +from .._utils.utils import ClientMixinABC JSON = MutableMapping[str, Any] T = TypeVar("T") @@ -62,7 +64,7 @@ def build_error_with_secrets_get_error_with_secrets_request( # pylint: disable= return HttpRequest(method="GET", url=_url, headers=_headers, **kwargs) -class ErrorWithSecretsOperationsMixin(ErrorWithSecretsMixinABC): +class ErrorWithSecretsOperationsMixin(ClientMixinABC[PipelineClient, ErrorWithSecretsConfiguration]): @distributed_trace def create_secret(self, **kwargs: Any) -> JSON: diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ErrorWithSecretsVersionTolerant/errorwithsecretsversiontolerant/_utils/__init__.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ErrorWithSecretsVersionTolerant/errorwithsecretsversiontolerant/_utils/__init__.py new file mode 100644 index 00000000000..0af9b28f660 --- /dev/null +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ErrorWithSecretsVersionTolerant/errorwithsecretsversiontolerant/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ErrorWithSecretsVersionTolerant/errorwithsecretsversiontolerant/_utils/serialization.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ErrorWithSecretsVersionTolerant/errorwithsecretsversiontolerant/_utils/serialization.py new file mode 100644 index 00000000000..f5187701d7b --- /dev/null +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ErrorWithSecretsVersionTolerant/errorwithsecretsversiontolerant/_utils/serialization.py @@ -0,0 +1,2032 @@ +# pylint: disable=line-too-long,useless-suppression,too-many-lines +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +# pyright: reportUnnecessaryTypeIgnoreComment=false + +from base64 import b64decode, b64encode +import calendar +import datetime +import decimal +import email +from enum import Enum +import json +import logging +import re +import sys +import codecs +from typing import ( + Dict, + Any, + cast, + Optional, + Union, + AnyStr, + IO, + Mapping, + Callable, + MutableMapping, + List, +) + +try: + from urllib import quote # type: ignore +except ImportError: + from urllib.parse import quote +import xml.etree.ElementTree as ET + +import isodate # type: ignore +from typing_extensions import Self + +from azure.core.exceptions import DeserializationError, SerializationError +from azure.core.serialization import NULL as CoreNull + +_BOM = codecs.BOM_UTF8.decode(encoding="utf-8") + +JSON = MutableMapping[str, Any] + + +class RawDeserializer: + + # Accept "text" because we're open minded people... + JSON_REGEXP = re.compile(r"^(application|text)/([a-z+.]+\+)?json$") + + # Name used in context + CONTEXT_NAME = "deserialized_data" + + @classmethod + def deserialize_from_text(cls, data: Optional[Union[AnyStr, IO]], content_type: Optional[str] = None) -> Any: + """Decode data according to content-type. + + Accept a stream of data as well, but will be load at once in memory for now. + + If no content-type, will return the string version (not bytes, not stream) + + :param data: Input, could be bytes or stream (will be decoded with UTF8) or text + :type data: str or bytes or IO + :param str content_type: The content type. + :return: The deserialized data. + :rtype: object + """ + if hasattr(data, "read"): + # Assume a stream + data = cast(IO, data).read() + + if isinstance(data, bytes): + data_as_str = data.decode(encoding="utf-8-sig") + else: + # Explain to mypy the correct type. + data_as_str = cast(str, data) + + # Remove Byte Order Mark if present in string + data_as_str = data_as_str.lstrip(_BOM) + + if content_type is None: + return data + + if cls.JSON_REGEXP.match(content_type): + try: + return json.loads(data_as_str) + except ValueError as err: + raise DeserializationError("JSON is invalid: {}".format(err), err) from err + elif "xml" in (content_type or []): + try: + + try: + if isinstance(data, unicode): # type: ignore + # If I'm Python 2.7 and unicode XML will scream if I try a "fromstring" on unicode string + data_as_str = data_as_str.encode(encoding="utf-8") # type: ignore + except NameError: + pass + + return ET.fromstring(data_as_str) # nosec + except ET.ParseError as err: + # It might be because the server has an issue, and returned JSON with + # content-type XML.... + # So let's try a JSON load, and if it's still broken + # let's flow the initial exception + def _json_attemp(data): + try: + return True, json.loads(data) + except ValueError: + return False, None # Don't care about this one + + success, json_result = _json_attemp(data) + if success: + return json_result + # If i'm here, it's not JSON, it's not XML, let's scream + # and raise the last context in this block (the XML exception) + # The function hack is because Py2.7 messes up with exception + # context otherwise. + _LOGGER.critical("Wasn't XML not JSON, failing") + raise DeserializationError("XML is invalid") from err + elif content_type.startswith("text/"): + return data_as_str + raise DeserializationError("Cannot deserialize content-type: {}".format(content_type)) + + @classmethod + def deserialize_from_http_generics(cls, body_bytes: Optional[Union[AnyStr, IO]], headers: Mapping) -> Any: + """Deserialize from HTTP response. + + Use bytes and headers to NOT use any requests/aiohttp or whatever + specific implementation. + Headers will tested for "content-type" + + :param bytes body_bytes: The body of the response. + :param dict headers: The headers of the response. + :returns: The deserialized data. + :rtype: object + """ + # Try to use content-type from headers if available + content_type = None + if "content-type" in headers: + content_type = headers["content-type"].split(";")[0].strip().lower() + # Ouch, this server did not declare what it sent... + # Let's guess it's JSON... + # Also, since Autorest was considering that an empty body was a valid JSON, + # need that test as well.... + else: + content_type = "application/json" + + if body_bytes: + return cls.deserialize_from_text(body_bytes, content_type) + return None + + +_LOGGER = logging.getLogger(__name__) + +try: + _long_type = long # type: ignore +except NameError: + _long_type = int + +TZ_UTC = datetime.timezone.utc + +_FLATTEN = re.compile(r"(? None: + self.additional_properties: Optional[Dict[str, Any]] = {} + for k in kwargs: # pylint: disable=consider-using-dict-items + if k not in self._attribute_map: + _LOGGER.warning("%s is not a known attribute of class %s and will be ignored", k, self.__class__) + elif k in self._validation and self._validation[k].get("readonly", False): + _LOGGER.warning("Readonly attribute %s will be ignored in class %s", k, self.__class__) + else: + setattr(self, k, kwargs[k]) + + def __eq__(self, other: Any) -> bool: + """Compare objects by comparing all attributes. + + :param object other: The object to compare + :returns: True if objects are equal + :rtype: bool + """ + if isinstance(other, self.__class__): + return self.__dict__ == other.__dict__ + return False + + def __ne__(self, other: Any) -> bool: + """Compare objects by comparing all attributes. + + :param object other: The object to compare + :returns: True if objects are not equal + :rtype: bool + """ + return not self.__eq__(other) + + def __str__(self) -> str: + return str(self.__dict__) + + @classmethod + def enable_additional_properties_sending(cls) -> None: + cls._attribute_map["additional_properties"] = {"key": "", "type": "{object}"} + + @classmethod + def is_xml_model(cls) -> bool: + try: + cls._xml_map # type: ignore + except AttributeError: + return False + return True + + @classmethod + def _create_xml_node(cls): + """Create XML node. + + :returns: The XML node + :rtype: xml.etree.ElementTree.Element + """ + try: + xml_map = cls._xml_map # type: ignore + except AttributeError: + xml_map = {} + + return _create_xml_node(xml_map.get("name", cls.__name__), xml_map.get("prefix", None), xml_map.get("ns", None)) + + def serialize(self, keep_readonly: bool = False, **kwargs: Any) -> JSON: + """Return the JSON that would be sent to server from this model. + + This is an alias to `as_dict(full_restapi_key_transformer, keep_readonly=False)`. + + If you want XML serialization, you can pass the kwargs is_xml=True. + + :param bool keep_readonly: If you want to serialize the readonly attributes + :returns: A dict JSON compatible object + :rtype: dict + """ + serializer = Serializer(self._infer_class_models()) + return serializer._serialize( # type: ignore # pylint: disable=protected-access + self, keep_readonly=keep_readonly, **kwargs + ) + + def as_dict( + self, + keep_readonly: bool = True, + key_transformer: Callable[[str, Dict[str, Any], Any], Any] = attribute_transformer, + **kwargs: Any + ) -> JSON: + """Return a dict that can be serialized using json.dump. + + Advanced usage might optionally use a callback as parameter: + + .. code::python + + def my_key_transformer(key, attr_desc, value): + return key + + Key is the attribute name used in Python. Attr_desc + is a dict of metadata. Currently contains 'type' with the + msrest type and 'key' with the RestAPI encoded key. + Value is the current value in this object. + + The string returned will be used to serialize the key. + If the return type is a list, this is considered hierarchical + result dict. + + See the three examples in this file: + + - attribute_transformer + - full_restapi_key_transformer + - last_restapi_key_transformer + + If you want XML serialization, you can pass the kwargs is_xml=True. + + :param bool keep_readonly: If you want to serialize the readonly attributes + :param function key_transformer: A key transformer function. + :returns: A dict JSON compatible object + :rtype: dict + """ + serializer = Serializer(self._infer_class_models()) + return serializer._serialize( # type: ignore # pylint: disable=protected-access + self, key_transformer=key_transformer, keep_readonly=keep_readonly, **kwargs + ) + + @classmethod + def _infer_class_models(cls): + try: + str_models = cls.__module__.rsplit(".", 1)[0] + models = sys.modules[str_models] + client_models = {k: v for k, v in models.__dict__.items() if isinstance(v, type)} + if cls.__name__ not in client_models: + raise ValueError("Not Autorest generated code") + except Exception: # pylint: disable=broad-exception-caught + # Assume it's not Autorest generated (tests?). Add ourselves as dependencies. + client_models = {cls.__name__: cls} + return client_models + + @classmethod + def deserialize(cls, data: Any, content_type: Optional[str] = None) -> Self: + """Parse a str using the RestAPI syntax and return a model. + + :param str data: A str using RestAPI structure. JSON by default. + :param str content_type: JSON by default, set application/xml if XML. + :returns: An instance of this model + :raises DeserializationError: if something went wrong + :rtype: Self + """ + deserializer = Deserializer(cls._infer_class_models()) + return deserializer(cls.__name__, data, content_type=content_type) # type: ignore + + @classmethod + def from_dict( + cls, + data: Any, + key_extractors: Optional[Callable[[str, Dict[str, Any], Any], Any]] = None, + content_type: Optional[str] = None, + ) -> Self: + """Parse a dict using given key extractor return a model. + + By default consider key + extractors (rest_key_case_insensitive_extractor, attribute_key_case_insensitive_extractor + and last_rest_key_case_insensitive_extractor) + + :param dict data: A dict using RestAPI structure + :param function key_extractors: A key extractor function. + :param str content_type: JSON by default, set application/xml if XML. + :returns: An instance of this model + :raises DeserializationError: if something went wrong + :rtype: Self + """ + deserializer = Deserializer(cls._infer_class_models()) + deserializer.key_extractors = ( # type: ignore + [ # type: ignore + attribute_key_case_insensitive_extractor, + rest_key_case_insensitive_extractor, + last_rest_key_case_insensitive_extractor, + ] + if key_extractors is None + else key_extractors + ) + return deserializer(cls.__name__, data, content_type=content_type) # type: ignore + + @classmethod + def _flatten_subtype(cls, key, objects): + if "_subtype_map" not in cls.__dict__: + return {} + result = dict(cls._subtype_map[key]) + for valuetype in cls._subtype_map[key].values(): + result.update(objects[valuetype]._flatten_subtype(key, objects)) # pylint: disable=protected-access + return result + + @classmethod + def _classify(cls, response, objects): + """Check the class _subtype_map for any child classes. + We want to ignore any inherited _subtype_maps. + + :param dict response: The initial data + :param dict objects: The class objects + :returns: The class to be used + :rtype: class + """ + for subtype_key in cls.__dict__.get("_subtype_map", {}).keys(): + subtype_value = None + + if not isinstance(response, ET.Element): + rest_api_response_key = cls._get_rest_key_parts(subtype_key)[-1] + subtype_value = response.get(rest_api_response_key, None) or response.get(subtype_key, None) + else: + subtype_value = xml_key_extractor(subtype_key, cls._attribute_map[subtype_key], response) + if subtype_value: + # Try to match base class. Can be class name only + # (bug to fix in Autorest to support x-ms-discriminator-name) + if cls.__name__ == subtype_value: + return cls + flatten_mapping_type = cls._flatten_subtype(subtype_key, objects) + try: + return objects[flatten_mapping_type[subtype_value]] # type: ignore + except KeyError: + _LOGGER.warning( + "Subtype value %s has no mapping, use base class %s.", + subtype_value, + cls.__name__, + ) + break + else: + _LOGGER.warning("Discriminator %s is absent or null, use base class %s.", subtype_key, cls.__name__) + break + return cls + + @classmethod + def _get_rest_key_parts(cls, attr_key): + """Get the RestAPI key of this attr, split it and decode part + :param str attr_key: Attribute key must be in attribute_map. + :returns: A list of RestAPI part + :rtype: list + """ + rest_split_key = _FLATTEN.split(cls._attribute_map[attr_key]["key"]) + return [_decode_attribute_map_key(key_part) for key_part in rest_split_key] + + +def _decode_attribute_map_key(key): + """This decode a key in an _attribute_map to the actual key we want to look at + inside the received data. + + :param str key: A key string from the generated code + :returns: The decoded key + :rtype: str + """ + return key.replace("\\.", ".") + + +class Serializer: # pylint: disable=too-many-public-methods + """Request object model serializer.""" + + basic_types = {str: "str", int: "int", bool: "bool", float: "float"} + + _xml_basic_types_serializers = {"bool": lambda x: str(x).lower()} + days = {0: "Mon", 1: "Tue", 2: "Wed", 3: "Thu", 4: "Fri", 5: "Sat", 6: "Sun"} + months = { + 1: "Jan", + 2: "Feb", + 3: "Mar", + 4: "Apr", + 5: "May", + 6: "Jun", + 7: "Jul", + 8: "Aug", + 9: "Sep", + 10: "Oct", + 11: "Nov", + 12: "Dec", + } + validation = { + "min_length": lambda x, y: len(x) < y, + "max_length": lambda x, y: len(x) > y, + "minimum": lambda x, y: x < y, + "maximum": lambda x, y: x > y, + "minimum_ex": lambda x, y: x <= y, + "maximum_ex": lambda x, y: x >= y, + "min_items": lambda x, y: len(x) < y, + "max_items": lambda x, y: len(x) > y, + "pattern": lambda x, y: not re.match(y, x, re.UNICODE), + "unique": lambda x, y: len(x) != len(set(x)), + "multiple": lambda x, y: x % y != 0, + } + + def __init__(self, classes: Optional[Mapping[str, type]] = None) -> None: + self.serialize_type = { + "iso-8601": Serializer.serialize_iso, + "rfc-1123": Serializer.serialize_rfc, + "unix-time": Serializer.serialize_unix, + "duration": Serializer.serialize_duration, + "date": Serializer.serialize_date, + "time": Serializer.serialize_time, + "decimal": Serializer.serialize_decimal, + "long": Serializer.serialize_long, + "bytearray": Serializer.serialize_bytearray, + "base64": Serializer.serialize_base64, + "object": self.serialize_object, + "[]": self.serialize_iter, + "{}": self.serialize_dict, + } + self.dependencies: Dict[str, type] = dict(classes) if classes else {} + self.key_transformer = full_restapi_key_transformer + self.client_side_validation = True + + def _serialize( # pylint: disable=too-many-nested-blocks, too-many-branches, too-many-statements, too-many-locals + self, target_obj, data_type=None, **kwargs + ): + """Serialize data into a string according to type. + + :param object target_obj: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str, dict + :raises SerializationError: if serialization fails. + :returns: The serialized data. + """ + key_transformer = kwargs.get("key_transformer", self.key_transformer) + keep_readonly = kwargs.get("keep_readonly", False) + if target_obj is None: + return None + + attr_name = None + class_name = target_obj.__class__.__name__ + + if data_type: + return self.serialize_data(target_obj, data_type, **kwargs) + + if not hasattr(target_obj, "_attribute_map"): + data_type = type(target_obj).__name__ + if data_type in self.basic_types.values(): + return self.serialize_data(target_obj, data_type, **kwargs) + + # Force "is_xml" kwargs if we detect a XML model + try: + is_xml_model_serialization = kwargs["is_xml"] + except KeyError: + is_xml_model_serialization = kwargs.setdefault("is_xml", target_obj.is_xml_model()) + + serialized = {} + if is_xml_model_serialization: + serialized = target_obj._create_xml_node() # pylint: disable=protected-access + try: + attributes = target_obj._attribute_map # pylint: disable=protected-access + for attr, attr_desc in attributes.items(): + attr_name = attr + if not keep_readonly and target_obj._validation.get( # pylint: disable=protected-access + attr_name, {} + ).get("readonly", False): + continue + + if attr_name == "additional_properties" and attr_desc["key"] == "": + if target_obj.additional_properties is not None: + serialized.update(target_obj.additional_properties) + continue + try: + + orig_attr = getattr(target_obj, attr) + if is_xml_model_serialization: + pass # Don't provide "transformer" for XML for now. Keep "orig_attr" + else: # JSON + keys, orig_attr = key_transformer(attr, attr_desc.copy(), orig_attr) + keys = keys if isinstance(keys, list) else [keys] + + kwargs["serialization_ctxt"] = attr_desc + new_attr = self.serialize_data(orig_attr, attr_desc["type"], **kwargs) + + if is_xml_model_serialization: + xml_desc = attr_desc.get("xml", {}) + xml_name = xml_desc.get("name", attr_desc["key"]) + xml_prefix = xml_desc.get("prefix", None) + xml_ns = xml_desc.get("ns", None) + if xml_desc.get("attr", False): + if xml_ns: + ET.register_namespace(xml_prefix, xml_ns) + xml_name = "{{{}}}{}".format(xml_ns, xml_name) + serialized.set(xml_name, new_attr) # type: ignore + continue + if xml_desc.get("text", False): + serialized.text = new_attr # type: ignore + continue + if isinstance(new_attr, list): + serialized.extend(new_attr) # type: ignore + elif isinstance(new_attr, ET.Element): + # If the down XML has no XML/Name, + # we MUST replace the tag with the local tag. But keeping the namespaces. + if "name" not in getattr(orig_attr, "_xml_map", {}): + splitted_tag = new_attr.tag.split("}") + if len(splitted_tag) == 2: # Namespace + new_attr.tag = "}".join([splitted_tag[0], xml_name]) + else: + new_attr.tag = xml_name + serialized.append(new_attr) # type: ignore + else: # That's a basic type + # Integrate namespace if necessary + local_node = _create_xml_node(xml_name, xml_prefix, xml_ns) + local_node.text = str(new_attr) + serialized.append(local_node) # type: ignore + else: # JSON + for k in reversed(keys): # type: ignore + new_attr = {k: new_attr} + + _new_attr = new_attr + _serialized = serialized + for k in keys: # type: ignore + if k not in _serialized: + _serialized.update(_new_attr) # type: ignore + _new_attr = _new_attr[k] # type: ignore + _serialized = _serialized[k] + except ValueError as err: + if isinstance(err, SerializationError): + raise + + except (AttributeError, KeyError, TypeError) as err: + msg = "Attribute {} in object {} cannot be serialized.\n{}".format(attr_name, class_name, str(target_obj)) + raise SerializationError(msg) from err + return serialized + + def body(self, data, data_type, **kwargs): + """Serialize data intended for a request body. + + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: dict + :raises SerializationError: if serialization fails. + :raises ValueError: if data is None + :returns: The serialized request body + """ + + # Just in case this is a dict + internal_data_type_str = data_type.strip("[]{}") + internal_data_type = self.dependencies.get(internal_data_type_str, None) + try: + is_xml_model_serialization = kwargs["is_xml"] + except KeyError: + if internal_data_type and issubclass(internal_data_type, Model): + is_xml_model_serialization = kwargs.setdefault("is_xml", internal_data_type.is_xml_model()) + else: + is_xml_model_serialization = False + if internal_data_type and not isinstance(internal_data_type, Enum): + try: + deserializer = Deserializer(self.dependencies) + # Since it's on serialization, it's almost sure that format is not JSON REST + # We're not able to deal with additional properties for now. + deserializer.additional_properties_detection = False + if is_xml_model_serialization: + deserializer.key_extractors = [ # type: ignore + attribute_key_case_insensitive_extractor, + ] + else: + deserializer.key_extractors = [ + rest_key_case_insensitive_extractor, + attribute_key_case_insensitive_extractor, + last_rest_key_case_insensitive_extractor, + ] + data = deserializer._deserialize(data_type, data) # pylint: disable=protected-access + except DeserializationError as err: + raise SerializationError("Unable to build a model: " + str(err)) from err + + return self._serialize(data, data_type, **kwargs) + + def url(self, name, data, data_type, **kwargs): + """Serialize data intended for a URL path. + + :param str name: The name of the URL path parameter. + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str + :returns: The serialized URL path + :raises TypeError: if serialization fails. + :raises ValueError: if data is None + """ + try: + output = self.serialize_data(data, data_type, **kwargs) + if data_type == "bool": + output = json.dumps(output) + + if kwargs.get("skip_quote") is True: + output = str(output) + output = output.replace("{", quote("{")).replace("}", quote("}")) + else: + output = quote(str(output), safe="") + except SerializationError as exc: + raise TypeError("{} must be type {}.".format(name, data_type)) from exc + return output + + def query(self, name, data, data_type, **kwargs): + """Serialize data intended for a URL query. + + :param str name: The name of the query parameter. + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str, list + :raises TypeError: if serialization fails. + :raises ValueError: if data is None + :returns: The serialized query parameter + """ + try: + # Treat the list aside, since we don't want to encode the div separator + if data_type.startswith("["): + internal_data_type = data_type[1:-1] + do_quote = not kwargs.get("skip_quote", False) + return self.serialize_iter(data, internal_data_type, do_quote=do_quote, **kwargs) + + # Not a list, regular serialization + output = self.serialize_data(data, data_type, **kwargs) + if data_type == "bool": + output = json.dumps(output) + if kwargs.get("skip_quote") is True: + output = str(output) + else: + output = quote(str(output), safe="") + except SerializationError as exc: + raise TypeError("{} must be type {}.".format(name, data_type)) from exc + return str(output) + + def header(self, name, data, data_type, **kwargs): + """Serialize data intended for a request header. + + :param str name: The name of the header. + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str + :raises TypeError: if serialization fails. + :raises ValueError: if data is None + :returns: The serialized header + """ + try: + if data_type in ["[str]"]: + data = ["" if d is None else d for d in data] + + output = self.serialize_data(data, data_type, **kwargs) + if data_type == "bool": + output = json.dumps(output) + except SerializationError as exc: + raise TypeError("{} must be type {}.".format(name, data_type)) from exc + return str(output) + + def serialize_data(self, data, data_type, **kwargs): + """Serialize generic data according to supplied data type. + + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :raises AttributeError: if required data is None. + :raises ValueError: if data is None + :raises SerializationError: if serialization fails. + :returns: The serialized data. + :rtype: str, int, float, bool, dict, list + """ + if data is None: + raise ValueError("No value for given attribute") + + try: + if data is CoreNull: + return None + if data_type in self.basic_types.values(): + return self.serialize_basic(data, data_type, **kwargs) + + if data_type in self.serialize_type: + return self.serialize_type[data_type](data, **kwargs) + + # If dependencies is empty, try with current data class + # It has to be a subclass of Enum anyway + enum_type = self.dependencies.get(data_type, data.__class__) + if issubclass(enum_type, Enum): + return Serializer.serialize_enum(data, enum_obj=enum_type) + + iter_type = data_type[0] + data_type[-1] + if iter_type in self.serialize_type: + return self.serialize_type[iter_type](data, data_type[1:-1], **kwargs) + + except (ValueError, TypeError) as err: + msg = "Unable to serialize value: {!r} as type: {!r}." + raise SerializationError(msg.format(data, data_type)) from err + return self._serialize(data, **kwargs) + + @classmethod + def _get_custom_serializers(cls, data_type, **kwargs): # pylint: disable=inconsistent-return-statements + custom_serializer = kwargs.get("basic_types_serializers", {}).get(data_type) + if custom_serializer: + return custom_serializer + if kwargs.get("is_xml", False): + return cls._xml_basic_types_serializers.get(data_type) + + @classmethod + def serialize_basic(cls, data, data_type, **kwargs): + """Serialize basic builting data type. + Serializes objects to str, int, float or bool. + + Possible kwargs: + - basic_types_serializers dict[str, callable] : If set, use the callable as serializer + - is_xml bool : If set, use xml_basic_types_serializers + + :param obj data: Object to be serialized. + :param str data_type: Type of object in the iterable. + :rtype: str, int, float, bool + :return: serialized object + """ + custom_serializer = cls._get_custom_serializers(data_type, **kwargs) + if custom_serializer: + return custom_serializer(data) + if data_type == "str": + return cls.serialize_unicode(data) + return eval(data_type)(data) # nosec # pylint: disable=eval-used + + @classmethod + def serialize_unicode(cls, data): + """Special handling for serializing unicode strings in Py2. + Encode to UTF-8 if unicode, otherwise handle as a str. + + :param str data: Object to be serialized. + :rtype: str + :return: serialized object + """ + try: # If I received an enum, return its value + return data.value + except AttributeError: + pass + + try: + if isinstance(data, unicode): # type: ignore + # Don't change it, JSON and XML ElementTree are totally able + # to serialize correctly u'' strings + return data + except NameError: + return str(data) + return str(data) + + def serialize_iter(self, data, iter_type, div=None, **kwargs): + """Serialize iterable. + + Supported kwargs: + - serialization_ctxt dict : The current entry of _attribute_map, or same format. + serialization_ctxt['type'] should be same as data_type. + - is_xml bool : If set, serialize as XML + + :param list data: Object to be serialized. + :param str iter_type: Type of object in the iterable. + :param str div: If set, this str will be used to combine the elements + in the iterable into a combined string. Default is 'None'. + Defaults to False. + :rtype: list, str + :return: serialized iterable + """ + if isinstance(data, str): + raise SerializationError("Refuse str type as a valid iter type.") + + serialization_ctxt = kwargs.get("serialization_ctxt", {}) + is_xml = kwargs.get("is_xml", False) + + serialized = [] + for d in data: + try: + serialized.append(self.serialize_data(d, iter_type, **kwargs)) + except ValueError as err: + if isinstance(err, SerializationError): + raise + serialized.append(None) + + if kwargs.get("do_quote", False): + serialized = ["" if s is None else quote(str(s), safe="") for s in serialized] + + if div: + serialized = ["" if s is None else str(s) for s in serialized] + serialized = div.join(serialized) + + if "xml" in serialization_ctxt or is_xml: + # XML serialization is more complicated + xml_desc = serialization_ctxt.get("xml", {}) + xml_name = xml_desc.get("name") + if not xml_name: + xml_name = serialization_ctxt["key"] + + # Create a wrap node if necessary (use the fact that Element and list have "append") + is_wrapped = xml_desc.get("wrapped", False) + node_name = xml_desc.get("itemsName", xml_name) + if is_wrapped: + final_result = _create_xml_node(xml_name, xml_desc.get("prefix", None), xml_desc.get("ns", None)) + else: + final_result = [] + # All list elements to "local_node" + for el in serialized: + if isinstance(el, ET.Element): + el_node = el + else: + el_node = _create_xml_node(node_name, xml_desc.get("prefix", None), xml_desc.get("ns", None)) + if el is not None: # Otherwise it writes "None" :-p + el_node.text = str(el) + final_result.append(el_node) + return final_result + return serialized + + def serialize_dict(self, attr, dict_type, **kwargs): + """Serialize a dictionary of objects. + + :param dict attr: Object to be serialized. + :param str dict_type: Type of object in the dictionary. + :rtype: dict + :return: serialized dictionary + """ + serialization_ctxt = kwargs.get("serialization_ctxt", {}) + serialized = {} + for key, value in attr.items(): + try: + serialized[self.serialize_unicode(key)] = self.serialize_data(value, dict_type, **kwargs) + except ValueError as err: + if isinstance(err, SerializationError): + raise + serialized[self.serialize_unicode(key)] = None + + if "xml" in serialization_ctxt: + # XML serialization is more complicated + xml_desc = serialization_ctxt["xml"] + xml_name = xml_desc["name"] + + final_result = _create_xml_node(xml_name, xml_desc.get("prefix", None), xml_desc.get("ns", None)) + for key, value in serialized.items(): + ET.SubElement(final_result, key).text = value + return final_result + + return serialized + + def serialize_object(self, attr, **kwargs): # pylint: disable=too-many-return-statements + """Serialize a generic object. + This will be handled as a dictionary. If object passed in is not + a basic type (str, int, float, dict, list) it will simply be + cast to str. + + :param dict attr: Object to be serialized. + :rtype: dict or str + :return: serialized object + """ + if attr is None: + return None + if isinstance(attr, ET.Element): + return attr + obj_type = type(attr) + if obj_type in self.basic_types: + return self.serialize_basic(attr, self.basic_types[obj_type], **kwargs) + if obj_type is _long_type: + return self.serialize_long(attr) + if obj_type is str: + return self.serialize_unicode(attr) + if obj_type is datetime.datetime: + return self.serialize_iso(attr) + if obj_type is datetime.date: + return self.serialize_date(attr) + if obj_type is datetime.time: + return self.serialize_time(attr) + if obj_type is datetime.timedelta: + return self.serialize_duration(attr) + if obj_type is decimal.Decimal: + return self.serialize_decimal(attr) + + # If it's a model or I know this dependency, serialize as a Model + if obj_type in self.dependencies.values() or isinstance(attr, Model): + return self._serialize(attr) + + if obj_type == dict: + serialized = {} + for key, value in attr.items(): + try: + serialized[self.serialize_unicode(key)] = self.serialize_object(value, **kwargs) + except ValueError: + serialized[self.serialize_unicode(key)] = None + return serialized + + if obj_type == list: + serialized = [] + for obj in attr: + try: + serialized.append(self.serialize_object(obj, **kwargs)) + except ValueError: + pass + return serialized + return str(attr) + + @staticmethod + def serialize_enum(attr, enum_obj=None): + try: + result = attr.value + except AttributeError: + result = attr + try: + enum_obj(result) # type: ignore + return result + except ValueError as exc: + for enum_value in enum_obj: # type: ignore + if enum_value.value.lower() == str(attr).lower(): + return enum_value.value + error = "{!r} is not valid value for enum {!r}" + raise SerializationError(error.format(attr, enum_obj)) from exc + + @staticmethod + def serialize_bytearray(attr, **kwargs): # pylint: disable=unused-argument + """Serialize bytearray into base-64 string. + + :param str attr: Object to be serialized. + :rtype: str + :return: serialized base64 + """ + return b64encode(attr).decode() + + @staticmethod + def serialize_base64(attr, **kwargs): # pylint: disable=unused-argument + """Serialize str into base-64 string. + + :param str attr: Object to be serialized. + :rtype: str + :return: serialized base64 + """ + encoded = b64encode(attr).decode("ascii") + return encoded.strip("=").replace("+", "-").replace("/", "_") + + @staticmethod + def serialize_decimal(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Decimal object to float. + + :param decimal attr: Object to be serialized. + :rtype: float + :return: serialized decimal + """ + return float(attr) + + @staticmethod + def serialize_long(attr, **kwargs): # pylint: disable=unused-argument + """Serialize long (Py2) or int (Py3). + + :param int attr: Object to be serialized. + :rtype: int/long + :return: serialized long + """ + return _long_type(attr) + + @staticmethod + def serialize_date(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Date object into ISO-8601 formatted string. + + :param Date attr: Object to be serialized. + :rtype: str + :return: serialized date + """ + if isinstance(attr, str): + attr = isodate.parse_date(attr) + t = "{:04}-{:02}-{:02}".format(attr.year, attr.month, attr.day) + return t + + @staticmethod + def serialize_time(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Time object into ISO-8601 formatted string. + + :param datetime.time attr: Object to be serialized. + :rtype: str + :return: serialized time + """ + if isinstance(attr, str): + attr = isodate.parse_time(attr) + t = "{:02}:{:02}:{:02}".format(attr.hour, attr.minute, attr.second) + if attr.microsecond: + t += ".{:02}".format(attr.microsecond) + return t + + @staticmethod + def serialize_duration(attr, **kwargs): # pylint: disable=unused-argument + """Serialize TimeDelta object into ISO-8601 formatted string. + + :param TimeDelta attr: Object to be serialized. + :rtype: str + :return: serialized duration + """ + if isinstance(attr, str): + attr = isodate.parse_duration(attr) + return isodate.duration_isoformat(attr) + + @staticmethod + def serialize_rfc(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Datetime object into RFC-1123 formatted string. + + :param Datetime attr: Object to be serialized. + :rtype: str + :raises TypeError: if format invalid. + :return: serialized rfc + """ + try: + if not attr.tzinfo: + _LOGGER.warning("Datetime with no tzinfo will be considered UTC.") + utc = attr.utctimetuple() + except AttributeError as exc: + raise TypeError("RFC1123 object must be valid Datetime object.") from exc + + return "{}, {:02} {} {:04} {:02}:{:02}:{:02} GMT".format( + Serializer.days[utc.tm_wday], + utc.tm_mday, + Serializer.months[utc.tm_mon], + utc.tm_year, + utc.tm_hour, + utc.tm_min, + utc.tm_sec, + ) + + @staticmethod + def serialize_iso(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Datetime object into ISO-8601 formatted string. + + :param Datetime attr: Object to be serialized. + :rtype: str + :raises SerializationError: if format invalid. + :return: serialized iso + """ + if isinstance(attr, str): + attr = isodate.parse_datetime(attr) + try: + if not attr.tzinfo: + _LOGGER.warning("Datetime with no tzinfo will be considered UTC.") + utc = attr.utctimetuple() + if utc.tm_year > 9999 or utc.tm_year < 1: + raise OverflowError("Hit max or min date") + + microseconds = str(attr.microsecond).rjust(6, "0").rstrip("0").ljust(3, "0") + if microseconds: + microseconds = "." + microseconds + date = "{:04}-{:02}-{:02}T{:02}:{:02}:{:02}".format( + utc.tm_year, utc.tm_mon, utc.tm_mday, utc.tm_hour, utc.tm_min, utc.tm_sec + ) + return date + microseconds + "Z" + except (ValueError, OverflowError) as err: + msg = "Unable to serialize datetime object." + raise SerializationError(msg) from err + except AttributeError as err: + msg = "ISO-8601 object must be valid Datetime object." + raise TypeError(msg) from err + + @staticmethod + def serialize_unix(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Datetime object into IntTime format. + This is represented as seconds. + + :param Datetime attr: Object to be serialized. + :rtype: int + :raises SerializationError: if format invalid + :return: serialied unix + """ + if isinstance(attr, int): + return attr + try: + if not attr.tzinfo: + _LOGGER.warning("Datetime with no tzinfo will be considered UTC.") + return int(calendar.timegm(attr.utctimetuple())) + except AttributeError as exc: + raise TypeError("Unix time object must be valid Datetime object.") from exc + + +def rest_key_extractor(attr, attr_desc, data): # pylint: disable=unused-argument + key = attr_desc["key"] + working_data = data + + while "." in key: + # Need the cast, as for some reasons "split" is typed as list[str | Any] + dict_keys = cast(List[str], _FLATTEN.split(key)) + if len(dict_keys) == 1: + key = _decode_attribute_map_key(dict_keys[0]) + break + working_key = _decode_attribute_map_key(dict_keys[0]) + working_data = working_data.get(working_key, data) + if working_data is None: + # If at any point while following flatten JSON path see None, it means + # that all properties under are None as well + return None + key = ".".join(dict_keys[1:]) + + return working_data.get(key) + + +def rest_key_case_insensitive_extractor( # pylint: disable=unused-argument, inconsistent-return-statements + attr, attr_desc, data +): + key = attr_desc["key"] + working_data = data + + while "." in key: + dict_keys = _FLATTEN.split(key) + if len(dict_keys) == 1: + key = _decode_attribute_map_key(dict_keys[0]) + break + working_key = _decode_attribute_map_key(dict_keys[0]) + working_data = attribute_key_case_insensitive_extractor(working_key, None, working_data) + if working_data is None: + # If at any point while following flatten JSON path see None, it means + # that all properties under are None as well + return None + key = ".".join(dict_keys[1:]) + + if working_data: + return attribute_key_case_insensitive_extractor(key, None, working_data) + + +def last_rest_key_extractor(attr, attr_desc, data): # pylint: disable=unused-argument + """Extract the attribute in "data" based on the last part of the JSON path key. + + :param str attr: The attribute to extract + :param dict attr_desc: The attribute description + :param dict data: The data to extract from + :rtype: object + :returns: The extracted attribute + """ + key = attr_desc["key"] + dict_keys = _FLATTEN.split(key) + return attribute_key_extractor(dict_keys[-1], None, data) + + +def last_rest_key_case_insensitive_extractor(attr, attr_desc, data): # pylint: disable=unused-argument + """Extract the attribute in "data" based on the last part of the JSON path key. + + This is the case insensitive version of "last_rest_key_extractor" + :param str attr: The attribute to extract + :param dict attr_desc: The attribute description + :param dict data: The data to extract from + :rtype: object + :returns: The extracted attribute + """ + key = attr_desc["key"] + dict_keys = _FLATTEN.split(key) + return attribute_key_case_insensitive_extractor(dict_keys[-1], None, data) + + +def attribute_key_extractor(attr, _, data): + return data.get(attr) + + +def attribute_key_case_insensitive_extractor(attr, _, data): + found_key = None + lower_attr = attr.lower() + for key in data: + if lower_attr == key.lower(): + found_key = key + break + + return data.get(found_key) + + +def _extract_name_from_internal_type(internal_type): + """Given an internal type XML description, extract correct XML name with namespace. + + :param dict internal_type: An model type + :rtype: tuple + :returns: A tuple XML name + namespace dict + """ + internal_type_xml_map = getattr(internal_type, "_xml_map", {}) + xml_name = internal_type_xml_map.get("name", internal_type.__name__) + xml_ns = internal_type_xml_map.get("ns", None) + if xml_ns: + xml_name = "{{{}}}{}".format(xml_ns, xml_name) + return xml_name + + +def xml_key_extractor(attr, attr_desc, data): # pylint: disable=unused-argument,too-many-return-statements + if isinstance(data, dict): + return None + + # Test if this model is XML ready first + if not isinstance(data, ET.Element): + return None + + xml_desc = attr_desc.get("xml", {}) + xml_name = xml_desc.get("name", attr_desc["key"]) + + # Look for a children + is_iter_type = attr_desc["type"].startswith("[") + is_wrapped = xml_desc.get("wrapped", False) + internal_type = attr_desc.get("internalType", None) + internal_type_xml_map = getattr(internal_type, "_xml_map", {}) + + # Integrate namespace if necessary + xml_ns = xml_desc.get("ns", internal_type_xml_map.get("ns", None)) + if xml_ns: + xml_name = "{{{}}}{}".format(xml_ns, xml_name) + + # If it's an attribute, that's simple + if xml_desc.get("attr", False): + return data.get(xml_name) + + # If it's x-ms-text, that's simple too + if xml_desc.get("text", False): + return data.text + + # Scenario where I take the local name: + # - Wrapped node + # - Internal type is an enum (considered basic types) + # - Internal type has no XML/Name node + if is_wrapped or (internal_type and (issubclass(internal_type, Enum) or "name" not in internal_type_xml_map)): + children = data.findall(xml_name) + # If internal type has a local name and it's not a list, I use that name + elif not is_iter_type and internal_type and "name" in internal_type_xml_map: + xml_name = _extract_name_from_internal_type(internal_type) + children = data.findall(xml_name) + # That's an array + else: + if internal_type: # Complex type, ignore itemsName and use the complex type name + items_name = _extract_name_from_internal_type(internal_type) + else: + items_name = xml_desc.get("itemsName", xml_name) + children = data.findall(items_name) + + if len(children) == 0: + if is_iter_type: + if is_wrapped: + return None # is_wrapped no node, we want None + return [] # not wrapped, assume empty list + return None # Assume it's not there, maybe an optional node. + + # If is_iter_type and not wrapped, return all found children + if is_iter_type: + if not is_wrapped: + return children + # Iter and wrapped, should have found one node only (the wrap one) + if len(children) != 1: + raise DeserializationError( + "Tried to deserialize an array not wrapped, and found several nodes '{}'. Maybe you should declare this array as wrapped?".format( + xml_name + ) + ) + return list(children[0]) # Might be empty list and that's ok. + + # Here it's not a itertype, we should have found one element only or empty + if len(children) > 1: + raise DeserializationError("Find several XML '{}' where it was not expected".format(xml_name)) + return children[0] + + +class Deserializer: + """Response object model deserializer. + + :param dict classes: Class type dictionary for deserializing complex types. + :ivar list key_extractors: Ordered list of extractors to be used by this deserializer. + """ + + basic_types = {str: "str", int: "int", bool: "bool", float: "float"} + + valid_date = re.compile(r"\d{4}[-]\d{2}[-]\d{2}T\d{2}:\d{2}:\d{2}\.?\d*Z?[-+]?[\d{2}]?:?[\d{2}]?") + + def __init__(self, classes: Optional[Mapping[str, type]] = None) -> None: + self.deserialize_type = { + "iso-8601": Deserializer.deserialize_iso, + "rfc-1123": Deserializer.deserialize_rfc, + "unix-time": Deserializer.deserialize_unix, + "duration": Deserializer.deserialize_duration, + "date": Deserializer.deserialize_date, + "time": Deserializer.deserialize_time, + "decimal": Deserializer.deserialize_decimal, + "long": Deserializer.deserialize_long, + "bytearray": Deserializer.deserialize_bytearray, + "base64": Deserializer.deserialize_base64, + "object": self.deserialize_object, + "[]": self.deserialize_iter, + "{}": self.deserialize_dict, + } + self.deserialize_expected_types = { + "duration": (isodate.Duration, datetime.timedelta), + "iso-8601": (datetime.datetime), + } + self.dependencies: Dict[str, type] = dict(classes) if classes else {} + self.key_extractors = [rest_key_extractor, xml_key_extractor] + # Additional properties only works if the "rest_key_extractor" is used to + # extract the keys. Making it to work whatever the key extractor is too much + # complicated, with no real scenario for now. + # So adding a flag to disable additional properties detection. This flag should be + # used if your expect the deserialization to NOT come from a JSON REST syntax. + # Otherwise, result are unexpected + self.additional_properties_detection = True + + def __call__(self, target_obj, response_data, content_type=None): + """Call the deserializer to process a REST response. + + :param str target_obj: Target data type to deserialize to. + :param requests.Response response_data: REST response object. + :param str content_type: Swagger "produces" if available. + :raises DeserializationError: if deserialization fails. + :return: Deserialized object. + :rtype: object + """ + data = self._unpack_content(response_data, content_type) + return self._deserialize(target_obj, data) + + def _deserialize(self, target_obj, data): # pylint: disable=inconsistent-return-statements + """Call the deserializer on a model. + + Data needs to be already deserialized as JSON or XML ElementTree + + :param str target_obj: Target data type to deserialize to. + :param object data: Object to deserialize. + :raises DeserializationError: if deserialization fails. + :return: Deserialized object. + :rtype: object + """ + # This is already a model, go recursive just in case + if hasattr(data, "_attribute_map"): + constants = [name for name, config in getattr(data, "_validation", {}).items() if config.get("constant")] + try: + for attr, mapconfig in data._attribute_map.items(): # pylint: disable=protected-access + if attr in constants: + continue + value = getattr(data, attr) + if value is None: + continue + local_type = mapconfig["type"] + internal_data_type = local_type.strip("[]{}") + if internal_data_type not in self.dependencies or isinstance(internal_data_type, Enum): + continue + setattr(data, attr, self._deserialize(local_type, value)) + return data + except AttributeError: + return + + response, class_name = self._classify_target(target_obj, data) + + if isinstance(response, str): + return self.deserialize_data(data, response) + if isinstance(response, type) and issubclass(response, Enum): + return self.deserialize_enum(data, response) + + if data is None or data is CoreNull: + return data + try: + attributes = response._attribute_map # type: ignore # pylint: disable=protected-access + d_attrs = {} + for attr, attr_desc in attributes.items(): + # Check empty string. If it's not empty, someone has a real "additionalProperties"... + if attr == "additional_properties" and attr_desc["key"] == "": + continue + raw_value = None + # Enhance attr_desc with some dynamic data + attr_desc = attr_desc.copy() # Do a copy, do not change the real one + internal_data_type = attr_desc["type"].strip("[]{}") + if internal_data_type in self.dependencies: + attr_desc["internalType"] = self.dependencies[internal_data_type] + + for key_extractor in self.key_extractors: + found_value = key_extractor(attr, attr_desc, data) + if found_value is not None: + if raw_value is not None and raw_value != found_value: + msg = ( + "Ignoring extracted value '%s' from %s for key '%s'" + " (duplicate extraction, follow extractors order)" + ) + _LOGGER.warning(msg, found_value, key_extractor, attr) + continue + raw_value = found_value + + value = self.deserialize_data(raw_value, attr_desc["type"]) + d_attrs[attr] = value + except (AttributeError, TypeError, KeyError) as err: + msg = "Unable to deserialize to object: " + class_name # type: ignore + raise DeserializationError(msg) from err + additional_properties = self._build_additional_properties(attributes, data) + return self._instantiate_model(response, d_attrs, additional_properties) + + def _build_additional_properties(self, attribute_map, data): + if not self.additional_properties_detection: + return None + if "additional_properties" in attribute_map and attribute_map.get("additional_properties", {}).get("key") != "": + # Check empty string. If it's not empty, someone has a real "additionalProperties" + return None + if isinstance(data, ET.Element): + data = {el.tag: el.text for el in data} + + known_keys = { + _decode_attribute_map_key(_FLATTEN.split(desc["key"])[0]) + for desc in attribute_map.values() + if desc["key"] != "" + } + present_keys = set(data.keys()) + missing_keys = present_keys - known_keys + return {key: data[key] for key in missing_keys} + + def _classify_target(self, target, data): + """Check to see whether the deserialization target object can + be classified into a subclass. + Once classification has been determined, initialize object. + + :param str target: The target object type to deserialize to. + :param str/dict data: The response data to deserialize. + :return: The classified target object and its class name. + :rtype: tuple + """ + if target is None: + return None, None + + if isinstance(target, str): + try: + target = self.dependencies[target] + except KeyError: + return target, target + + try: + target = target._classify(data, self.dependencies) # type: ignore # pylint: disable=protected-access + except AttributeError: + pass # Target is not a Model, no classify + return target, target.__class__.__name__ # type: ignore + + def failsafe_deserialize(self, target_obj, data, content_type=None): + """Ignores any errors encountered in deserialization, + and falls back to not deserializing the object. Recommended + for use in error deserialization, as we want to return the + HttpResponseError to users, and not have them deal with + a deserialization error. + + :param str target_obj: The target object type to deserialize to. + :param str/dict data: The response data to deserialize. + :param str content_type: Swagger "produces" if available. + :return: Deserialized object. + :rtype: object + """ + try: + return self(target_obj, data, content_type=content_type) + except: # pylint: disable=bare-except + _LOGGER.debug( + "Ran into a deserialization error. Ignoring since this is failsafe deserialization", exc_info=True + ) + return None + + @staticmethod + def _unpack_content(raw_data, content_type=None): + """Extract the correct structure for deserialization. + + If raw_data is a PipelineResponse, try to extract the result of RawDeserializer. + if we can't, raise. Your Pipeline should have a RawDeserializer. + + If not a pipeline response and raw_data is bytes or string, use content-type + to decode it. If no content-type, try JSON. + + If raw_data is something else, bypass all logic and return it directly. + + :param obj raw_data: Data to be processed. + :param str content_type: How to parse if raw_data is a string/bytes. + :raises JSONDecodeError: If JSON is requested and parsing is impossible. + :raises UnicodeDecodeError: If bytes is not UTF8 + :rtype: object + :return: Unpacked content. + """ + # Assume this is enough to detect a Pipeline Response without importing it + context = getattr(raw_data, "context", {}) + if context: + if RawDeserializer.CONTEXT_NAME in context: + return context[RawDeserializer.CONTEXT_NAME] + raise ValueError("This pipeline didn't have the RawDeserializer policy; can't deserialize") + + # Assume this is enough to recognize universal_http.ClientResponse without importing it + if hasattr(raw_data, "body"): + return RawDeserializer.deserialize_from_http_generics(raw_data.text(), raw_data.headers) + + # Assume this enough to recognize requests.Response without importing it. + if hasattr(raw_data, "_content_consumed"): + return RawDeserializer.deserialize_from_http_generics(raw_data.text, raw_data.headers) + + if isinstance(raw_data, (str, bytes)) or hasattr(raw_data, "read"): + return RawDeserializer.deserialize_from_text(raw_data, content_type) # type: ignore + return raw_data + + def _instantiate_model(self, response, attrs, additional_properties=None): + """Instantiate a response model passing in deserialized args. + + :param Response response: The response model class. + :param dict attrs: The deserialized response attributes. + :param dict additional_properties: Additional properties to be set. + :rtype: Response + :return: The instantiated response model. + """ + if callable(response): + subtype = getattr(response, "_subtype_map", {}) + try: + readonly = [ + k + for k, v in response._validation.items() # pylint: disable=protected-access # type: ignore + if v.get("readonly") + ] + const = [ + k + for k, v in response._validation.items() # pylint: disable=protected-access # type: ignore + if v.get("constant") + ] + kwargs = {k: v for k, v in attrs.items() if k not in subtype and k not in readonly + const} + response_obj = response(**kwargs) + for attr in readonly: + setattr(response_obj, attr, attrs.get(attr)) + if additional_properties: + response_obj.additional_properties = additional_properties # type: ignore + return response_obj + except TypeError as err: + msg = "Unable to deserialize {} into model {}. ".format(kwargs, response) # type: ignore + raise DeserializationError(msg + str(err)) from err + else: + try: + for attr, value in attrs.items(): + setattr(response, attr, value) + return response + except Exception as exp: + msg = "Unable to populate response model. " + msg += "Type: {}, Error: {}".format(type(response), exp) + raise DeserializationError(msg) from exp + + def deserialize_data(self, data, data_type): # pylint: disable=too-many-return-statements + """Process data for deserialization according to data type. + + :param str data: The response string to be deserialized. + :param str data_type: The type to deserialize to. + :raises DeserializationError: if deserialization fails. + :return: Deserialized object. + :rtype: object + """ + if data is None: + return data + + try: + if not data_type: + return data + if data_type in self.basic_types.values(): + return self.deserialize_basic(data, data_type) + if data_type in self.deserialize_type: + if isinstance(data, self.deserialize_expected_types.get(data_type, tuple())): + return data + + is_a_text_parsing_type = lambda x: x not in [ # pylint: disable=unnecessary-lambda-assignment + "object", + "[]", + r"{}", + ] + if isinstance(data, ET.Element) and is_a_text_parsing_type(data_type) and not data.text: + return None + data_val = self.deserialize_type[data_type](data) + return data_val + + iter_type = data_type[0] + data_type[-1] + if iter_type in self.deserialize_type: + return self.deserialize_type[iter_type](data, data_type[1:-1]) + + obj_type = self.dependencies[data_type] + if issubclass(obj_type, Enum): + if isinstance(data, ET.Element): + data = data.text + return self.deserialize_enum(data, obj_type) + + except (ValueError, TypeError, AttributeError) as err: + msg = "Unable to deserialize response data." + msg += " Data: {}, {}".format(data, data_type) + raise DeserializationError(msg) from err + return self._deserialize(obj_type, data) + + def deserialize_iter(self, attr, iter_type): + """Deserialize an iterable. + + :param list attr: Iterable to be deserialized. + :param str iter_type: The type of object in the iterable. + :return: Deserialized iterable. + :rtype: list + """ + if attr is None: + return None + if isinstance(attr, ET.Element): # If I receive an element here, get the children + attr = list(attr) + if not isinstance(attr, (list, set)): + raise DeserializationError("Cannot deserialize as [{}] an object of type {}".format(iter_type, type(attr))) + return [self.deserialize_data(a, iter_type) for a in attr] + + def deserialize_dict(self, attr, dict_type): + """Deserialize a dictionary. + + :param dict/list attr: Dictionary to be deserialized. Also accepts + a list of key, value pairs. + :param str dict_type: The object type of the items in the dictionary. + :return: Deserialized dictionary. + :rtype: dict + """ + if isinstance(attr, list): + return {x["key"]: self.deserialize_data(x["value"], dict_type) for x in attr} + + if isinstance(attr, ET.Element): + # Transform value into {"Key": "value"} + attr = {el.tag: el.text for el in attr} + return {k: self.deserialize_data(v, dict_type) for k, v in attr.items()} + + def deserialize_object(self, attr, **kwargs): # pylint: disable=too-many-return-statements + """Deserialize a generic object. + This will be handled as a dictionary. + + :param dict attr: Dictionary to be deserialized. + :return: Deserialized object. + :rtype: dict + :raises TypeError: if non-builtin datatype encountered. + """ + if attr is None: + return None + if isinstance(attr, ET.Element): + # Do no recurse on XML, just return the tree as-is + return attr + if isinstance(attr, str): + return self.deserialize_basic(attr, "str") + obj_type = type(attr) + if obj_type in self.basic_types: + return self.deserialize_basic(attr, self.basic_types[obj_type]) + if obj_type is _long_type: + return self.deserialize_long(attr) + + if obj_type == dict: + deserialized = {} + for key, value in attr.items(): + try: + deserialized[key] = self.deserialize_object(value, **kwargs) + except ValueError: + deserialized[key] = None + return deserialized + + if obj_type == list: + deserialized = [] + for obj in attr: + try: + deserialized.append(self.deserialize_object(obj, **kwargs)) + except ValueError: + pass + return deserialized + + error = "Cannot deserialize generic object with type: " + raise TypeError(error + str(obj_type)) + + def deserialize_basic(self, attr, data_type): # pylint: disable=too-many-return-statements + """Deserialize basic builtin data type from string. + Will attempt to convert to str, int, float and bool. + This function will also accept '1', '0', 'true' and 'false' as + valid bool values. + + :param str attr: response string to be deserialized. + :param str data_type: deserialization data type. + :return: Deserialized basic type. + :rtype: str, int, float or bool + :raises TypeError: if string format is not valid. + """ + # If we're here, data is supposed to be a basic type. + # If it's still an XML node, take the text + if isinstance(attr, ET.Element): + attr = attr.text + if not attr: + if data_type == "str": + # None or '', node is empty string. + return "" + # None or '', node with a strong type is None. + # Don't try to model "empty bool" or "empty int" + return None + + if data_type == "bool": + if attr in [True, False, 1, 0]: + return bool(attr) + if isinstance(attr, str): + if attr.lower() in ["true", "1"]: + return True + if attr.lower() in ["false", "0"]: + return False + raise TypeError("Invalid boolean value: {}".format(attr)) + + if data_type == "str": + return self.deserialize_unicode(attr) + return eval(data_type)(attr) # nosec # pylint: disable=eval-used + + @staticmethod + def deserialize_unicode(data): + """Preserve unicode objects in Python 2, otherwise return data + as a string. + + :param str data: response string to be deserialized. + :return: Deserialized string. + :rtype: str or unicode + """ + # We might be here because we have an enum modeled as string, + # and we try to deserialize a partial dict with enum inside + if isinstance(data, Enum): + return data + + # Consider this is real string + try: + if isinstance(data, unicode): # type: ignore + return data + except NameError: + return str(data) + return str(data) + + @staticmethod + def deserialize_enum(data, enum_obj): + """Deserialize string into enum object. + + If the string is not a valid enum value it will be returned as-is + and a warning will be logged. + + :param str data: Response string to be deserialized. If this value is + None or invalid it will be returned as-is. + :param Enum enum_obj: Enum object to deserialize to. + :return: Deserialized enum object. + :rtype: Enum + """ + if isinstance(data, enum_obj) or data is None: + return data + if isinstance(data, Enum): + data = data.value + if isinstance(data, int): + # Workaround. We might consider remove it in the future. + try: + return list(enum_obj.__members__.values())[data] + except IndexError as exc: + error = "{!r} is not a valid index for enum {!r}" + raise DeserializationError(error.format(data, enum_obj)) from exc + try: + return enum_obj(str(data)) + except ValueError: + for enum_value in enum_obj: + if enum_value.value.lower() == str(data).lower(): + return enum_value + # We don't fail anymore for unknown value, we deserialize as a string + _LOGGER.warning("Deserializer is not able to find %s as valid enum in %s", data, enum_obj) + return Deserializer.deserialize_unicode(data) + + @staticmethod + def deserialize_bytearray(attr): + """Deserialize string into bytearray. + + :param str attr: response string to be deserialized. + :return: Deserialized bytearray + :rtype: bytearray + :raises TypeError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + return bytearray(b64decode(attr)) # type: ignore + + @staticmethod + def deserialize_base64(attr): + """Deserialize base64 encoded string into string. + + :param str attr: response string to be deserialized. + :return: Deserialized base64 string + :rtype: bytearray + :raises TypeError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + padding = "=" * (3 - (len(attr) + 3) % 4) # type: ignore + attr = attr + padding # type: ignore + encoded = attr.replace("-", "+").replace("_", "/") + return b64decode(encoded) + + @staticmethod + def deserialize_decimal(attr): + """Deserialize string into Decimal object. + + :param str attr: response string to be deserialized. + :return: Deserialized decimal + :raises DeserializationError: if string format invalid. + :rtype: decimal + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + return decimal.Decimal(str(attr)) # type: ignore + except decimal.DecimalException as err: + msg = "Invalid decimal {}".format(attr) + raise DeserializationError(msg) from err + + @staticmethod + def deserialize_long(attr): + """Deserialize string into long (Py2) or int (Py3). + + :param str attr: response string to be deserialized. + :return: Deserialized int + :rtype: long or int + :raises ValueError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + return _long_type(attr) # type: ignore + + @staticmethod + def deserialize_duration(attr): + """Deserialize ISO-8601 formatted string into TimeDelta object. + + :param str attr: response string to be deserialized. + :return: Deserialized duration + :rtype: TimeDelta + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + duration = isodate.parse_duration(attr) + except (ValueError, OverflowError, AttributeError) as err: + msg = "Cannot deserialize duration object." + raise DeserializationError(msg) from err + return duration + + @staticmethod + def deserialize_date(attr): + """Deserialize ISO-8601 formatted string into Date object. + + :param str attr: response string to be deserialized. + :return: Deserialized date + :rtype: Date + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + if re.search(r"[^\W\d_]", attr, re.I + re.U): # type: ignore + raise DeserializationError("Date must have only digits and -. Received: %s" % attr) + # This must NOT use defaultmonth/defaultday. Using None ensure this raises an exception. + return isodate.parse_date(attr, defaultmonth=0, defaultday=0) + + @staticmethod + def deserialize_time(attr): + """Deserialize ISO-8601 formatted string into time object. + + :param str attr: response string to be deserialized. + :return: Deserialized time + :rtype: datetime.time + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + if re.search(r"[^\W\d_]", attr, re.I + re.U): # type: ignore + raise DeserializationError("Date must have only digits and -. Received: %s" % attr) + return isodate.parse_time(attr) + + @staticmethod + def deserialize_rfc(attr): + """Deserialize RFC-1123 formatted string into Datetime object. + + :param str attr: response string to be deserialized. + :return: Deserialized RFC datetime + :rtype: Datetime + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + parsed_date = email.utils.parsedate_tz(attr) # type: ignore + date_obj = datetime.datetime( + *parsed_date[:6], tzinfo=datetime.timezone(datetime.timedelta(minutes=(parsed_date[9] or 0) / 60)) + ) + if not date_obj.tzinfo: + date_obj = date_obj.astimezone(tz=TZ_UTC) + except ValueError as err: + msg = "Cannot deserialize to rfc datetime object." + raise DeserializationError(msg) from err + return date_obj + + @staticmethod + def deserialize_iso(attr): + """Deserialize ISO-8601 formatted string into Datetime object. + + :param str attr: response string to be deserialized. + :return: Deserialized ISO datetime + :rtype: Datetime + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + attr = attr.upper() # type: ignore + match = Deserializer.valid_date.match(attr) + if not match: + raise ValueError("Invalid datetime string: " + attr) + + check_decimal = attr.split(".") + if len(check_decimal) > 1: + decimal_str = "" + for digit in check_decimal[1]: + if digit.isdigit(): + decimal_str += digit + else: + break + if len(decimal_str) > 6: + attr = attr.replace(decimal_str, decimal_str[0:6]) + + date_obj = isodate.parse_datetime(attr) + test_utc = date_obj.utctimetuple() + if test_utc.tm_year > 9999 or test_utc.tm_year < 1: + raise OverflowError("Hit max or min date") + except (ValueError, OverflowError, AttributeError) as err: + msg = "Cannot deserialize datetime object." + raise DeserializationError(msg) from err + return date_obj + + @staticmethod + def deserialize_unix(attr): + """Serialize Datetime object into IntTime format. + This is represented as seconds. + + :param int attr: Object to be serialized. + :return: Deserialized datetime + :rtype: Datetime + :raises DeserializationError: if format invalid + """ + if isinstance(attr, ET.Element): + attr = int(attr.text) # type: ignore + try: + attr = int(attr) + date_obj = datetime.datetime.fromtimestamp(attr, TZ_UTC) + except ValueError as err: + msg = "Cannot deserialize to unix datetime object." + raise DeserializationError(msg) from err + return date_obj diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ErrorWithSecretsVersionTolerant/errorwithsecretsversiontolerant/_utils/utils.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ErrorWithSecretsVersionTolerant/errorwithsecretsversiontolerant/_utils/utils.py new file mode 100644 index 00000000000..39b612f39a9 --- /dev/null +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ErrorWithSecretsVersionTolerant/errorwithsecretsversiontolerant/_utils/utils.py @@ -0,0 +1,25 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from abc import ABC +from typing import Generic, TYPE_CHECKING, TypeVar + +if TYPE_CHECKING: + from .serialization import Deserializer, Serializer + + +TClient = TypeVar("TClient") +TConfig = TypeVar("TConfig") + + +class ClientMixinABC(ABC, Generic[TClient, TConfig]): + """DO NOT use this class. It is for internal typing use only.""" + + _client: TClient + _config: TConfig + _serialize: "Serializer" + _deserialize: "Deserializer" diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ErrorWithSecretsVersionTolerant/errorwithsecretsversiontolerant/_vendor.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ErrorWithSecretsVersionTolerant/errorwithsecretsversiontolerant/_vendor.py deleted file mode 100644 index fb1aa891cce..00000000000 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ErrorWithSecretsVersionTolerant/errorwithsecretsversiontolerant/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) AutoRest Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import ErrorWithSecretsConfiguration - -if TYPE_CHECKING: - from azure.core import PipelineClient - - from ._serialization import Deserializer, Serializer - - -class ErrorWithSecretsMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "PipelineClient" - _config: ErrorWithSecretsConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ErrorWithSecretsVersionTolerant/errorwithsecretsversiontolerant/aio/_client.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ErrorWithSecretsVersionTolerant/errorwithsecretsversiontolerant/aio/_client.py index 4322727da4e..24112a9f97b 100644 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ErrorWithSecretsVersionTolerant/errorwithsecretsversiontolerant/aio/_client.py +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ErrorWithSecretsVersionTolerant/errorwithsecretsversiontolerant/aio/_client.py @@ -14,7 +14,7 @@ from azure.core.pipeline import policies from azure.core.rest import AsyncHttpResponse, HttpRequest -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import ErrorWithSecretsConfiguration from ._operations import ErrorWithSecretsOperationsMixin diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ErrorWithSecretsVersionTolerant/errorwithsecretsversiontolerant/aio/_operations/_operations.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ErrorWithSecretsVersionTolerant/errorwithsecretsversiontolerant/aio/_operations/_operations.py index ddf6a05a865..f57ecca6b39 100644 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ErrorWithSecretsVersionTolerant/errorwithsecretsversiontolerant/aio/_operations/_operations.py +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ErrorWithSecretsVersionTolerant/errorwithsecretsversiontolerant/aio/_operations/_operations.py @@ -9,6 +9,7 @@ from collections.abc import MutableMapping from typing import Any, Callable, Dict, Optional, TypeVar, cast +from azure.core import AsyncPipelineClient from azure.core.exceptions import ( ClientAuthenticationError, HttpResponseError, @@ -25,14 +26,15 @@ build_error_with_secrets_create_secret_request, build_error_with_secrets_get_error_with_secrets_request, ) -from .._vendor import ErrorWithSecretsMixinABC +from ..._utils.utils import ClientMixinABC +from .._configuration import ErrorWithSecretsConfiguration JSON = MutableMapping[str, Any] T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, AsyncHttpResponse], T, Dict[str, Any]], Any]] -class ErrorWithSecretsOperationsMixin(ErrorWithSecretsMixinABC): +class ErrorWithSecretsOperationsMixin(ClientMixinABC[AsyncPipelineClient, ErrorWithSecretsConfiguration]): @distributed_trace_async async def create_secret(self, **kwargs: Any) -> JSON: diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ErrorWithSecretsVersionTolerant/errorwithsecretsversiontolerant/aio/_vendor.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ErrorWithSecretsVersionTolerant/errorwithsecretsversiontolerant/aio/_vendor.py deleted file mode 100644 index e000cbd9842..00000000000 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ErrorWithSecretsVersionTolerant/errorwithsecretsversiontolerant/aio/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) AutoRest Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import ErrorWithSecretsConfiguration - -if TYPE_CHECKING: - from azure.core import AsyncPipelineClient - - from .._serialization import Deserializer, Serializer - - -class ErrorWithSecretsMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "AsyncPipelineClient" - _config: ErrorWithSecretsConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ExtensibleEnumsVersionTolerant/extensibleenumsswaggerversiontolerant/_client.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ExtensibleEnumsVersionTolerant/extensibleenumsswaggerversiontolerant/_client.py index f179051440b..b086b90cbae 100644 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ExtensibleEnumsVersionTolerant/extensibleenumsswaggerversiontolerant/_client.py +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ExtensibleEnumsVersionTolerant/extensibleenumsswaggerversiontolerant/_client.py @@ -15,7 +15,7 @@ from azure.core.rest import HttpRequest, HttpResponse from ._configuration import PetStoreIncConfiguration -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer from .operations import PetOperations diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ExtensibleEnumsVersionTolerant/extensibleenumsswaggerversiontolerant/_utils/__init__.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ExtensibleEnumsVersionTolerant/extensibleenumsswaggerversiontolerant/_utils/__init__.py new file mode 100644 index 00000000000..0af9b28f660 --- /dev/null +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ExtensibleEnumsVersionTolerant/extensibleenumsswaggerversiontolerant/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ExtensibleEnumsVersionTolerant/extensibleenumsswaggerversiontolerant/_utils/serialization.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ExtensibleEnumsVersionTolerant/extensibleenumsswaggerversiontolerant/_utils/serialization.py new file mode 100644 index 00000000000..f5187701d7b --- /dev/null +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ExtensibleEnumsVersionTolerant/extensibleenumsswaggerversiontolerant/_utils/serialization.py @@ -0,0 +1,2032 @@ +# pylint: disable=line-too-long,useless-suppression,too-many-lines +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +# pyright: reportUnnecessaryTypeIgnoreComment=false + +from base64 import b64decode, b64encode +import calendar +import datetime +import decimal +import email +from enum import Enum +import json +import logging +import re +import sys +import codecs +from typing import ( + Dict, + Any, + cast, + Optional, + Union, + AnyStr, + IO, + Mapping, + Callable, + MutableMapping, + List, +) + +try: + from urllib import quote # type: ignore +except ImportError: + from urllib.parse import quote +import xml.etree.ElementTree as ET + +import isodate # type: ignore +from typing_extensions import Self + +from azure.core.exceptions import DeserializationError, SerializationError +from azure.core.serialization import NULL as CoreNull + +_BOM = codecs.BOM_UTF8.decode(encoding="utf-8") + +JSON = MutableMapping[str, Any] + + +class RawDeserializer: + + # Accept "text" because we're open minded people... + JSON_REGEXP = re.compile(r"^(application|text)/([a-z+.]+\+)?json$") + + # Name used in context + CONTEXT_NAME = "deserialized_data" + + @classmethod + def deserialize_from_text(cls, data: Optional[Union[AnyStr, IO]], content_type: Optional[str] = None) -> Any: + """Decode data according to content-type. + + Accept a stream of data as well, but will be load at once in memory for now. + + If no content-type, will return the string version (not bytes, not stream) + + :param data: Input, could be bytes or stream (will be decoded with UTF8) or text + :type data: str or bytes or IO + :param str content_type: The content type. + :return: The deserialized data. + :rtype: object + """ + if hasattr(data, "read"): + # Assume a stream + data = cast(IO, data).read() + + if isinstance(data, bytes): + data_as_str = data.decode(encoding="utf-8-sig") + else: + # Explain to mypy the correct type. + data_as_str = cast(str, data) + + # Remove Byte Order Mark if present in string + data_as_str = data_as_str.lstrip(_BOM) + + if content_type is None: + return data + + if cls.JSON_REGEXP.match(content_type): + try: + return json.loads(data_as_str) + except ValueError as err: + raise DeserializationError("JSON is invalid: {}".format(err), err) from err + elif "xml" in (content_type or []): + try: + + try: + if isinstance(data, unicode): # type: ignore + # If I'm Python 2.7 and unicode XML will scream if I try a "fromstring" on unicode string + data_as_str = data_as_str.encode(encoding="utf-8") # type: ignore + except NameError: + pass + + return ET.fromstring(data_as_str) # nosec + except ET.ParseError as err: + # It might be because the server has an issue, and returned JSON with + # content-type XML.... + # So let's try a JSON load, and if it's still broken + # let's flow the initial exception + def _json_attemp(data): + try: + return True, json.loads(data) + except ValueError: + return False, None # Don't care about this one + + success, json_result = _json_attemp(data) + if success: + return json_result + # If i'm here, it's not JSON, it's not XML, let's scream + # and raise the last context in this block (the XML exception) + # The function hack is because Py2.7 messes up with exception + # context otherwise. + _LOGGER.critical("Wasn't XML not JSON, failing") + raise DeserializationError("XML is invalid") from err + elif content_type.startswith("text/"): + return data_as_str + raise DeserializationError("Cannot deserialize content-type: {}".format(content_type)) + + @classmethod + def deserialize_from_http_generics(cls, body_bytes: Optional[Union[AnyStr, IO]], headers: Mapping) -> Any: + """Deserialize from HTTP response. + + Use bytes and headers to NOT use any requests/aiohttp or whatever + specific implementation. + Headers will tested for "content-type" + + :param bytes body_bytes: The body of the response. + :param dict headers: The headers of the response. + :returns: The deserialized data. + :rtype: object + """ + # Try to use content-type from headers if available + content_type = None + if "content-type" in headers: + content_type = headers["content-type"].split(";")[0].strip().lower() + # Ouch, this server did not declare what it sent... + # Let's guess it's JSON... + # Also, since Autorest was considering that an empty body was a valid JSON, + # need that test as well.... + else: + content_type = "application/json" + + if body_bytes: + return cls.deserialize_from_text(body_bytes, content_type) + return None + + +_LOGGER = logging.getLogger(__name__) + +try: + _long_type = long # type: ignore +except NameError: + _long_type = int + +TZ_UTC = datetime.timezone.utc + +_FLATTEN = re.compile(r"(? None: + self.additional_properties: Optional[Dict[str, Any]] = {} + for k in kwargs: # pylint: disable=consider-using-dict-items + if k not in self._attribute_map: + _LOGGER.warning("%s is not a known attribute of class %s and will be ignored", k, self.__class__) + elif k in self._validation and self._validation[k].get("readonly", False): + _LOGGER.warning("Readonly attribute %s will be ignored in class %s", k, self.__class__) + else: + setattr(self, k, kwargs[k]) + + def __eq__(self, other: Any) -> bool: + """Compare objects by comparing all attributes. + + :param object other: The object to compare + :returns: True if objects are equal + :rtype: bool + """ + if isinstance(other, self.__class__): + return self.__dict__ == other.__dict__ + return False + + def __ne__(self, other: Any) -> bool: + """Compare objects by comparing all attributes. + + :param object other: The object to compare + :returns: True if objects are not equal + :rtype: bool + """ + return not self.__eq__(other) + + def __str__(self) -> str: + return str(self.__dict__) + + @classmethod + def enable_additional_properties_sending(cls) -> None: + cls._attribute_map["additional_properties"] = {"key": "", "type": "{object}"} + + @classmethod + def is_xml_model(cls) -> bool: + try: + cls._xml_map # type: ignore + except AttributeError: + return False + return True + + @classmethod + def _create_xml_node(cls): + """Create XML node. + + :returns: The XML node + :rtype: xml.etree.ElementTree.Element + """ + try: + xml_map = cls._xml_map # type: ignore + except AttributeError: + xml_map = {} + + return _create_xml_node(xml_map.get("name", cls.__name__), xml_map.get("prefix", None), xml_map.get("ns", None)) + + def serialize(self, keep_readonly: bool = False, **kwargs: Any) -> JSON: + """Return the JSON that would be sent to server from this model. + + This is an alias to `as_dict(full_restapi_key_transformer, keep_readonly=False)`. + + If you want XML serialization, you can pass the kwargs is_xml=True. + + :param bool keep_readonly: If you want to serialize the readonly attributes + :returns: A dict JSON compatible object + :rtype: dict + """ + serializer = Serializer(self._infer_class_models()) + return serializer._serialize( # type: ignore # pylint: disable=protected-access + self, keep_readonly=keep_readonly, **kwargs + ) + + def as_dict( + self, + keep_readonly: bool = True, + key_transformer: Callable[[str, Dict[str, Any], Any], Any] = attribute_transformer, + **kwargs: Any + ) -> JSON: + """Return a dict that can be serialized using json.dump. + + Advanced usage might optionally use a callback as parameter: + + .. code::python + + def my_key_transformer(key, attr_desc, value): + return key + + Key is the attribute name used in Python. Attr_desc + is a dict of metadata. Currently contains 'type' with the + msrest type and 'key' with the RestAPI encoded key. + Value is the current value in this object. + + The string returned will be used to serialize the key. + If the return type is a list, this is considered hierarchical + result dict. + + See the three examples in this file: + + - attribute_transformer + - full_restapi_key_transformer + - last_restapi_key_transformer + + If you want XML serialization, you can pass the kwargs is_xml=True. + + :param bool keep_readonly: If you want to serialize the readonly attributes + :param function key_transformer: A key transformer function. + :returns: A dict JSON compatible object + :rtype: dict + """ + serializer = Serializer(self._infer_class_models()) + return serializer._serialize( # type: ignore # pylint: disable=protected-access + self, key_transformer=key_transformer, keep_readonly=keep_readonly, **kwargs + ) + + @classmethod + def _infer_class_models(cls): + try: + str_models = cls.__module__.rsplit(".", 1)[0] + models = sys.modules[str_models] + client_models = {k: v for k, v in models.__dict__.items() if isinstance(v, type)} + if cls.__name__ not in client_models: + raise ValueError("Not Autorest generated code") + except Exception: # pylint: disable=broad-exception-caught + # Assume it's not Autorest generated (tests?). Add ourselves as dependencies. + client_models = {cls.__name__: cls} + return client_models + + @classmethod + def deserialize(cls, data: Any, content_type: Optional[str] = None) -> Self: + """Parse a str using the RestAPI syntax and return a model. + + :param str data: A str using RestAPI structure. JSON by default. + :param str content_type: JSON by default, set application/xml if XML. + :returns: An instance of this model + :raises DeserializationError: if something went wrong + :rtype: Self + """ + deserializer = Deserializer(cls._infer_class_models()) + return deserializer(cls.__name__, data, content_type=content_type) # type: ignore + + @classmethod + def from_dict( + cls, + data: Any, + key_extractors: Optional[Callable[[str, Dict[str, Any], Any], Any]] = None, + content_type: Optional[str] = None, + ) -> Self: + """Parse a dict using given key extractor return a model. + + By default consider key + extractors (rest_key_case_insensitive_extractor, attribute_key_case_insensitive_extractor + and last_rest_key_case_insensitive_extractor) + + :param dict data: A dict using RestAPI structure + :param function key_extractors: A key extractor function. + :param str content_type: JSON by default, set application/xml if XML. + :returns: An instance of this model + :raises DeserializationError: if something went wrong + :rtype: Self + """ + deserializer = Deserializer(cls._infer_class_models()) + deserializer.key_extractors = ( # type: ignore + [ # type: ignore + attribute_key_case_insensitive_extractor, + rest_key_case_insensitive_extractor, + last_rest_key_case_insensitive_extractor, + ] + if key_extractors is None + else key_extractors + ) + return deserializer(cls.__name__, data, content_type=content_type) # type: ignore + + @classmethod + def _flatten_subtype(cls, key, objects): + if "_subtype_map" not in cls.__dict__: + return {} + result = dict(cls._subtype_map[key]) + for valuetype in cls._subtype_map[key].values(): + result.update(objects[valuetype]._flatten_subtype(key, objects)) # pylint: disable=protected-access + return result + + @classmethod + def _classify(cls, response, objects): + """Check the class _subtype_map for any child classes. + We want to ignore any inherited _subtype_maps. + + :param dict response: The initial data + :param dict objects: The class objects + :returns: The class to be used + :rtype: class + """ + for subtype_key in cls.__dict__.get("_subtype_map", {}).keys(): + subtype_value = None + + if not isinstance(response, ET.Element): + rest_api_response_key = cls._get_rest_key_parts(subtype_key)[-1] + subtype_value = response.get(rest_api_response_key, None) or response.get(subtype_key, None) + else: + subtype_value = xml_key_extractor(subtype_key, cls._attribute_map[subtype_key], response) + if subtype_value: + # Try to match base class. Can be class name only + # (bug to fix in Autorest to support x-ms-discriminator-name) + if cls.__name__ == subtype_value: + return cls + flatten_mapping_type = cls._flatten_subtype(subtype_key, objects) + try: + return objects[flatten_mapping_type[subtype_value]] # type: ignore + except KeyError: + _LOGGER.warning( + "Subtype value %s has no mapping, use base class %s.", + subtype_value, + cls.__name__, + ) + break + else: + _LOGGER.warning("Discriminator %s is absent or null, use base class %s.", subtype_key, cls.__name__) + break + return cls + + @classmethod + def _get_rest_key_parts(cls, attr_key): + """Get the RestAPI key of this attr, split it and decode part + :param str attr_key: Attribute key must be in attribute_map. + :returns: A list of RestAPI part + :rtype: list + """ + rest_split_key = _FLATTEN.split(cls._attribute_map[attr_key]["key"]) + return [_decode_attribute_map_key(key_part) for key_part in rest_split_key] + + +def _decode_attribute_map_key(key): + """This decode a key in an _attribute_map to the actual key we want to look at + inside the received data. + + :param str key: A key string from the generated code + :returns: The decoded key + :rtype: str + """ + return key.replace("\\.", ".") + + +class Serializer: # pylint: disable=too-many-public-methods + """Request object model serializer.""" + + basic_types = {str: "str", int: "int", bool: "bool", float: "float"} + + _xml_basic_types_serializers = {"bool": lambda x: str(x).lower()} + days = {0: "Mon", 1: "Tue", 2: "Wed", 3: "Thu", 4: "Fri", 5: "Sat", 6: "Sun"} + months = { + 1: "Jan", + 2: "Feb", + 3: "Mar", + 4: "Apr", + 5: "May", + 6: "Jun", + 7: "Jul", + 8: "Aug", + 9: "Sep", + 10: "Oct", + 11: "Nov", + 12: "Dec", + } + validation = { + "min_length": lambda x, y: len(x) < y, + "max_length": lambda x, y: len(x) > y, + "minimum": lambda x, y: x < y, + "maximum": lambda x, y: x > y, + "minimum_ex": lambda x, y: x <= y, + "maximum_ex": lambda x, y: x >= y, + "min_items": lambda x, y: len(x) < y, + "max_items": lambda x, y: len(x) > y, + "pattern": lambda x, y: not re.match(y, x, re.UNICODE), + "unique": lambda x, y: len(x) != len(set(x)), + "multiple": lambda x, y: x % y != 0, + } + + def __init__(self, classes: Optional[Mapping[str, type]] = None) -> None: + self.serialize_type = { + "iso-8601": Serializer.serialize_iso, + "rfc-1123": Serializer.serialize_rfc, + "unix-time": Serializer.serialize_unix, + "duration": Serializer.serialize_duration, + "date": Serializer.serialize_date, + "time": Serializer.serialize_time, + "decimal": Serializer.serialize_decimal, + "long": Serializer.serialize_long, + "bytearray": Serializer.serialize_bytearray, + "base64": Serializer.serialize_base64, + "object": self.serialize_object, + "[]": self.serialize_iter, + "{}": self.serialize_dict, + } + self.dependencies: Dict[str, type] = dict(classes) if classes else {} + self.key_transformer = full_restapi_key_transformer + self.client_side_validation = True + + def _serialize( # pylint: disable=too-many-nested-blocks, too-many-branches, too-many-statements, too-many-locals + self, target_obj, data_type=None, **kwargs + ): + """Serialize data into a string according to type. + + :param object target_obj: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str, dict + :raises SerializationError: if serialization fails. + :returns: The serialized data. + """ + key_transformer = kwargs.get("key_transformer", self.key_transformer) + keep_readonly = kwargs.get("keep_readonly", False) + if target_obj is None: + return None + + attr_name = None + class_name = target_obj.__class__.__name__ + + if data_type: + return self.serialize_data(target_obj, data_type, **kwargs) + + if not hasattr(target_obj, "_attribute_map"): + data_type = type(target_obj).__name__ + if data_type in self.basic_types.values(): + return self.serialize_data(target_obj, data_type, **kwargs) + + # Force "is_xml" kwargs if we detect a XML model + try: + is_xml_model_serialization = kwargs["is_xml"] + except KeyError: + is_xml_model_serialization = kwargs.setdefault("is_xml", target_obj.is_xml_model()) + + serialized = {} + if is_xml_model_serialization: + serialized = target_obj._create_xml_node() # pylint: disable=protected-access + try: + attributes = target_obj._attribute_map # pylint: disable=protected-access + for attr, attr_desc in attributes.items(): + attr_name = attr + if not keep_readonly and target_obj._validation.get( # pylint: disable=protected-access + attr_name, {} + ).get("readonly", False): + continue + + if attr_name == "additional_properties" and attr_desc["key"] == "": + if target_obj.additional_properties is not None: + serialized.update(target_obj.additional_properties) + continue + try: + + orig_attr = getattr(target_obj, attr) + if is_xml_model_serialization: + pass # Don't provide "transformer" for XML for now. Keep "orig_attr" + else: # JSON + keys, orig_attr = key_transformer(attr, attr_desc.copy(), orig_attr) + keys = keys if isinstance(keys, list) else [keys] + + kwargs["serialization_ctxt"] = attr_desc + new_attr = self.serialize_data(orig_attr, attr_desc["type"], **kwargs) + + if is_xml_model_serialization: + xml_desc = attr_desc.get("xml", {}) + xml_name = xml_desc.get("name", attr_desc["key"]) + xml_prefix = xml_desc.get("prefix", None) + xml_ns = xml_desc.get("ns", None) + if xml_desc.get("attr", False): + if xml_ns: + ET.register_namespace(xml_prefix, xml_ns) + xml_name = "{{{}}}{}".format(xml_ns, xml_name) + serialized.set(xml_name, new_attr) # type: ignore + continue + if xml_desc.get("text", False): + serialized.text = new_attr # type: ignore + continue + if isinstance(new_attr, list): + serialized.extend(new_attr) # type: ignore + elif isinstance(new_attr, ET.Element): + # If the down XML has no XML/Name, + # we MUST replace the tag with the local tag. But keeping the namespaces. + if "name" not in getattr(orig_attr, "_xml_map", {}): + splitted_tag = new_attr.tag.split("}") + if len(splitted_tag) == 2: # Namespace + new_attr.tag = "}".join([splitted_tag[0], xml_name]) + else: + new_attr.tag = xml_name + serialized.append(new_attr) # type: ignore + else: # That's a basic type + # Integrate namespace if necessary + local_node = _create_xml_node(xml_name, xml_prefix, xml_ns) + local_node.text = str(new_attr) + serialized.append(local_node) # type: ignore + else: # JSON + for k in reversed(keys): # type: ignore + new_attr = {k: new_attr} + + _new_attr = new_attr + _serialized = serialized + for k in keys: # type: ignore + if k not in _serialized: + _serialized.update(_new_attr) # type: ignore + _new_attr = _new_attr[k] # type: ignore + _serialized = _serialized[k] + except ValueError as err: + if isinstance(err, SerializationError): + raise + + except (AttributeError, KeyError, TypeError) as err: + msg = "Attribute {} in object {} cannot be serialized.\n{}".format(attr_name, class_name, str(target_obj)) + raise SerializationError(msg) from err + return serialized + + def body(self, data, data_type, **kwargs): + """Serialize data intended for a request body. + + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: dict + :raises SerializationError: if serialization fails. + :raises ValueError: if data is None + :returns: The serialized request body + """ + + # Just in case this is a dict + internal_data_type_str = data_type.strip("[]{}") + internal_data_type = self.dependencies.get(internal_data_type_str, None) + try: + is_xml_model_serialization = kwargs["is_xml"] + except KeyError: + if internal_data_type and issubclass(internal_data_type, Model): + is_xml_model_serialization = kwargs.setdefault("is_xml", internal_data_type.is_xml_model()) + else: + is_xml_model_serialization = False + if internal_data_type and not isinstance(internal_data_type, Enum): + try: + deserializer = Deserializer(self.dependencies) + # Since it's on serialization, it's almost sure that format is not JSON REST + # We're not able to deal with additional properties for now. + deserializer.additional_properties_detection = False + if is_xml_model_serialization: + deserializer.key_extractors = [ # type: ignore + attribute_key_case_insensitive_extractor, + ] + else: + deserializer.key_extractors = [ + rest_key_case_insensitive_extractor, + attribute_key_case_insensitive_extractor, + last_rest_key_case_insensitive_extractor, + ] + data = deserializer._deserialize(data_type, data) # pylint: disable=protected-access + except DeserializationError as err: + raise SerializationError("Unable to build a model: " + str(err)) from err + + return self._serialize(data, data_type, **kwargs) + + def url(self, name, data, data_type, **kwargs): + """Serialize data intended for a URL path. + + :param str name: The name of the URL path parameter. + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str + :returns: The serialized URL path + :raises TypeError: if serialization fails. + :raises ValueError: if data is None + """ + try: + output = self.serialize_data(data, data_type, **kwargs) + if data_type == "bool": + output = json.dumps(output) + + if kwargs.get("skip_quote") is True: + output = str(output) + output = output.replace("{", quote("{")).replace("}", quote("}")) + else: + output = quote(str(output), safe="") + except SerializationError as exc: + raise TypeError("{} must be type {}.".format(name, data_type)) from exc + return output + + def query(self, name, data, data_type, **kwargs): + """Serialize data intended for a URL query. + + :param str name: The name of the query parameter. + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str, list + :raises TypeError: if serialization fails. + :raises ValueError: if data is None + :returns: The serialized query parameter + """ + try: + # Treat the list aside, since we don't want to encode the div separator + if data_type.startswith("["): + internal_data_type = data_type[1:-1] + do_quote = not kwargs.get("skip_quote", False) + return self.serialize_iter(data, internal_data_type, do_quote=do_quote, **kwargs) + + # Not a list, regular serialization + output = self.serialize_data(data, data_type, **kwargs) + if data_type == "bool": + output = json.dumps(output) + if kwargs.get("skip_quote") is True: + output = str(output) + else: + output = quote(str(output), safe="") + except SerializationError as exc: + raise TypeError("{} must be type {}.".format(name, data_type)) from exc + return str(output) + + def header(self, name, data, data_type, **kwargs): + """Serialize data intended for a request header. + + :param str name: The name of the header. + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str + :raises TypeError: if serialization fails. + :raises ValueError: if data is None + :returns: The serialized header + """ + try: + if data_type in ["[str]"]: + data = ["" if d is None else d for d in data] + + output = self.serialize_data(data, data_type, **kwargs) + if data_type == "bool": + output = json.dumps(output) + except SerializationError as exc: + raise TypeError("{} must be type {}.".format(name, data_type)) from exc + return str(output) + + def serialize_data(self, data, data_type, **kwargs): + """Serialize generic data according to supplied data type. + + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :raises AttributeError: if required data is None. + :raises ValueError: if data is None + :raises SerializationError: if serialization fails. + :returns: The serialized data. + :rtype: str, int, float, bool, dict, list + """ + if data is None: + raise ValueError("No value for given attribute") + + try: + if data is CoreNull: + return None + if data_type in self.basic_types.values(): + return self.serialize_basic(data, data_type, **kwargs) + + if data_type in self.serialize_type: + return self.serialize_type[data_type](data, **kwargs) + + # If dependencies is empty, try with current data class + # It has to be a subclass of Enum anyway + enum_type = self.dependencies.get(data_type, data.__class__) + if issubclass(enum_type, Enum): + return Serializer.serialize_enum(data, enum_obj=enum_type) + + iter_type = data_type[0] + data_type[-1] + if iter_type in self.serialize_type: + return self.serialize_type[iter_type](data, data_type[1:-1], **kwargs) + + except (ValueError, TypeError) as err: + msg = "Unable to serialize value: {!r} as type: {!r}." + raise SerializationError(msg.format(data, data_type)) from err + return self._serialize(data, **kwargs) + + @classmethod + def _get_custom_serializers(cls, data_type, **kwargs): # pylint: disable=inconsistent-return-statements + custom_serializer = kwargs.get("basic_types_serializers", {}).get(data_type) + if custom_serializer: + return custom_serializer + if kwargs.get("is_xml", False): + return cls._xml_basic_types_serializers.get(data_type) + + @classmethod + def serialize_basic(cls, data, data_type, **kwargs): + """Serialize basic builting data type. + Serializes objects to str, int, float or bool. + + Possible kwargs: + - basic_types_serializers dict[str, callable] : If set, use the callable as serializer + - is_xml bool : If set, use xml_basic_types_serializers + + :param obj data: Object to be serialized. + :param str data_type: Type of object in the iterable. + :rtype: str, int, float, bool + :return: serialized object + """ + custom_serializer = cls._get_custom_serializers(data_type, **kwargs) + if custom_serializer: + return custom_serializer(data) + if data_type == "str": + return cls.serialize_unicode(data) + return eval(data_type)(data) # nosec # pylint: disable=eval-used + + @classmethod + def serialize_unicode(cls, data): + """Special handling for serializing unicode strings in Py2. + Encode to UTF-8 if unicode, otherwise handle as a str. + + :param str data: Object to be serialized. + :rtype: str + :return: serialized object + """ + try: # If I received an enum, return its value + return data.value + except AttributeError: + pass + + try: + if isinstance(data, unicode): # type: ignore + # Don't change it, JSON and XML ElementTree are totally able + # to serialize correctly u'' strings + return data + except NameError: + return str(data) + return str(data) + + def serialize_iter(self, data, iter_type, div=None, **kwargs): + """Serialize iterable. + + Supported kwargs: + - serialization_ctxt dict : The current entry of _attribute_map, or same format. + serialization_ctxt['type'] should be same as data_type. + - is_xml bool : If set, serialize as XML + + :param list data: Object to be serialized. + :param str iter_type: Type of object in the iterable. + :param str div: If set, this str will be used to combine the elements + in the iterable into a combined string. Default is 'None'. + Defaults to False. + :rtype: list, str + :return: serialized iterable + """ + if isinstance(data, str): + raise SerializationError("Refuse str type as a valid iter type.") + + serialization_ctxt = kwargs.get("serialization_ctxt", {}) + is_xml = kwargs.get("is_xml", False) + + serialized = [] + for d in data: + try: + serialized.append(self.serialize_data(d, iter_type, **kwargs)) + except ValueError as err: + if isinstance(err, SerializationError): + raise + serialized.append(None) + + if kwargs.get("do_quote", False): + serialized = ["" if s is None else quote(str(s), safe="") for s in serialized] + + if div: + serialized = ["" if s is None else str(s) for s in serialized] + serialized = div.join(serialized) + + if "xml" in serialization_ctxt or is_xml: + # XML serialization is more complicated + xml_desc = serialization_ctxt.get("xml", {}) + xml_name = xml_desc.get("name") + if not xml_name: + xml_name = serialization_ctxt["key"] + + # Create a wrap node if necessary (use the fact that Element and list have "append") + is_wrapped = xml_desc.get("wrapped", False) + node_name = xml_desc.get("itemsName", xml_name) + if is_wrapped: + final_result = _create_xml_node(xml_name, xml_desc.get("prefix", None), xml_desc.get("ns", None)) + else: + final_result = [] + # All list elements to "local_node" + for el in serialized: + if isinstance(el, ET.Element): + el_node = el + else: + el_node = _create_xml_node(node_name, xml_desc.get("prefix", None), xml_desc.get("ns", None)) + if el is not None: # Otherwise it writes "None" :-p + el_node.text = str(el) + final_result.append(el_node) + return final_result + return serialized + + def serialize_dict(self, attr, dict_type, **kwargs): + """Serialize a dictionary of objects. + + :param dict attr: Object to be serialized. + :param str dict_type: Type of object in the dictionary. + :rtype: dict + :return: serialized dictionary + """ + serialization_ctxt = kwargs.get("serialization_ctxt", {}) + serialized = {} + for key, value in attr.items(): + try: + serialized[self.serialize_unicode(key)] = self.serialize_data(value, dict_type, **kwargs) + except ValueError as err: + if isinstance(err, SerializationError): + raise + serialized[self.serialize_unicode(key)] = None + + if "xml" in serialization_ctxt: + # XML serialization is more complicated + xml_desc = serialization_ctxt["xml"] + xml_name = xml_desc["name"] + + final_result = _create_xml_node(xml_name, xml_desc.get("prefix", None), xml_desc.get("ns", None)) + for key, value in serialized.items(): + ET.SubElement(final_result, key).text = value + return final_result + + return serialized + + def serialize_object(self, attr, **kwargs): # pylint: disable=too-many-return-statements + """Serialize a generic object. + This will be handled as a dictionary. If object passed in is not + a basic type (str, int, float, dict, list) it will simply be + cast to str. + + :param dict attr: Object to be serialized. + :rtype: dict or str + :return: serialized object + """ + if attr is None: + return None + if isinstance(attr, ET.Element): + return attr + obj_type = type(attr) + if obj_type in self.basic_types: + return self.serialize_basic(attr, self.basic_types[obj_type], **kwargs) + if obj_type is _long_type: + return self.serialize_long(attr) + if obj_type is str: + return self.serialize_unicode(attr) + if obj_type is datetime.datetime: + return self.serialize_iso(attr) + if obj_type is datetime.date: + return self.serialize_date(attr) + if obj_type is datetime.time: + return self.serialize_time(attr) + if obj_type is datetime.timedelta: + return self.serialize_duration(attr) + if obj_type is decimal.Decimal: + return self.serialize_decimal(attr) + + # If it's a model or I know this dependency, serialize as a Model + if obj_type in self.dependencies.values() or isinstance(attr, Model): + return self._serialize(attr) + + if obj_type == dict: + serialized = {} + for key, value in attr.items(): + try: + serialized[self.serialize_unicode(key)] = self.serialize_object(value, **kwargs) + except ValueError: + serialized[self.serialize_unicode(key)] = None + return serialized + + if obj_type == list: + serialized = [] + for obj in attr: + try: + serialized.append(self.serialize_object(obj, **kwargs)) + except ValueError: + pass + return serialized + return str(attr) + + @staticmethod + def serialize_enum(attr, enum_obj=None): + try: + result = attr.value + except AttributeError: + result = attr + try: + enum_obj(result) # type: ignore + return result + except ValueError as exc: + for enum_value in enum_obj: # type: ignore + if enum_value.value.lower() == str(attr).lower(): + return enum_value.value + error = "{!r} is not valid value for enum {!r}" + raise SerializationError(error.format(attr, enum_obj)) from exc + + @staticmethod + def serialize_bytearray(attr, **kwargs): # pylint: disable=unused-argument + """Serialize bytearray into base-64 string. + + :param str attr: Object to be serialized. + :rtype: str + :return: serialized base64 + """ + return b64encode(attr).decode() + + @staticmethod + def serialize_base64(attr, **kwargs): # pylint: disable=unused-argument + """Serialize str into base-64 string. + + :param str attr: Object to be serialized. + :rtype: str + :return: serialized base64 + """ + encoded = b64encode(attr).decode("ascii") + return encoded.strip("=").replace("+", "-").replace("/", "_") + + @staticmethod + def serialize_decimal(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Decimal object to float. + + :param decimal attr: Object to be serialized. + :rtype: float + :return: serialized decimal + """ + return float(attr) + + @staticmethod + def serialize_long(attr, **kwargs): # pylint: disable=unused-argument + """Serialize long (Py2) or int (Py3). + + :param int attr: Object to be serialized. + :rtype: int/long + :return: serialized long + """ + return _long_type(attr) + + @staticmethod + def serialize_date(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Date object into ISO-8601 formatted string. + + :param Date attr: Object to be serialized. + :rtype: str + :return: serialized date + """ + if isinstance(attr, str): + attr = isodate.parse_date(attr) + t = "{:04}-{:02}-{:02}".format(attr.year, attr.month, attr.day) + return t + + @staticmethod + def serialize_time(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Time object into ISO-8601 formatted string. + + :param datetime.time attr: Object to be serialized. + :rtype: str + :return: serialized time + """ + if isinstance(attr, str): + attr = isodate.parse_time(attr) + t = "{:02}:{:02}:{:02}".format(attr.hour, attr.minute, attr.second) + if attr.microsecond: + t += ".{:02}".format(attr.microsecond) + return t + + @staticmethod + def serialize_duration(attr, **kwargs): # pylint: disable=unused-argument + """Serialize TimeDelta object into ISO-8601 formatted string. + + :param TimeDelta attr: Object to be serialized. + :rtype: str + :return: serialized duration + """ + if isinstance(attr, str): + attr = isodate.parse_duration(attr) + return isodate.duration_isoformat(attr) + + @staticmethod + def serialize_rfc(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Datetime object into RFC-1123 formatted string. + + :param Datetime attr: Object to be serialized. + :rtype: str + :raises TypeError: if format invalid. + :return: serialized rfc + """ + try: + if not attr.tzinfo: + _LOGGER.warning("Datetime with no tzinfo will be considered UTC.") + utc = attr.utctimetuple() + except AttributeError as exc: + raise TypeError("RFC1123 object must be valid Datetime object.") from exc + + return "{}, {:02} {} {:04} {:02}:{:02}:{:02} GMT".format( + Serializer.days[utc.tm_wday], + utc.tm_mday, + Serializer.months[utc.tm_mon], + utc.tm_year, + utc.tm_hour, + utc.tm_min, + utc.tm_sec, + ) + + @staticmethod + def serialize_iso(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Datetime object into ISO-8601 formatted string. + + :param Datetime attr: Object to be serialized. + :rtype: str + :raises SerializationError: if format invalid. + :return: serialized iso + """ + if isinstance(attr, str): + attr = isodate.parse_datetime(attr) + try: + if not attr.tzinfo: + _LOGGER.warning("Datetime with no tzinfo will be considered UTC.") + utc = attr.utctimetuple() + if utc.tm_year > 9999 or utc.tm_year < 1: + raise OverflowError("Hit max or min date") + + microseconds = str(attr.microsecond).rjust(6, "0").rstrip("0").ljust(3, "0") + if microseconds: + microseconds = "." + microseconds + date = "{:04}-{:02}-{:02}T{:02}:{:02}:{:02}".format( + utc.tm_year, utc.tm_mon, utc.tm_mday, utc.tm_hour, utc.tm_min, utc.tm_sec + ) + return date + microseconds + "Z" + except (ValueError, OverflowError) as err: + msg = "Unable to serialize datetime object." + raise SerializationError(msg) from err + except AttributeError as err: + msg = "ISO-8601 object must be valid Datetime object." + raise TypeError(msg) from err + + @staticmethod + def serialize_unix(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Datetime object into IntTime format. + This is represented as seconds. + + :param Datetime attr: Object to be serialized. + :rtype: int + :raises SerializationError: if format invalid + :return: serialied unix + """ + if isinstance(attr, int): + return attr + try: + if not attr.tzinfo: + _LOGGER.warning("Datetime with no tzinfo will be considered UTC.") + return int(calendar.timegm(attr.utctimetuple())) + except AttributeError as exc: + raise TypeError("Unix time object must be valid Datetime object.") from exc + + +def rest_key_extractor(attr, attr_desc, data): # pylint: disable=unused-argument + key = attr_desc["key"] + working_data = data + + while "." in key: + # Need the cast, as for some reasons "split" is typed as list[str | Any] + dict_keys = cast(List[str], _FLATTEN.split(key)) + if len(dict_keys) == 1: + key = _decode_attribute_map_key(dict_keys[0]) + break + working_key = _decode_attribute_map_key(dict_keys[0]) + working_data = working_data.get(working_key, data) + if working_data is None: + # If at any point while following flatten JSON path see None, it means + # that all properties under are None as well + return None + key = ".".join(dict_keys[1:]) + + return working_data.get(key) + + +def rest_key_case_insensitive_extractor( # pylint: disable=unused-argument, inconsistent-return-statements + attr, attr_desc, data +): + key = attr_desc["key"] + working_data = data + + while "." in key: + dict_keys = _FLATTEN.split(key) + if len(dict_keys) == 1: + key = _decode_attribute_map_key(dict_keys[0]) + break + working_key = _decode_attribute_map_key(dict_keys[0]) + working_data = attribute_key_case_insensitive_extractor(working_key, None, working_data) + if working_data is None: + # If at any point while following flatten JSON path see None, it means + # that all properties under are None as well + return None + key = ".".join(dict_keys[1:]) + + if working_data: + return attribute_key_case_insensitive_extractor(key, None, working_data) + + +def last_rest_key_extractor(attr, attr_desc, data): # pylint: disable=unused-argument + """Extract the attribute in "data" based on the last part of the JSON path key. + + :param str attr: The attribute to extract + :param dict attr_desc: The attribute description + :param dict data: The data to extract from + :rtype: object + :returns: The extracted attribute + """ + key = attr_desc["key"] + dict_keys = _FLATTEN.split(key) + return attribute_key_extractor(dict_keys[-1], None, data) + + +def last_rest_key_case_insensitive_extractor(attr, attr_desc, data): # pylint: disable=unused-argument + """Extract the attribute in "data" based on the last part of the JSON path key. + + This is the case insensitive version of "last_rest_key_extractor" + :param str attr: The attribute to extract + :param dict attr_desc: The attribute description + :param dict data: The data to extract from + :rtype: object + :returns: The extracted attribute + """ + key = attr_desc["key"] + dict_keys = _FLATTEN.split(key) + return attribute_key_case_insensitive_extractor(dict_keys[-1], None, data) + + +def attribute_key_extractor(attr, _, data): + return data.get(attr) + + +def attribute_key_case_insensitive_extractor(attr, _, data): + found_key = None + lower_attr = attr.lower() + for key in data: + if lower_attr == key.lower(): + found_key = key + break + + return data.get(found_key) + + +def _extract_name_from_internal_type(internal_type): + """Given an internal type XML description, extract correct XML name with namespace. + + :param dict internal_type: An model type + :rtype: tuple + :returns: A tuple XML name + namespace dict + """ + internal_type_xml_map = getattr(internal_type, "_xml_map", {}) + xml_name = internal_type_xml_map.get("name", internal_type.__name__) + xml_ns = internal_type_xml_map.get("ns", None) + if xml_ns: + xml_name = "{{{}}}{}".format(xml_ns, xml_name) + return xml_name + + +def xml_key_extractor(attr, attr_desc, data): # pylint: disable=unused-argument,too-many-return-statements + if isinstance(data, dict): + return None + + # Test if this model is XML ready first + if not isinstance(data, ET.Element): + return None + + xml_desc = attr_desc.get("xml", {}) + xml_name = xml_desc.get("name", attr_desc["key"]) + + # Look for a children + is_iter_type = attr_desc["type"].startswith("[") + is_wrapped = xml_desc.get("wrapped", False) + internal_type = attr_desc.get("internalType", None) + internal_type_xml_map = getattr(internal_type, "_xml_map", {}) + + # Integrate namespace if necessary + xml_ns = xml_desc.get("ns", internal_type_xml_map.get("ns", None)) + if xml_ns: + xml_name = "{{{}}}{}".format(xml_ns, xml_name) + + # If it's an attribute, that's simple + if xml_desc.get("attr", False): + return data.get(xml_name) + + # If it's x-ms-text, that's simple too + if xml_desc.get("text", False): + return data.text + + # Scenario where I take the local name: + # - Wrapped node + # - Internal type is an enum (considered basic types) + # - Internal type has no XML/Name node + if is_wrapped or (internal_type and (issubclass(internal_type, Enum) or "name" not in internal_type_xml_map)): + children = data.findall(xml_name) + # If internal type has a local name and it's not a list, I use that name + elif not is_iter_type and internal_type and "name" in internal_type_xml_map: + xml_name = _extract_name_from_internal_type(internal_type) + children = data.findall(xml_name) + # That's an array + else: + if internal_type: # Complex type, ignore itemsName and use the complex type name + items_name = _extract_name_from_internal_type(internal_type) + else: + items_name = xml_desc.get("itemsName", xml_name) + children = data.findall(items_name) + + if len(children) == 0: + if is_iter_type: + if is_wrapped: + return None # is_wrapped no node, we want None + return [] # not wrapped, assume empty list + return None # Assume it's not there, maybe an optional node. + + # If is_iter_type and not wrapped, return all found children + if is_iter_type: + if not is_wrapped: + return children + # Iter and wrapped, should have found one node only (the wrap one) + if len(children) != 1: + raise DeserializationError( + "Tried to deserialize an array not wrapped, and found several nodes '{}'. Maybe you should declare this array as wrapped?".format( + xml_name + ) + ) + return list(children[0]) # Might be empty list and that's ok. + + # Here it's not a itertype, we should have found one element only or empty + if len(children) > 1: + raise DeserializationError("Find several XML '{}' where it was not expected".format(xml_name)) + return children[0] + + +class Deserializer: + """Response object model deserializer. + + :param dict classes: Class type dictionary for deserializing complex types. + :ivar list key_extractors: Ordered list of extractors to be used by this deserializer. + """ + + basic_types = {str: "str", int: "int", bool: "bool", float: "float"} + + valid_date = re.compile(r"\d{4}[-]\d{2}[-]\d{2}T\d{2}:\d{2}:\d{2}\.?\d*Z?[-+]?[\d{2}]?:?[\d{2}]?") + + def __init__(self, classes: Optional[Mapping[str, type]] = None) -> None: + self.deserialize_type = { + "iso-8601": Deserializer.deserialize_iso, + "rfc-1123": Deserializer.deserialize_rfc, + "unix-time": Deserializer.deserialize_unix, + "duration": Deserializer.deserialize_duration, + "date": Deserializer.deserialize_date, + "time": Deserializer.deserialize_time, + "decimal": Deserializer.deserialize_decimal, + "long": Deserializer.deserialize_long, + "bytearray": Deserializer.deserialize_bytearray, + "base64": Deserializer.deserialize_base64, + "object": self.deserialize_object, + "[]": self.deserialize_iter, + "{}": self.deserialize_dict, + } + self.deserialize_expected_types = { + "duration": (isodate.Duration, datetime.timedelta), + "iso-8601": (datetime.datetime), + } + self.dependencies: Dict[str, type] = dict(classes) if classes else {} + self.key_extractors = [rest_key_extractor, xml_key_extractor] + # Additional properties only works if the "rest_key_extractor" is used to + # extract the keys. Making it to work whatever the key extractor is too much + # complicated, with no real scenario for now. + # So adding a flag to disable additional properties detection. This flag should be + # used if your expect the deserialization to NOT come from a JSON REST syntax. + # Otherwise, result are unexpected + self.additional_properties_detection = True + + def __call__(self, target_obj, response_data, content_type=None): + """Call the deserializer to process a REST response. + + :param str target_obj: Target data type to deserialize to. + :param requests.Response response_data: REST response object. + :param str content_type: Swagger "produces" if available. + :raises DeserializationError: if deserialization fails. + :return: Deserialized object. + :rtype: object + """ + data = self._unpack_content(response_data, content_type) + return self._deserialize(target_obj, data) + + def _deserialize(self, target_obj, data): # pylint: disable=inconsistent-return-statements + """Call the deserializer on a model. + + Data needs to be already deserialized as JSON or XML ElementTree + + :param str target_obj: Target data type to deserialize to. + :param object data: Object to deserialize. + :raises DeserializationError: if deserialization fails. + :return: Deserialized object. + :rtype: object + """ + # This is already a model, go recursive just in case + if hasattr(data, "_attribute_map"): + constants = [name for name, config in getattr(data, "_validation", {}).items() if config.get("constant")] + try: + for attr, mapconfig in data._attribute_map.items(): # pylint: disable=protected-access + if attr in constants: + continue + value = getattr(data, attr) + if value is None: + continue + local_type = mapconfig["type"] + internal_data_type = local_type.strip("[]{}") + if internal_data_type not in self.dependencies or isinstance(internal_data_type, Enum): + continue + setattr(data, attr, self._deserialize(local_type, value)) + return data + except AttributeError: + return + + response, class_name = self._classify_target(target_obj, data) + + if isinstance(response, str): + return self.deserialize_data(data, response) + if isinstance(response, type) and issubclass(response, Enum): + return self.deserialize_enum(data, response) + + if data is None or data is CoreNull: + return data + try: + attributes = response._attribute_map # type: ignore # pylint: disable=protected-access + d_attrs = {} + for attr, attr_desc in attributes.items(): + # Check empty string. If it's not empty, someone has a real "additionalProperties"... + if attr == "additional_properties" and attr_desc["key"] == "": + continue + raw_value = None + # Enhance attr_desc with some dynamic data + attr_desc = attr_desc.copy() # Do a copy, do not change the real one + internal_data_type = attr_desc["type"].strip("[]{}") + if internal_data_type in self.dependencies: + attr_desc["internalType"] = self.dependencies[internal_data_type] + + for key_extractor in self.key_extractors: + found_value = key_extractor(attr, attr_desc, data) + if found_value is not None: + if raw_value is not None and raw_value != found_value: + msg = ( + "Ignoring extracted value '%s' from %s for key '%s'" + " (duplicate extraction, follow extractors order)" + ) + _LOGGER.warning(msg, found_value, key_extractor, attr) + continue + raw_value = found_value + + value = self.deserialize_data(raw_value, attr_desc["type"]) + d_attrs[attr] = value + except (AttributeError, TypeError, KeyError) as err: + msg = "Unable to deserialize to object: " + class_name # type: ignore + raise DeserializationError(msg) from err + additional_properties = self._build_additional_properties(attributes, data) + return self._instantiate_model(response, d_attrs, additional_properties) + + def _build_additional_properties(self, attribute_map, data): + if not self.additional_properties_detection: + return None + if "additional_properties" in attribute_map and attribute_map.get("additional_properties", {}).get("key") != "": + # Check empty string. If it's not empty, someone has a real "additionalProperties" + return None + if isinstance(data, ET.Element): + data = {el.tag: el.text for el in data} + + known_keys = { + _decode_attribute_map_key(_FLATTEN.split(desc["key"])[0]) + for desc in attribute_map.values() + if desc["key"] != "" + } + present_keys = set(data.keys()) + missing_keys = present_keys - known_keys + return {key: data[key] for key in missing_keys} + + def _classify_target(self, target, data): + """Check to see whether the deserialization target object can + be classified into a subclass. + Once classification has been determined, initialize object. + + :param str target: The target object type to deserialize to. + :param str/dict data: The response data to deserialize. + :return: The classified target object and its class name. + :rtype: tuple + """ + if target is None: + return None, None + + if isinstance(target, str): + try: + target = self.dependencies[target] + except KeyError: + return target, target + + try: + target = target._classify(data, self.dependencies) # type: ignore # pylint: disable=protected-access + except AttributeError: + pass # Target is not a Model, no classify + return target, target.__class__.__name__ # type: ignore + + def failsafe_deserialize(self, target_obj, data, content_type=None): + """Ignores any errors encountered in deserialization, + and falls back to not deserializing the object. Recommended + for use in error deserialization, as we want to return the + HttpResponseError to users, and not have them deal with + a deserialization error. + + :param str target_obj: The target object type to deserialize to. + :param str/dict data: The response data to deserialize. + :param str content_type: Swagger "produces" if available. + :return: Deserialized object. + :rtype: object + """ + try: + return self(target_obj, data, content_type=content_type) + except: # pylint: disable=bare-except + _LOGGER.debug( + "Ran into a deserialization error. Ignoring since this is failsafe deserialization", exc_info=True + ) + return None + + @staticmethod + def _unpack_content(raw_data, content_type=None): + """Extract the correct structure for deserialization. + + If raw_data is a PipelineResponse, try to extract the result of RawDeserializer. + if we can't, raise. Your Pipeline should have a RawDeserializer. + + If not a pipeline response and raw_data is bytes or string, use content-type + to decode it. If no content-type, try JSON. + + If raw_data is something else, bypass all logic and return it directly. + + :param obj raw_data: Data to be processed. + :param str content_type: How to parse if raw_data is a string/bytes. + :raises JSONDecodeError: If JSON is requested and parsing is impossible. + :raises UnicodeDecodeError: If bytes is not UTF8 + :rtype: object + :return: Unpacked content. + """ + # Assume this is enough to detect a Pipeline Response without importing it + context = getattr(raw_data, "context", {}) + if context: + if RawDeserializer.CONTEXT_NAME in context: + return context[RawDeserializer.CONTEXT_NAME] + raise ValueError("This pipeline didn't have the RawDeserializer policy; can't deserialize") + + # Assume this is enough to recognize universal_http.ClientResponse without importing it + if hasattr(raw_data, "body"): + return RawDeserializer.deserialize_from_http_generics(raw_data.text(), raw_data.headers) + + # Assume this enough to recognize requests.Response without importing it. + if hasattr(raw_data, "_content_consumed"): + return RawDeserializer.deserialize_from_http_generics(raw_data.text, raw_data.headers) + + if isinstance(raw_data, (str, bytes)) or hasattr(raw_data, "read"): + return RawDeserializer.deserialize_from_text(raw_data, content_type) # type: ignore + return raw_data + + def _instantiate_model(self, response, attrs, additional_properties=None): + """Instantiate a response model passing in deserialized args. + + :param Response response: The response model class. + :param dict attrs: The deserialized response attributes. + :param dict additional_properties: Additional properties to be set. + :rtype: Response + :return: The instantiated response model. + """ + if callable(response): + subtype = getattr(response, "_subtype_map", {}) + try: + readonly = [ + k + for k, v in response._validation.items() # pylint: disable=protected-access # type: ignore + if v.get("readonly") + ] + const = [ + k + for k, v in response._validation.items() # pylint: disable=protected-access # type: ignore + if v.get("constant") + ] + kwargs = {k: v for k, v in attrs.items() if k not in subtype and k not in readonly + const} + response_obj = response(**kwargs) + for attr in readonly: + setattr(response_obj, attr, attrs.get(attr)) + if additional_properties: + response_obj.additional_properties = additional_properties # type: ignore + return response_obj + except TypeError as err: + msg = "Unable to deserialize {} into model {}. ".format(kwargs, response) # type: ignore + raise DeserializationError(msg + str(err)) from err + else: + try: + for attr, value in attrs.items(): + setattr(response, attr, value) + return response + except Exception as exp: + msg = "Unable to populate response model. " + msg += "Type: {}, Error: {}".format(type(response), exp) + raise DeserializationError(msg) from exp + + def deserialize_data(self, data, data_type): # pylint: disable=too-many-return-statements + """Process data for deserialization according to data type. + + :param str data: The response string to be deserialized. + :param str data_type: The type to deserialize to. + :raises DeserializationError: if deserialization fails. + :return: Deserialized object. + :rtype: object + """ + if data is None: + return data + + try: + if not data_type: + return data + if data_type in self.basic_types.values(): + return self.deserialize_basic(data, data_type) + if data_type in self.deserialize_type: + if isinstance(data, self.deserialize_expected_types.get(data_type, tuple())): + return data + + is_a_text_parsing_type = lambda x: x not in [ # pylint: disable=unnecessary-lambda-assignment + "object", + "[]", + r"{}", + ] + if isinstance(data, ET.Element) and is_a_text_parsing_type(data_type) and not data.text: + return None + data_val = self.deserialize_type[data_type](data) + return data_val + + iter_type = data_type[0] + data_type[-1] + if iter_type in self.deserialize_type: + return self.deserialize_type[iter_type](data, data_type[1:-1]) + + obj_type = self.dependencies[data_type] + if issubclass(obj_type, Enum): + if isinstance(data, ET.Element): + data = data.text + return self.deserialize_enum(data, obj_type) + + except (ValueError, TypeError, AttributeError) as err: + msg = "Unable to deserialize response data." + msg += " Data: {}, {}".format(data, data_type) + raise DeserializationError(msg) from err + return self._deserialize(obj_type, data) + + def deserialize_iter(self, attr, iter_type): + """Deserialize an iterable. + + :param list attr: Iterable to be deserialized. + :param str iter_type: The type of object in the iterable. + :return: Deserialized iterable. + :rtype: list + """ + if attr is None: + return None + if isinstance(attr, ET.Element): # If I receive an element here, get the children + attr = list(attr) + if not isinstance(attr, (list, set)): + raise DeserializationError("Cannot deserialize as [{}] an object of type {}".format(iter_type, type(attr))) + return [self.deserialize_data(a, iter_type) for a in attr] + + def deserialize_dict(self, attr, dict_type): + """Deserialize a dictionary. + + :param dict/list attr: Dictionary to be deserialized. Also accepts + a list of key, value pairs. + :param str dict_type: The object type of the items in the dictionary. + :return: Deserialized dictionary. + :rtype: dict + """ + if isinstance(attr, list): + return {x["key"]: self.deserialize_data(x["value"], dict_type) for x in attr} + + if isinstance(attr, ET.Element): + # Transform value into {"Key": "value"} + attr = {el.tag: el.text for el in attr} + return {k: self.deserialize_data(v, dict_type) for k, v in attr.items()} + + def deserialize_object(self, attr, **kwargs): # pylint: disable=too-many-return-statements + """Deserialize a generic object. + This will be handled as a dictionary. + + :param dict attr: Dictionary to be deserialized. + :return: Deserialized object. + :rtype: dict + :raises TypeError: if non-builtin datatype encountered. + """ + if attr is None: + return None + if isinstance(attr, ET.Element): + # Do no recurse on XML, just return the tree as-is + return attr + if isinstance(attr, str): + return self.deserialize_basic(attr, "str") + obj_type = type(attr) + if obj_type in self.basic_types: + return self.deserialize_basic(attr, self.basic_types[obj_type]) + if obj_type is _long_type: + return self.deserialize_long(attr) + + if obj_type == dict: + deserialized = {} + for key, value in attr.items(): + try: + deserialized[key] = self.deserialize_object(value, **kwargs) + except ValueError: + deserialized[key] = None + return deserialized + + if obj_type == list: + deserialized = [] + for obj in attr: + try: + deserialized.append(self.deserialize_object(obj, **kwargs)) + except ValueError: + pass + return deserialized + + error = "Cannot deserialize generic object with type: " + raise TypeError(error + str(obj_type)) + + def deserialize_basic(self, attr, data_type): # pylint: disable=too-many-return-statements + """Deserialize basic builtin data type from string. + Will attempt to convert to str, int, float and bool. + This function will also accept '1', '0', 'true' and 'false' as + valid bool values. + + :param str attr: response string to be deserialized. + :param str data_type: deserialization data type. + :return: Deserialized basic type. + :rtype: str, int, float or bool + :raises TypeError: if string format is not valid. + """ + # If we're here, data is supposed to be a basic type. + # If it's still an XML node, take the text + if isinstance(attr, ET.Element): + attr = attr.text + if not attr: + if data_type == "str": + # None or '', node is empty string. + return "" + # None or '', node with a strong type is None. + # Don't try to model "empty bool" or "empty int" + return None + + if data_type == "bool": + if attr in [True, False, 1, 0]: + return bool(attr) + if isinstance(attr, str): + if attr.lower() in ["true", "1"]: + return True + if attr.lower() in ["false", "0"]: + return False + raise TypeError("Invalid boolean value: {}".format(attr)) + + if data_type == "str": + return self.deserialize_unicode(attr) + return eval(data_type)(attr) # nosec # pylint: disable=eval-used + + @staticmethod + def deserialize_unicode(data): + """Preserve unicode objects in Python 2, otherwise return data + as a string. + + :param str data: response string to be deserialized. + :return: Deserialized string. + :rtype: str or unicode + """ + # We might be here because we have an enum modeled as string, + # and we try to deserialize a partial dict with enum inside + if isinstance(data, Enum): + return data + + # Consider this is real string + try: + if isinstance(data, unicode): # type: ignore + return data + except NameError: + return str(data) + return str(data) + + @staticmethod + def deserialize_enum(data, enum_obj): + """Deserialize string into enum object. + + If the string is not a valid enum value it will be returned as-is + and a warning will be logged. + + :param str data: Response string to be deserialized. If this value is + None or invalid it will be returned as-is. + :param Enum enum_obj: Enum object to deserialize to. + :return: Deserialized enum object. + :rtype: Enum + """ + if isinstance(data, enum_obj) or data is None: + return data + if isinstance(data, Enum): + data = data.value + if isinstance(data, int): + # Workaround. We might consider remove it in the future. + try: + return list(enum_obj.__members__.values())[data] + except IndexError as exc: + error = "{!r} is not a valid index for enum {!r}" + raise DeserializationError(error.format(data, enum_obj)) from exc + try: + return enum_obj(str(data)) + except ValueError: + for enum_value in enum_obj: + if enum_value.value.lower() == str(data).lower(): + return enum_value + # We don't fail anymore for unknown value, we deserialize as a string + _LOGGER.warning("Deserializer is not able to find %s as valid enum in %s", data, enum_obj) + return Deserializer.deserialize_unicode(data) + + @staticmethod + def deserialize_bytearray(attr): + """Deserialize string into bytearray. + + :param str attr: response string to be deserialized. + :return: Deserialized bytearray + :rtype: bytearray + :raises TypeError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + return bytearray(b64decode(attr)) # type: ignore + + @staticmethod + def deserialize_base64(attr): + """Deserialize base64 encoded string into string. + + :param str attr: response string to be deserialized. + :return: Deserialized base64 string + :rtype: bytearray + :raises TypeError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + padding = "=" * (3 - (len(attr) + 3) % 4) # type: ignore + attr = attr + padding # type: ignore + encoded = attr.replace("-", "+").replace("_", "/") + return b64decode(encoded) + + @staticmethod + def deserialize_decimal(attr): + """Deserialize string into Decimal object. + + :param str attr: response string to be deserialized. + :return: Deserialized decimal + :raises DeserializationError: if string format invalid. + :rtype: decimal + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + return decimal.Decimal(str(attr)) # type: ignore + except decimal.DecimalException as err: + msg = "Invalid decimal {}".format(attr) + raise DeserializationError(msg) from err + + @staticmethod + def deserialize_long(attr): + """Deserialize string into long (Py2) or int (Py3). + + :param str attr: response string to be deserialized. + :return: Deserialized int + :rtype: long or int + :raises ValueError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + return _long_type(attr) # type: ignore + + @staticmethod + def deserialize_duration(attr): + """Deserialize ISO-8601 formatted string into TimeDelta object. + + :param str attr: response string to be deserialized. + :return: Deserialized duration + :rtype: TimeDelta + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + duration = isodate.parse_duration(attr) + except (ValueError, OverflowError, AttributeError) as err: + msg = "Cannot deserialize duration object." + raise DeserializationError(msg) from err + return duration + + @staticmethod + def deserialize_date(attr): + """Deserialize ISO-8601 formatted string into Date object. + + :param str attr: response string to be deserialized. + :return: Deserialized date + :rtype: Date + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + if re.search(r"[^\W\d_]", attr, re.I + re.U): # type: ignore + raise DeserializationError("Date must have only digits and -. Received: %s" % attr) + # This must NOT use defaultmonth/defaultday. Using None ensure this raises an exception. + return isodate.parse_date(attr, defaultmonth=0, defaultday=0) + + @staticmethod + def deserialize_time(attr): + """Deserialize ISO-8601 formatted string into time object. + + :param str attr: response string to be deserialized. + :return: Deserialized time + :rtype: datetime.time + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + if re.search(r"[^\W\d_]", attr, re.I + re.U): # type: ignore + raise DeserializationError("Date must have only digits and -. Received: %s" % attr) + return isodate.parse_time(attr) + + @staticmethod + def deserialize_rfc(attr): + """Deserialize RFC-1123 formatted string into Datetime object. + + :param str attr: response string to be deserialized. + :return: Deserialized RFC datetime + :rtype: Datetime + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + parsed_date = email.utils.parsedate_tz(attr) # type: ignore + date_obj = datetime.datetime( + *parsed_date[:6], tzinfo=datetime.timezone(datetime.timedelta(minutes=(parsed_date[9] or 0) / 60)) + ) + if not date_obj.tzinfo: + date_obj = date_obj.astimezone(tz=TZ_UTC) + except ValueError as err: + msg = "Cannot deserialize to rfc datetime object." + raise DeserializationError(msg) from err + return date_obj + + @staticmethod + def deserialize_iso(attr): + """Deserialize ISO-8601 formatted string into Datetime object. + + :param str attr: response string to be deserialized. + :return: Deserialized ISO datetime + :rtype: Datetime + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + attr = attr.upper() # type: ignore + match = Deserializer.valid_date.match(attr) + if not match: + raise ValueError("Invalid datetime string: " + attr) + + check_decimal = attr.split(".") + if len(check_decimal) > 1: + decimal_str = "" + for digit in check_decimal[1]: + if digit.isdigit(): + decimal_str += digit + else: + break + if len(decimal_str) > 6: + attr = attr.replace(decimal_str, decimal_str[0:6]) + + date_obj = isodate.parse_datetime(attr) + test_utc = date_obj.utctimetuple() + if test_utc.tm_year > 9999 or test_utc.tm_year < 1: + raise OverflowError("Hit max or min date") + except (ValueError, OverflowError, AttributeError) as err: + msg = "Cannot deserialize datetime object." + raise DeserializationError(msg) from err + return date_obj + + @staticmethod + def deserialize_unix(attr): + """Serialize Datetime object into IntTime format. + This is represented as seconds. + + :param int attr: Object to be serialized. + :return: Deserialized datetime + :rtype: Datetime + :raises DeserializationError: if format invalid + """ + if isinstance(attr, ET.Element): + attr = int(attr.text) # type: ignore + try: + attr = int(attr) + date_obj = datetime.datetime.fromtimestamp(attr, TZ_UTC) + except ValueError as err: + msg = "Cannot deserialize to unix datetime object." + raise DeserializationError(msg) from err + return date_obj diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ExtensibleEnumsVersionTolerant/extensibleenumsswaggerversiontolerant/aio/_client.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ExtensibleEnumsVersionTolerant/extensibleenumsswaggerversiontolerant/aio/_client.py index 4c393b8e516..9d6dbc20c15 100644 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ExtensibleEnumsVersionTolerant/extensibleenumsswaggerversiontolerant/aio/_client.py +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ExtensibleEnumsVersionTolerant/extensibleenumsswaggerversiontolerant/aio/_client.py @@ -14,7 +14,7 @@ from azure.core.pipeline import policies from azure.core.rest import AsyncHttpResponse, HttpRequest -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import PetStoreIncConfiguration from .operations import PetOperations diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ExtensibleEnumsVersionTolerant/extensibleenumsswaggerversiontolerant/aio/operations/_operations.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ExtensibleEnumsVersionTolerant/extensibleenumsswaggerversiontolerant/aio/operations/_operations.py index 3232c907f59..0fe88bf6ec2 100644 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ExtensibleEnumsVersionTolerant/extensibleenumsswaggerversiontolerant/aio/operations/_operations.py +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ExtensibleEnumsVersionTolerant/extensibleenumsswaggerversiontolerant/aio/operations/_operations.py @@ -23,7 +23,7 @@ from azure.core.tracing.decorator_async import distributed_trace_async from azure.core.utils import case_insensitive_dict -from ..._serialization import Deserializer, Serializer +from ..._utils.serialization import Deserializer, Serializer from ...operations._operations import build_pet_add_pet_request, build_pet_get_by_pet_id_request from .._configuration import PetStoreIncConfiguration diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ExtensibleEnumsVersionTolerant/extensibleenumsswaggerversiontolerant/operations/_operations.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ExtensibleEnumsVersionTolerant/extensibleenumsswaggerversiontolerant/operations/_operations.py index 977593150fb..a8cb85f8d64 100644 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ExtensibleEnumsVersionTolerant/extensibleenumsswaggerversiontolerant/operations/_operations.py +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ExtensibleEnumsVersionTolerant/extensibleenumsswaggerversiontolerant/operations/_operations.py @@ -24,7 +24,7 @@ from azure.core.utils import case_insensitive_dict from .._configuration import PetStoreIncConfiguration -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer JSON = MutableMapping[str, Any] T = TypeVar("T") diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/HeaderVersionTolerant/headerversiontolerant/_client.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/HeaderVersionTolerant/headerversiontolerant/_client.py index f93715103bb..74d64f661cf 100644 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/HeaderVersionTolerant/headerversiontolerant/_client.py +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/HeaderVersionTolerant/headerversiontolerant/_client.py @@ -15,7 +15,7 @@ from azure.core.rest import HttpRequest, HttpResponse from ._configuration import AutoRestSwaggerBATHeaderServiceConfiguration -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer from .operations import HeaderOperations diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/HeaderVersionTolerant/headerversiontolerant/_utils/__init__.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/HeaderVersionTolerant/headerversiontolerant/_utils/__init__.py new file mode 100644 index 00000000000..0af9b28f660 --- /dev/null +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/HeaderVersionTolerant/headerversiontolerant/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/HeaderVersionTolerant/headerversiontolerant/_utils/serialization.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/HeaderVersionTolerant/headerversiontolerant/_utils/serialization.py new file mode 100644 index 00000000000..f5187701d7b --- /dev/null +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/HeaderVersionTolerant/headerversiontolerant/_utils/serialization.py @@ -0,0 +1,2032 @@ +# pylint: disable=line-too-long,useless-suppression,too-many-lines +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +# pyright: reportUnnecessaryTypeIgnoreComment=false + +from base64 import b64decode, b64encode +import calendar +import datetime +import decimal +import email +from enum import Enum +import json +import logging +import re +import sys +import codecs +from typing import ( + Dict, + Any, + cast, + Optional, + Union, + AnyStr, + IO, + Mapping, + Callable, + MutableMapping, + List, +) + +try: + from urllib import quote # type: ignore +except ImportError: + from urllib.parse import quote +import xml.etree.ElementTree as ET + +import isodate # type: ignore +from typing_extensions import Self + +from azure.core.exceptions import DeserializationError, SerializationError +from azure.core.serialization import NULL as CoreNull + +_BOM = codecs.BOM_UTF8.decode(encoding="utf-8") + +JSON = MutableMapping[str, Any] + + +class RawDeserializer: + + # Accept "text" because we're open minded people... + JSON_REGEXP = re.compile(r"^(application|text)/([a-z+.]+\+)?json$") + + # Name used in context + CONTEXT_NAME = "deserialized_data" + + @classmethod + def deserialize_from_text(cls, data: Optional[Union[AnyStr, IO]], content_type: Optional[str] = None) -> Any: + """Decode data according to content-type. + + Accept a stream of data as well, but will be load at once in memory for now. + + If no content-type, will return the string version (not bytes, not stream) + + :param data: Input, could be bytes or stream (will be decoded with UTF8) or text + :type data: str or bytes or IO + :param str content_type: The content type. + :return: The deserialized data. + :rtype: object + """ + if hasattr(data, "read"): + # Assume a stream + data = cast(IO, data).read() + + if isinstance(data, bytes): + data_as_str = data.decode(encoding="utf-8-sig") + else: + # Explain to mypy the correct type. + data_as_str = cast(str, data) + + # Remove Byte Order Mark if present in string + data_as_str = data_as_str.lstrip(_BOM) + + if content_type is None: + return data + + if cls.JSON_REGEXP.match(content_type): + try: + return json.loads(data_as_str) + except ValueError as err: + raise DeserializationError("JSON is invalid: {}".format(err), err) from err + elif "xml" in (content_type or []): + try: + + try: + if isinstance(data, unicode): # type: ignore + # If I'm Python 2.7 and unicode XML will scream if I try a "fromstring" on unicode string + data_as_str = data_as_str.encode(encoding="utf-8") # type: ignore + except NameError: + pass + + return ET.fromstring(data_as_str) # nosec + except ET.ParseError as err: + # It might be because the server has an issue, and returned JSON with + # content-type XML.... + # So let's try a JSON load, and if it's still broken + # let's flow the initial exception + def _json_attemp(data): + try: + return True, json.loads(data) + except ValueError: + return False, None # Don't care about this one + + success, json_result = _json_attemp(data) + if success: + return json_result + # If i'm here, it's not JSON, it's not XML, let's scream + # and raise the last context in this block (the XML exception) + # The function hack is because Py2.7 messes up with exception + # context otherwise. + _LOGGER.critical("Wasn't XML not JSON, failing") + raise DeserializationError("XML is invalid") from err + elif content_type.startswith("text/"): + return data_as_str + raise DeserializationError("Cannot deserialize content-type: {}".format(content_type)) + + @classmethod + def deserialize_from_http_generics(cls, body_bytes: Optional[Union[AnyStr, IO]], headers: Mapping) -> Any: + """Deserialize from HTTP response. + + Use bytes and headers to NOT use any requests/aiohttp or whatever + specific implementation. + Headers will tested for "content-type" + + :param bytes body_bytes: The body of the response. + :param dict headers: The headers of the response. + :returns: The deserialized data. + :rtype: object + """ + # Try to use content-type from headers if available + content_type = None + if "content-type" in headers: + content_type = headers["content-type"].split(";")[0].strip().lower() + # Ouch, this server did not declare what it sent... + # Let's guess it's JSON... + # Also, since Autorest was considering that an empty body was a valid JSON, + # need that test as well.... + else: + content_type = "application/json" + + if body_bytes: + return cls.deserialize_from_text(body_bytes, content_type) + return None + + +_LOGGER = logging.getLogger(__name__) + +try: + _long_type = long # type: ignore +except NameError: + _long_type = int + +TZ_UTC = datetime.timezone.utc + +_FLATTEN = re.compile(r"(? None: + self.additional_properties: Optional[Dict[str, Any]] = {} + for k in kwargs: # pylint: disable=consider-using-dict-items + if k not in self._attribute_map: + _LOGGER.warning("%s is not a known attribute of class %s and will be ignored", k, self.__class__) + elif k in self._validation and self._validation[k].get("readonly", False): + _LOGGER.warning("Readonly attribute %s will be ignored in class %s", k, self.__class__) + else: + setattr(self, k, kwargs[k]) + + def __eq__(self, other: Any) -> bool: + """Compare objects by comparing all attributes. + + :param object other: The object to compare + :returns: True if objects are equal + :rtype: bool + """ + if isinstance(other, self.__class__): + return self.__dict__ == other.__dict__ + return False + + def __ne__(self, other: Any) -> bool: + """Compare objects by comparing all attributes. + + :param object other: The object to compare + :returns: True if objects are not equal + :rtype: bool + """ + return not self.__eq__(other) + + def __str__(self) -> str: + return str(self.__dict__) + + @classmethod + def enable_additional_properties_sending(cls) -> None: + cls._attribute_map["additional_properties"] = {"key": "", "type": "{object}"} + + @classmethod + def is_xml_model(cls) -> bool: + try: + cls._xml_map # type: ignore + except AttributeError: + return False + return True + + @classmethod + def _create_xml_node(cls): + """Create XML node. + + :returns: The XML node + :rtype: xml.etree.ElementTree.Element + """ + try: + xml_map = cls._xml_map # type: ignore + except AttributeError: + xml_map = {} + + return _create_xml_node(xml_map.get("name", cls.__name__), xml_map.get("prefix", None), xml_map.get("ns", None)) + + def serialize(self, keep_readonly: bool = False, **kwargs: Any) -> JSON: + """Return the JSON that would be sent to server from this model. + + This is an alias to `as_dict(full_restapi_key_transformer, keep_readonly=False)`. + + If you want XML serialization, you can pass the kwargs is_xml=True. + + :param bool keep_readonly: If you want to serialize the readonly attributes + :returns: A dict JSON compatible object + :rtype: dict + """ + serializer = Serializer(self._infer_class_models()) + return serializer._serialize( # type: ignore # pylint: disable=protected-access + self, keep_readonly=keep_readonly, **kwargs + ) + + def as_dict( + self, + keep_readonly: bool = True, + key_transformer: Callable[[str, Dict[str, Any], Any], Any] = attribute_transformer, + **kwargs: Any + ) -> JSON: + """Return a dict that can be serialized using json.dump. + + Advanced usage might optionally use a callback as parameter: + + .. code::python + + def my_key_transformer(key, attr_desc, value): + return key + + Key is the attribute name used in Python. Attr_desc + is a dict of metadata. Currently contains 'type' with the + msrest type and 'key' with the RestAPI encoded key. + Value is the current value in this object. + + The string returned will be used to serialize the key. + If the return type is a list, this is considered hierarchical + result dict. + + See the three examples in this file: + + - attribute_transformer + - full_restapi_key_transformer + - last_restapi_key_transformer + + If you want XML serialization, you can pass the kwargs is_xml=True. + + :param bool keep_readonly: If you want to serialize the readonly attributes + :param function key_transformer: A key transformer function. + :returns: A dict JSON compatible object + :rtype: dict + """ + serializer = Serializer(self._infer_class_models()) + return serializer._serialize( # type: ignore # pylint: disable=protected-access + self, key_transformer=key_transformer, keep_readonly=keep_readonly, **kwargs + ) + + @classmethod + def _infer_class_models(cls): + try: + str_models = cls.__module__.rsplit(".", 1)[0] + models = sys.modules[str_models] + client_models = {k: v for k, v in models.__dict__.items() if isinstance(v, type)} + if cls.__name__ not in client_models: + raise ValueError("Not Autorest generated code") + except Exception: # pylint: disable=broad-exception-caught + # Assume it's not Autorest generated (tests?). Add ourselves as dependencies. + client_models = {cls.__name__: cls} + return client_models + + @classmethod + def deserialize(cls, data: Any, content_type: Optional[str] = None) -> Self: + """Parse a str using the RestAPI syntax and return a model. + + :param str data: A str using RestAPI structure. JSON by default. + :param str content_type: JSON by default, set application/xml if XML. + :returns: An instance of this model + :raises DeserializationError: if something went wrong + :rtype: Self + """ + deserializer = Deserializer(cls._infer_class_models()) + return deserializer(cls.__name__, data, content_type=content_type) # type: ignore + + @classmethod + def from_dict( + cls, + data: Any, + key_extractors: Optional[Callable[[str, Dict[str, Any], Any], Any]] = None, + content_type: Optional[str] = None, + ) -> Self: + """Parse a dict using given key extractor return a model. + + By default consider key + extractors (rest_key_case_insensitive_extractor, attribute_key_case_insensitive_extractor + and last_rest_key_case_insensitive_extractor) + + :param dict data: A dict using RestAPI structure + :param function key_extractors: A key extractor function. + :param str content_type: JSON by default, set application/xml if XML. + :returns: An instance of this model + :raises DeserializationError: if something went wrong + :rtype: Self + """ + deserializer = Deserializer(cls._infer_class_models()) + deserializer.key_extractors = ( # type: ignore + [ # type: ignore + attribute_key_case_insensitive_extractor, + rest_key_case_insensitive_extractor, + last_rest_key_case_insensitive_extractor, + ] + if key_extractors is None + else key_extractors + ) + return deserializer(cls.__name__, data, content_type=content_type) # type: ignore + + @classmethod + def _flatten_subtype(cls, key, objects): + if "_subtype_map" not in cls.__dict__: + return {} + result = dict(cls._subtype_map[key]) + for valuetype in cls._subtype_map[key].values(): + result.update(objects[valuetype]._flatten_subtype(key, objects)) # pylint: disable=protected-access + return result + + @classmethod + def _classify(cls, response, objects): + """Check the class _subtype_map for any child classes. + We want to ignore any inherited _subtype_maps. + + :param dict response: The initial data + :param dict objects: The class objects + :returns: The class to be used + :rtype: class + """ + for subtype_key in cls.__dict__.get("_subtype_map", {}).keys(): + subtype_value = None + + if not isinstance(response, ET.Element): + rest_api_response_key = cls._get_rest_key_parts(subtype_key)[-1] + subtype_value = response.get(rest_api_response_key, None) or response.get(subtype_key, None) + else: + subtype_value = xml_key_extractor(subtype_key, cls._attribute_map[subtype_key], response) + if subtype_value: + # Try to match base class. Can be class name only + # (bug to fix in Autorest to support x-ms-discriminator-name) + if cls.__name__ == subtype_value: + return cls + flatten_mapping_type = cls._flatten_subtype(subtype_key, objects) + try: + return objects[flatten_mapping_type[subtype_value]] # type: ignore + except KeyError: + _LOGGER.warning( + "Subtype value %s has no mapping, use base class %s.", + subtype_value, + cls.__name__, + ) + break + else: + _LOGGER.warning("Discriminator %s is absent or null, use base class %s.", subtype_key, cls.__name__) + break + return cls + + @classmethod + def _get_rest_key_parts(cls, attr_key): + """Get the RestAPI key of this attr, split it and decode part + :param str attr_key: Attribute key must be in attribute_map. + :returns: A list of RestAPI part + :rtype: list + """ + rest_split_key = _FLATTEN.split(cls._attribute_map[attr_key]["key"]) + return [_decode_attribute_map_key(key_part) for key_part in rest_split_key] + + +def _decode_attribute_map_key(key): + """This decode a key in an _attribute_map to the actual key we want to look at + inside the received data. + + :param str key: A key string from the generated code + :returns: The decoded key + :rtype: str + """ + return key.replace("\\.", ".") + + +class Serializer: # pylint: disable=too-many-public-methods + """Request object model serializer.""" + + basic_types = {str: "str", int: "int", bool: "bool", float: "float"} + + _xml_basic_types_serializers = {"bool": lambda x: str(x).lower()} + days = {0: "Mon", 1: "Tue", 2: "Wed", 3: "Thu", 4: "Fri", 5: "Sat", 6: "Sun"} + months = { + 1: "Jan", + 2: "Feb", + 3: "Mar", + 4: "Apr", + 5: "May", + 6: "Jun", + 7: "Jul", + 8: "Aug", + 9: "Sep", + 10: "Oct", + 11: "Nov", + 12: "Dec", + } + validation = { + "min_length": lambda x, y: len(x) < y, + "max_length": lambda x, y: len(x) > y, + "minimum": lambda x, y: x < y, + "maximum": lambda x, y: x > y, + "minimum_ex": lambda x, y: x <= y, + "maximum_ex": lambda x, y: x >= y, + "min_items": lambda x, y: len(x) < y, + "max_items": lambda x, y: len(x) > y, + "pattern": lambda x, y: not re.match(y, x, re.UNICODE), + "unique": lambda x, y: len(x) != len(set(x)), + "multiple": lambda x, y: x % y != 0, + } + + def __init__(self, classes: Optional[Mapping[str, type]] = None) -> None: + self.serialize_type = { + "iso-8601": Serializer.serialize_iso, + "rfc-1123": Serializer.serialize_rfc, + "unix-time": Serializer.serialize_unix, + "duration": Serializer.serialize_duration, + "date": Serializer.serialize_date, + "time": Serializer.serialize_time, + "decimal": Serializer.serialize_decimal, + "long": Serializer.serialize_long, + "bytearray": Serializer.serialize_bytearray, + "base64": Serializer.serialize_base64, + "object": self.serialize_object, + "[]": self.serialize_iter, + "{}": self.serialize_dict, + } + self.dependencies: Dict[str, type] = dict(classes) if classes else {} + self.key_transformer = full_restapi_key_transformer + self.client_side_validation = True + + def _serialize( # pylint: disable=too-many-nested-blocks, too-many-branches, too-many-statements, too-many-locals + self, target_obj, data_type=None, **kwargs + ): + """Serialize data into a string according to type. + + :param object target_obj: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str, dict + :raises SerializationError: if serialization fails. + :returns: The serialized data. + """ + key_transformer = kwargs.get("key_transformer", self.key_transformer) + keep_readonly = kwargs.get("keep_readonly", False) + if target_obj is None: + return None + + attr_name = None + class_name = target_obj.__class__.__name__ + + if data_type: + return self.serialize_data(target_obj, data_type, **kwargs) + + if not hasattr(target_obj, "_attribute_map"): + data_type = type(target_obj).__name__ + if data_type in self.basic_types.values(): + return self.serialize_data(target_obj, data_type, **kwargs) + + # Force "is_xml" kwargs if we detect a XML model + try: + is_xml_model_serialization = kwargs["is_xml"] + except KeyError: + is_xml_model_serialization = kwargs.setdefault("is_xml", target_obj.is_xml_model()) + + serialized = {} + if is_xml_model_serialization: + serialized = target_obj._create_xml_node() # pylint: disable=protected-access + try: + attributes = target_obj._attribute_map # pylint: disable=protected-access + for attr, attr_desc in attributes.items(): + attr_name = attr + if not keep_readonly and target_obj._validation.get( # pylint: disable=protected-access + attr_name, {} + ).get("readonly", False): + continue + + if attr_name == "additional_properties" and attr_desc["key"] == "": + if target_obj.additional_properties is not None: + serialized.update(target_obj.additional_properties) + continue + try: + + orig_attr = getattr(target_obj, attr) + if is_xml_model_serialization: + pass # Don't provide "transformer" for XML for now. Keep "orig_attr" + else: # JSON + keys, orig_attr = key_transformer(attr, attr_desc.copy(), orig_attr) + keys = keys if isinstance(keys, list) else [keys] + + kwargs["serialization_ctxt"] = attr_desc + new_attr = self.serialize_data(orig_attr, attr_desc["type"], **kwargs) + + if is_xml_model_serialization: + xml_desc = attr_desc.get("xml", {}) + xml_name = xml_desc.get("name", attr_desc["key"]) + xml_prefix = xml_desc.get("prefix", None) + xml_ns = xml_desc.get("ns", None) + if xml_desc.get("attr", False): + if xml_ns: + ET.register_namespace(xml_prefix, xml_ns) + xml_name = "{{{}}}{}".format(xml_ns, xml_name) + serialized.set(xml_name, new_attr) # type: ignore + continue + if xml_desc.get("text", False): + serialized.text = new_attr # type: ignore + continue + if isinstance(new_attr, list): + serialized.extend(new_attr) # type: ignore + elif isinstance(new_attr, ET.Element): + # If the down XML has no XML/Name, + # we MUST replace the tag with the local tag. But keeping the namespaces. + if "name" not in getattr(orig_attr, "_xml_map", {}): + splitted_tag = new_attr.tag.split("}") + if len(splitted_tag) == 2: # Namespace + new_attr.tag = "}".join([splitted_tag[0], xml_name]) + else: + new_attr.tag = xml_name + serialized.append(new_attr) # type: ignore + else: # That's a basic type + # Integrate namespace if necessary + local_node = _create_xml_node(xml_name, xml_prefix, xml_ns) + local_node.text = str(new_attr) + serialized.append(local_node) # type: ignore + else: # JSON + for k in reversed(keys): # type: ignore + new_attr = {k: new_attr} + + _new_attr = new_attr + _serialized = serialized + for k in keys: # type: ignore + if k not in _serialized: + _serialized.update(_new_attr) # type: ignore + _new_attr = _new_attr[k] # type: ignore + _serialized = _serialized[k] + except ValueError as err: + if isinstance(err, SerializationError): + raise + + except (AttributeError, KeyError, TypeError) as err: + msg = "Attribute {} in object {} cannot be serialized.\n{}".format(attr_name, class_name, str(target_obj)) + raise SerializationError(msg) from err + return serialized + + def body(self, data, data_type, **kwargs): + """Serialize data intended for a request body. + + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: dict + :raises SerializationError: if serialization fails. + :raises ValueError: if data is None + :returns: The serialized request body + """ + + # Just in case this is a dict + internal_data_type_str = data_type.strip("[]{}") + internal_data_type = self.dependencies.get(internal_data_type_str, None) + try: + is_xml_model_serialization = kwargs["is_xml"] + except KeyError: + if internal_data_type and issubclass(internal_data_type, Model): + is_xml_model_serialization = kwargs.setdefault("is_xml", internal_data_type.is_xml_model()) + else: + is_xml_model_serialization = False + if internal_data_type and not isinstance(internal_data_type, Enum): + try: + deserializer = Deserializer(self.dependencies) + # Since it's on serialization, it's almost sure that format is not JSON REST + # We're not able to deal with additional properties for now. + deserializer.additional_properties_detection = False + if is_xml_model_serialization: + deserializer.key_extractors = [ # type: ignore + attribute_key_case_insensitive_extractor, + ] + else: + deserializer.key_extractors = [ + rest_key_case_insensitive_extractor, + attribute_key_case_insensitive_extractor, + last_rest_key_case_insensitive_extractor, + ] + data = deserializer._deserialize(data_type, data) # pylint: disable=protected-access + except DeserializationError as err: + raise SerializationError("Unable to build a model: " + str(err)) from err + + return self._serialize(data, data_type, **kwargs) + + def url(self, name, data, data_type, **kwargs): + """Serialize data intended for a URL path. + + :param str name: The name of the URL path parameter. + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str + :returns: The serialized URL path + :raises TypeError: if serialization fails. + :raises ValueError: if data is None + """ + try: + output = self.serialize_data(data, data_type, **kwargs) + if data_type == "bool": + output = json.dumps(output) + + if kwargs.get("skip_quote") is True: + output = str(output) + output = output.replace("{", quote("{")).replace("}", quote("}")) + else: + output = quote(str(output), safe="") + except SerializationError as exc: + raise TypeError("{} must be type {}.".format(name, data_type)) from exc + return output + + def query(self, name, data, data_type, **kwargs): + """Serialize data intended for a URL query. + + :param str name: The name of the query parameter. + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str, list + :raises TypeError: if serialization fails. + :raises ValueError: if data is None + :returns: The serialized query parameter + """ + try: + # Treat the list aside, since we don't want to encode the div separator + if data_type.startswith("["): + internal_data_type = data_type[1:-1] + do_quote = not kwargs.get("skip_quote", False) + return self.serialize_iter(data, internal_data_type, do_quote=do_quote, **kwargs) + + # Not a list, regular serialization + output = self.serialize_data(data, data_type, **kwargs) + if data_type == "bool": + output = json.dumps(output) + if kwargs.get("skip_quote") is True: + output = str(output) + else: + output = quote(str(output), safe="") + except SerializationError as exc: + raise TypeError("{} must be type {}.".format(name, data_type)) from exc + return str(output) + + def header(self, name, data, data_type, **kwargs): + """Serialize data intended for a request header. + + :param str name: The name of the header. + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str + :raises TypeError: if serialization fails. + :raises ValueError: if data is None + :returns: The serialized header + """ + try: + if data_type in ["[str]"]: + data = ["" if d is None else d for d in data] + + output = self.serialize_data(data, data_type, **kwargs) + if data_type == "bool": + output = json.dumps(output) + except SerializationError as exc: + raise TypeError("{} must be type {}.".format(name, data_type)) from exc + return str(output) + + def serialize_data(self, data, data_type, **kwargs): + """Serialize generic data according to supplied data type. + + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :raises AttributeError: if required data is None. + :raises ValueError: if data is None + :raises SerializationError: if serialization fails. + :returns: The serialized data. + :rtype: str, int, float, bool, dict, list + """ + if data is None: + raise ValueError("No value for given attribute") + + try: + if data is CoreNull: + return None + if data_type in self.basic_types.values(): + return self.serialize_basic(data, data_type, **kwargs) + + if data_type in self.serialize_type: + return self.serialize_type[data_type](data, **kwargs) + + # If dependencies is empty, try with current data class + # It has to be a subclass of Enum anyway + enum_type = self.dependencies.get(data_type, data.__class__) + if issubclass(enum_type, Enum): + return Serializer.serialize_enum(data, enum_obj=enum_type) + + iter_type = data_type[0] + data_type[-1] + if iter_type in self.serialize_type: + return self.serialize_type[iter_type](data, data_type[1:-1], **kwargs) + + except (ValueError, TypeError) as err: + msg = "Unable to serialize value: {!r} as type: {!r}." + raise SerializationError(msg.format(data, data_type)) from err + return self._serialize(data, **kwargs) + + @classmethod + def _get_custom_serializers(cls, data_type, **kwargs): # pylint: disable=inconsistent-return-statements + custom_serializer = kwargs.get("basic_types_serializers", {}).get(data_type) + if custom_serializer: + return custom_serializer + if kwargs.get("is_xml", False): + return cls._xml_basic_types_serializers.get(data_type) + + @classmethod + def serialize_basic(cls, data, data_type, **kwargs): + """Serialize basic builting data type. + Serializes objects to str, int, float or bool. + + Possible kwargs: + - basic_types_serializers dict[str, callable] : If set, use the callable as serializer + - is_xml bool : If set, use xml_basic_types_serializers + + :param obj data: Object to be serialized. + :param str data_type: Type of object in the iterable. + :rtype: str, int, float, bool + :return: serialized object + """ + custom_serializer = cls._get_custom_serializers(data_type, **kwargs) + if custom_serializer: + return custom_serializer(data) + if data_type == "str": + return cls.serialize_unicode(data) + return eval(data_type)(data) # nosec # pylint: disable=eval-used + + @classmethod + def serialize_unicode(cls, data): + """Special handling for serializing unicode strings in Py2. + Encode to UTF-8 if unicode, otherwise handle as a str. + + :param str data: Object to be serialized. + :rtype: str + :return: serialized object + """ + try: # If I received an enum, return its value + return data.value + except AttributeError: + pass + + try: + if isinstance(data, unicode): # type: ignore + # Don't change it, JSON and XML ElementTree are totally able + # to serialize correctly u'' strings + return data + except NameError: + return str(data) + return str(data) + + def serialize_iter(self, data, iter_type, div=None, **kwargs): + """Serialize iterable. + + Supported kwargs: + - serialization_ctxt dict : The current entry of _attribute_map, or same format. + serialization_ctxt['type'] should be same as data_type. + - is_xml bool : If set, serialize as XML + + :param list data: Object to be serialized. + :param str iter_type: Type of object in the iterable. + :param str div: If set, this str will be used to combine the elements + in the iterable into a combined string. Default is 'None'. + Defaults to False. + :rtype: list, str + :return: serialized iterable + """ + if isinstance(data, str): + raise SerializationError("Refuse str type as a valid iter type.") + + serialization_ctxt = kwargs.get("serialization_ctxt", {}) + is_xml = kwargs.get("is_xml", False) + + serialized = [] + for d in data: + try: + serialized.append(self.serialize_data(d, iter_type, **kwargs)) + except ValueError as err: + if isinstance(err, SerializationError): + raise + serialized.append(None) + + if kwargs.get("do_quote", False): + serialized = ["" if s is None else quote(str(s), safe="") for s in serialized] + + if div: + serialized = ["" if s is None else str(s) for s in serialized] + serialized = div.join(serialized) + + if "xml" in serialization_ctxt or is_xml: + # XML serialization is more complicated + xml_desc = serialization_ctxt.get("xml", {}) + xml_name = xml_desc.get("name") + if not xml_name: + xml_name = serialization_ctxt["key"] + + # Create a wrap node if necessary (use the fact that Element and list have "append") + is_wrapped = xml_desc.get("wrapped", False) + node_name = xml_desc.get("itemsName", xml_name) + if is_wrapped: + final_result = _create_xml_node(xml_name, xml_desc.get("prefix", None), xml_desc.get("ns", None)) + else: + final_result = [] + # All list elements to "local_node" + for el in serialized: + if isinstance(el, ET.Element): + el_node = el + else: + el_node = _create_xml_node(node_name, xml_desc.get("prefix", None), xml_desc.get("ns", None)) + if el is not None: # Otherwise it writes "None" :-p + el_node.text = str(el) + final_result.append(el_node) + return final_result + return serialized + + def serialize_dict(self, attr, dict_type, **kwargs): + """Serialize a dictionary of objects. + + :param dict attr: Object to be serialized. + :param str dict_type: Type of object in the dictionary. + :rtype: dict + :return: serialized dictionary + """ + serialization_ctxt = kwargs.get("serialization_ctxt", {}) + serialized = {} + for key, value in attr.items(): + try: + serialized[self.serialize_unicode(key)] = self.serialize_data(value, dict_type, **kwargs) + except ValueError as err: + if isinstance(err, SerializationError): + raise + serialized[self.serialize_unicode(key)] = None + + if "xml" in serialization_ctxt: + # XML serialization is more complicated + xml_desc = serialization_ctxt["xml"] + xml_name = xml_desc["name"] + + final_result = _create_xml_node(xml_name, xml_desc.get("prefix", None), xml_desc.get("ns", None)) + for key, value in serialized.items(): + ET.SubElement(final_result, key).text = value + return final_result + + return serialized + + def serialize_object(self, attr, **kwargs): # pylint: disable=too-many-return-statements + """Serialize a generic object. + This will be handled as a dictionary. If object passed in is not + a basic type (str, int, float, dict, list) it will simply be + cast to str. + + :param dict attr: Object to be serialized. + :rtype: dict or str + :return: serialized object + """ + if attr is None: + return None + if isinstance(attr, ET.Element): + return attr + obj_type = type(attr) + if obj_type in self.basic_types: + return self.serialize_basic(attr, self.basic_types[obj_type], **kwargs) + if obj_type is _long_type: + return self.serialize_long(attr) + if obj_type is str: + return self.serialize_unicode(attr) + if obj_type is datetime.datetime: + return self.serialize_iso(attr) + if obj_type is datetime.date: + return self.serialize_date(attr) + if obj_type is datetime.time: + return self.serialize_time(attr) + if obj_type is datetime.timedelta: + return self.serialize_duration(attr) + if obj_type is decimal.Decimal: + return self.serialize_decimal(attr) + + # If it's a model or I know this dependency, serialize as a Model + if obj_type in self.dependencies.values() or isinstance(attr, Model): + return self._serialize(attr) + + if obj_type == dict: + serialized = {} + for key, value in attr.items(): + try: + serialized[self.serialize_unicode(key)] = self.serialize_object(value, **kwargs) + except ValueError: + serialized[self.serialize_unicode(key)] = None + return serialized + + if obj_type == list: + serialized = [] + for obj in attr: + try: + serialized.append(self.serialize_object(obj, **kwargs)) + except ValueError: + pass + return serialized + return str(attr) + + @staticmethod + def serialize_enum(attr, enum_obj=None): + try: + result = attr.value + except AttributeError: + result = attr + try: + enum_obj(result) # type: ignore + return result + except ValueError as exc: + for enum_value in enum_obj: # type: ignore + if enum_value.value.lower() == str(attr).lower(): + return enum_value.value + error = "{!r} is not valid value for enum {!r}" + raise SerializationError(error.format(attr, enum_obj)) from exc + + @staticmethod + def serialize_bytearray(attr, **kwargs): # pylint: disable=unused-argument + """Serialize bytearray into base-64 string. + + :param str attr: Object to be serialized. + :rtype: str + :return: serialized base64 + """ + return b64encode(attr).decode() + + @staticmethod + def serialize_base64(attr, **kwargs): # pylint: disable=unused-argument + """Serialize str into base-64 string. + + :param str attr: Object to be serialized. + :rtype: str + :return: serialized base64 + """ + encoded = b64encode(attr).decode("ascii") + return encoded.strip("=").replace("+", "-").replace("/", "_") + + @staticmethod + def serialize_decimal(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Decimal object to float. + + :param decimal attr: Object to be serialized. + :rtype: float + :return: serialized decimal + """ + return float(attr) + + @staticmethod + def serialize_long(attr, **kwargs): # pylint: disable=unused-argument + """Serialize long (Py2) or int (Py3). + + :param int attr: Object to be serialized. + :rtype: int/long + :return: serialized long + """ + return _long_type(attr) + + @staticmethod + def serialize_date(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Date object into ISO-8601 formatted string. + + :param Date attr: Object to be serialized. + :rtype: str + :return: serialized date + """ + if isinstance(attr, str): + attr = isodate.parse_date(attr) + t = "{:04}-{:02}-{:02}".format(attr.year, attr.month, attr.day) + return t + + @staticmethod + def serialize_time(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Time object into ISO-8601 formatted string. + + :param datetime.time attr: Object to be serialized. + :rtype: str + :return: serialized time + """ + if isinstance(attr, str): + attr = isodate.parse_time(attr) + t = "{:02}:{:02}:{:02}".format(attr.hour, attr.minute, attr.second) + if attr.microsecond: + t += ".{:02}".format(attr.microsecond) + return t + + @staticmethod + def serialize_duration(attr, **kwargs): # pylint: disable=unused-argument + """Serialize TimeDelta object into ISO-8601 formatted string. + + :param TimeDelta attr: Object to be serialized. + :rtype: str + :return: serialized duration + """ + if isinstance(attr, str): + attr = isodate.parse_duration(attr) + return isodate.duration_isoformat(attr) + + @staticmethod + def serialize_rfc(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Datetime object into RFC-1123 formatted string. + + :param Datetime attr: Object to be serialized. + :rtype: str + :raises TypeError: if format invalid. + :return: serialized rfc + """ + try: + if not attr.tzinfo: + _LOGGER.warning("Datetime with no tzinfo will be considered UTC.") + utc = attr.utctimetuple() + except AttributeError as exc: + raise TypeError("RFC1123 object must be valid Datetime object.") from exc + + return "{}, {:02} {} {:04} {:02}:{:02}:{:02} GMT".format( + Serializer.days[utc.tm_wday], + utc.tm_mday, + Serializer.months[utc.tm_mon], + utc.tm_year, + utc.tm_hour, + utc.tm_min, + utc.tm_sec, + ) + + @staticmethod + def serialize_iso(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Datetime object into ISO-8601 formatted string. + + :param Datetime attr: Object to be serialized. + :rtype: str + :raises SerializationError: if format invalid. + :return: serialized iso + """ + if isinstance(attr, str): + attr = isodate.parse_datetime(attr) + try: + if not attr.tzinfo: + _LOGGER.warning("Datetime with no tzinfo will be considered UTC.") + utc = attr.utctimetuple() + if utc.tm_year > 9999 or utc.tm_year < 1: + raise OverflowError("Hit max or min date") + + microseconds = str(attr.microsecond).rjust(6, "0").rstrip("0").ljust(3, "0") + if microseconds: + microseconds = "." + microseconds + date = "{:04}-{:02}-{:02}T{:02}:{:02}:{:02}".format( + utc.tm_year, utc.tm_mon, utc.tm_mday, utc.tm_hour, utc.tm_min, utc.tm_sec + ) + return date + microseconds + "Z" + except (ValueError, OverflowError) as err: + msg = "Unable to serialize datetime object." + raise SerializationError(msg) from err + except AttributeError as err: + msg = "ISO-8601 object must be valid Datetime object." + raise TypeError(msg) from err + + @staticmethod + def serialize_unix(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Datetime object into IntTime format. + This is represented as seconds. + + :param Datetime attr: Object to be serialized. + :rtype: int + :raises SerializationError: if format invalid + :return: serialied unix + """ + if isinstance(attr, int): + return attr + try: + if not attr.tzinfo: + _LOGGER.warning("Datetime with no tzinfo will be considered UTC.") + return int(calendar.timegm(attr.utctimetuple())) + except AttributeError as exc: + raise TypeError("Unix time object must be valid Datetime object.") from exc + + +def rest_key_extractor(attr, attr_desc, data): # pylint: disable=unused-argument + key = attr_desc["key"] + working_data = data + + while "." in key: + # Need the cast, as for some reasons "split" is typed as list[str | Any] + dict_keys = cast(List[str], _FLATTEN.split(key)) + if len(dict_keys) == 1: + key = _decode_attribute_map_key(dict_keys[0]) + break + working_key = _decode_attribute_map_key(dict_keys[0]) + working_data = working_data.get(working_key, data) + if working_data is None: + # If at any point while following flatten JSON path see None, it means + # that all properties under are None as well + return None + key = ".".join(dict_keys[1:]) + + return working_data.get(key) + + +def rest_key_case_insensitive_extractor( # pylint: disable=unused-argument, inconsistent-return-statements + attr, attr_desc, data +): + key = attr_desc["key"] + working_data = data + + while "." in key: + dict_keys = _FLATTEN.split(key) + if len(dict_keys) == 1: + key = _decode_attribute_map_key(dict_keys[0]) + break + working_key = _decode_attribute_map_key(dict_keys[0]) + working_data = attribute_key_case_insensitive_extractor(working_key, None, working_data) + if working_data is None: + # If at any point while following flatten JSON path see None, it means + # that all properties under are None as well + return None + key = ".".join(dict_keys[1:]) + + if working_data: + return attribute_key_case_insensitive_extractor(key, None, working_data) + + +def last_rest_key_extractor(attr, attr_desc, data): # pylint: disable=unused-argument + """Extract the attribute in "data" based on the last part of the JSON path key. + + :param str attr: The attribute to extract + :param dict attr_desc: The attribute description + :param dict data: The data to extract from + :rtype: object + :returns: The extracted attribute + """ + key = attr_desc["key"] + dict_keys = _FLATTEN.split(key) + return attribute_key_extractor(dict_keys[-1], None, data) + + +def last_rest_key_case_insensitive_extractor(attr, attr_desc, data): # pylint: disable=unused-argument + """Extract the attribute in "data" based on the last part of the JSON path key. + + This is the case insensitive version of "last_rest_key_extractor" + :param str attr: The attribute to extract + :param dict attr_desc: The attribute description + :param dict data: The data to extract from + :rtype: object + :returns: The extracted attribute + """ + key = attr_desc["key"] + dict_keys = _FLATTEN.split(key) + return attribute_key_case_insensitive_extractor(dict_keys[-1], None, data) + + +def attribute_key_extractor(attr, _, data): + return data.get(attr) + + +def attribute_key_case_insensitive_extractor(attr, _, data): + found_key = None + lower_attr = attr.lower() + for key in data: + if lower_attr == key.lower(): + found_key = key + break + + return data.get(found_key) + + +def _extract_name_from_internal_type(internal_type): + """Given an internal type XML description, extract correct XML name with namespace. + + :param dict internal_type: An model type + :rtype: tuple + :returns: A tuple XML name + namespace dict + """ + internal_type_xml_map = getattr(internal_type, "_xml_map", {}) + xml_name = internal_type_xml_map.get("name", internal_type.__name__) + xml_ns = internal_type_xml_map.get("ns", None) + if xml_ns: + xml_name = "{{{}}}{}".format(xml_ns, xml_name) + return xml_name + + +def xml_key_extractor(attr, attr_desc, data): # pylint: disable=unused-argument,too-many-return-statements + if isinstance(data, dict): + return None + + # Test if this model is XML ready first + if not isinstance(data, ET.Element): + return None + + xml_desc = attr_desc.get("xml", {}) + xml_name = xml_desc.get("name", attr_desc["key"]) + + # Look for a children + is_iter_type = attr_desc["type"].startswith("[") + is_wrapped = xml_desc.get("wrapped", False) + internal_type = attr_desc.get("internalType", None) + internal_type_xml_map = getattr(internal_type, "_xml_map", {}) + + # Integrate namespace if necessary + xml_ns = xml_desc.get("ns", internal_type_xml_map.get("ns", None)) + if xml_ns: + xml_name = "{{{}}}{}".format(xml_ns, xml_name) + + # If it's an attribute, that's simple + if xml_desc.get("attr", False): + return data.get(xml_name) + + # If it's x-ms-text, that's simple too + if xml_desc.get("text", False): + return data.text + + # Scenario where I take the local name: + # - Wrapped node + # - Internal type is an enum (considered basic types) + # - Internal type has no XML/Name node + if is_wrapped or (internal_type and (issubclass(internal_type, Enum) or "name" not in internal_type_xml_map)): + children = data.findall(xml_name) + # If internal type has a local name and it's not a list, I use that name + elif not is_iter_type and internal_type and "name" in internal_type_xml_map: + xml_name = _extract_name_from_internal_type(internal_type) + children = data.findall(xml_name) + # That's an array + else: + if internal_type: # Complex type, ignore itemsName and use the complex type name + items_name = _extract_name_from_internal_type(internal_type) + else: + items_name = xml_desc.get("itemsName", xml_name) + children = data.findall(items_name) + + if len(children) == 0: + if is_iter_type: + if is_wrapped: + return None # is_wrapped no node, we want None + return [] # not wrapped, assume empty list + return None # Assume it's not there, maybe an optional node. + + # If is_iter_type and not wrapped, return all found children + if is_iter_type: + if not is_wrapped: + return children + # Iter and wrapped, should have found one node only (the wrap one) + if len(children) != 1: + raise DeserializationError( + "Tried to deserialize an array not wrapped, and found several nodes '{}'. Maybe you should declare this array as wrapped?".format( + xml_name + ) + ) + return list(children[0]) # Might be empty list and that's ok. + + # Here it's not a itertype, we should have found one element only or empty + if len(children) > 1: + raise DeserializationError("Find several XML '{}' where it was not expected".format(xml_name)) + return children[0] + + +class Deserializer: + """Response object model deserializer. + + :param dict classes: Class type dictionary for deserializing complex types. + :ivar list key_extractors: Ordered list of extractors to be used by this deserializer. + """ + + basic_types = {str: "str", int: "int", bool: "bool", float: "float"} + + valid_date = re.compile(r"\d{4}[-]\d{2}[-]\d{2}T\d{2}:\d{2}:\d{2}\.?\d*Z?[-+]?[\d{2}]?:?[\d{2}]?") + + def __init__(self, classes: Optional[Mapping[str, type]] = None) -> None: + self.deserialize_type = { + "iso-8601": Deserializer.deserialize_iso, + "rfc-1123": Deserializer.deserialize_rfc, + "unix-time": Deserializer.deserialize_unix, + "duration": Deserializer.deserialize_duration, + "date": Deserializer.deserialize_date, + "time": Deserializer.deserialize_time, + "decimal": Deserializer.deserialize_decimal, + "long": Deserializer.deserialize_long, + "bytearray": Deserializer.deserialize_bytearray, + "base64": Deserializer.deserialize_base64, + "object": self.deserialize_object, + "[]": self.deserialize_iter, + "{}": self.deserialize_dict, + } + self.deserialize_expected_types = { + "duration": (isodate.Duration, datetime.timedelta), + "iso-8601": (datetime.datetime), + } + self.dependencies: Dict[str, type] = dict(classes) if classes else {} + self.key_extractors = [rest_key_extractor, xml_key_extractor] + # Additional properties only works if the "rest_key_extractor" is used to + # extract the keys. Making it to work whatever the key extractor is too much + # complicated, with no real scenario for now. + # So adding a flag to disable additional properties detection. This flag should be + # used if your expect the deserialization to NOT come from a JSON REST syntax. + # Otherwise, result are unexpected + self.additional_properties_detection = True + + def __call__(self, target_obj, response_data, content_type=None): + """Call the deserializer to process a REST response. + + :param str target_obj: Target data type to deserialize to. + :param requests.Response response_data: REST response object. + :param str content_type: Swagger "produces" if available. + :raises DeserializationError: if deserialization fails. + :return: Deserialized object. + :rtype: object + """ + data = self._unpack_content(response_data, content_type) + return self._deserialize(target_obj, data) + + def _deserialize(self, target_obj, data): # pylint: disable=inconsistent-return-statements + """Call the deserializer on a model. + + Data needs to be already deserialized as JSON or XML ElementTree + + :param str target_obj: Target data type to deserialize to. + :param object data: Object to deserialize. + :raises DeserializationError: if deserialization fails. + :return: Deserialized object. + :rtype: object + """ + # This is already a model, go recursive just in case + if hasattr(data, "_attribute_map"): + constants = [name for name, config in getattr(data, "_validation", {}).items() if config.get("constant")] + try: + for attr, mapconfig in data._attribute_map.items(): # pylint: disable=protected-access + if attr in constants: + continue + value = getattr(data, attr) + if value is None: + continue + local_type = mapconfig["type"] + internal_data_type = local_type.strip("[]{}") + if internal_data_type not in self.dependencies or isinstance(internal_data_type, Enum): + continue + setattr(data, attr, self._deserialize(local_type, value)) + return data + except AttributeError: + return + + response, class_name = self._classify_target(target_obj, data) + + if isinstance(response, str): + return self.deserialize_data(data, response) + if isinstance(response, type) and issubclass(response, Enum): + return self.deserialize_enum(data, response) + + if data is None or data is CoreNull: + return data + try: + attributes = response._attribute_map # type: ignore # pylint: disable=protected-access + d_attrs = {} + for attr, attr_desc in attributes.items(): + # Check empty string. If it's not empty, someone has a real "additionalProperties"... + if attr == "additional_properties" and attr_desc["key"] == "": + continue + raw_value = None + # Enhance attr_desc with some dynamic data + attr_desc = attr_desc.copy() # Do a copy, do not change the real one + internal_data_type = attr_desc["type"].strip("[]{}") + if internal_data_type in self.dependencies: + attr_desc["internalType"] = self.dependencies[internal_data_type] + + for key_extractor in self.key_extractors: + found_value = key_extractor(attr, attr_desc, data) + if found_value is not None: + if raw_value is not None and raw_value != found_value: + msg = ( + "Ignoring extracted value '%s' from %s for key '%s'" + " (duplicate extraction, follow extractors order)" + ) + _LOGGER.warning(msg, found_value, key_extractor, attr) + continue + raw_value = found_value + + value = self.deserialize_data(raw_value, attr_desc["type"]) + d_attrs[attr] = value + except (AttributeError, TypeError, KeyError) as err: + msg = "Unable to deserialize to object: " + class_name # type: ignore + raise DeserializationError(msg) from err + additional_properties = self._build_additional_properties(attributes, data) + return self._instantiate_model(response, d_attrs, additional_properties) + + def _build_additional_properties(self, attribute_map, data): + if not self.additional_properties_detection: + return None + if "additional_properties" in attribute_map and attribute_map.get("additional_properties", {}).get("key") != "": + # Check empty string. If it's not empty, someone has a real "additionalProperties" + return None + if isinstance(data, ET.Element): + data = {el.tag: el.text for el in data} + + known_keys = { + _decode_attribute_map_key(_FLATTEN.split(desc["key"])[0]) + for desc in attribute_map.values() + if desc["key"] != "" + } + present_keys = set(data.keys()) + missing_keys = present_keys - known_keys + return {key: data[key] for key in missing_keys} + + def _classify_target(self, target, data): + """Check to see whether the deserialization target object can + be classified into a subclass. + Once classification has been determined, initialize object. + + :param str target: The target object type to deserialize to. + :param str/dict data: The response data to deserialize. + :return: The classified target object and its class name. + :rtype: tuple + """ + if target is None: + return None, None + + if isinstance(target, str): + try: + target = self.dependencies[target] + except KeyError: + return target, target + + try: + target = target._classify(data, self.dependencies) # type: ignore # pylint: disable=protected-access + except AttributeError: + pass # Target is not a Model, no classify + return target, target.__class__.__name__ # type: ignore + + def failsafe_deserialize(self, target_obj, data, content_type=None): + """Ignores any errors encountered in deserialization, + and falls back to not deserializing the object. Recommended + for use in error deserialization, as we want to return the + HttpResponseError to users, and not have them deal with + a deserialization error. + + :param str target_obj: The target object type to deserialize to. + :param str/dict data: The response data to deserialize. + :param str content_type: Swagger "produces" if available. + :return: Deserialized object. + :rtype: object + """ + try: + return self(target_obj, data, content_type=content_type) + except: # pylint: disable=bare-except + _LOGGER.debug( + "Ran into a deserialization error. Ignoring since this is failsafe deserialization", exc_info=True + ) + return None + + @staticmethod + def _unpack_content(raw_data, content_type=None): + """Extract the correct structure for deserialization. + + If raw_data is a PipelineResponse, try to extract the result of RawDeserializer. + if we can't, raise. Your Pipeline should have a RawDeserializer. + + If not a pipeline response and raw_data is bytes or string, use content-type + to decode it. If no content-type, try JSON. + + If raw_data is something else, bypass all logic and return it directly. + + :param obj raw_data: Data to be processed. + :param str content_type: How to parse if raw_data is a string/bytes. + :raises JSONDecodeError: If JSON is requested and parsing is impossible. + :raises UnicodeDecodeError: If bytes is not UTF8 + :rtype: object + :return: Unpacked content. + """ + # Assume this is enough to detect a Pipeline Response without importing it + context = getattr(raw_data, "context", {}) + if context: + if RawDeserializer.CONTEXT_NAME in context: + return context[RawDeserializer.CONTEXT_NAME] + raise ValueError("This pipeline didn't have the RawDeserializer policy; can't deserialize") + + # Assume this is enough to recognize universal_http.ClientResponse without importing it + if hasattr(raw_data, "body"): + return RawDeserializer.deserialize_from_http_generics(raw_data.text(), raw_data.headers) + + # Assume this enough to recognize requests.Response without importing it. + if hasattr(raw_data, "_content_consumed"): + return RawDeserializer.deserialize_from_http_generics(raw_data.text, raw_data.headers) + + if isinstance(raw_data, (str, bytes)) or hasattr(raw_data, "read"): + return RawDeserializer.deserialize_from_text(raw_data, content_type) # type: ignore + return raw_data + + def _instantiate_model(self, response, attrs, additional_properties=None): + """Instantiate a response model passing in deserialized args. + + :param Response response: The response model class. + :param dict attrs: The deserialized response attributes. + :param dict additional_properties: Additional properties to be set. + :rtype: Response + :return: The instantiated response model. + """ + if callable(response): + subtype = getattr(response, "_subtype_map", {}) + try: + readonly = [ + k + for k, v in response._validation.items() # pylint: disable=protected-access # type: ignore + if v.get("readonly") + ] + const = [ + k + for k, v in response._validation.items() # pylint: disable=protected-access # type: ignore + if v.get("constant") + ] + kwargs = {k: v for k, v in attrs.items() if k not in subtype and k not in readonly + const} + response_obj = response(**kwargs) + for attr in readonly: + setattr(response_obj, attr, attrs.get(attr)) + if additional_properties: + response_obj.additional_properties = additional_properties # type: ignore + return response_obj + except TypeError as err: + msg = "Unable to deserialize {} into model {}. ".format(kwargs, response) # type: ignore + raise DeserializationError(msg + str(err)) from err + else: + try: + for attr, value in attrs.items(): + setattr(response, attr, value) + return response + except Exception as exp: + msg = "Unable to populate response model. " + msg += "Type: {}, Error: {}".format(type(response), exp) + raise DeserializationError(msg) from exp + + def deserialize_data(self, data, data_type): # pylint: disable=too-many-return-statements + """Process data for deserialization according to data type. + + :param str data: The response string to be deserialized. + :param str data_type: The type to deserialize to. + :raises DeserializationError: if deserialization fails. + :return: Deserialized object. + :rtype: object + """ + if data is None: + return data + + try: + if not data_type: + return data + if data_type in self.basic_types.values(): + return self.deserialize_basic(data, data_type) + if data_type in self.deserialize_type: + if isinstance(data, self.deserialize_expected_types.get(data_type, tuple())): + return data + + is_a_text_parsing_type = lambda x: x not in [ # pylint: disable=unnecessary-lambda-assignment + "object", + "[]", + r"{}", + ] + if isinstance(data, ET.Element) and is_a_text_parsing_type(data_type) and not data.text: + return None + data_val = self.deserialize_type[data_type](data) + return data_val + + iter_type = data_type[0] + data_type[-1] + if iter_type in self.deserialize_type: + return self.deserialize_type[iter_type](data, data_type[1:-1]) + + obj_type = self.dependencies[data_type] + if issubclass(obj_type, Enum): + if isinstance(data, ET.Element): + data = data.text + return self.deserialize_enum(data, obj_type) + + except (ValueError, TypeError, AttributeError) as err: + msg = "Unable to deserialize response data." + msg += " Data: {}, {}".format(data, data_type) + raise DeserializationError(msg) from err + return self._deserialize(obj_type, data) + + def deserialize_iter(self, attr, iter_type): + """Deserialize an iterable. + + :param list attr: Iterable to be deserialized. + :param str iter_type: The type of object in the iterable. + :return: Deserialized iterable. + :rtype: list + """ + if attr is None: + return None + if isinstance(attr, ET.Element): # If I receive an element here, get the children + attr = list(attr) + if not isinstance(attr, (list, set)): + raise DeserializationError("Cannot deserialize as [{}] an object of type {}".format(iter_type, type(attr))) + return [self.deserialize_data(a, iter_type) for a in attr] + + def deserialize_dict(self, attr, dict_type): + """Deserialize a dictionary. + + :param dict/list attr: Dictionary to be deserialized. Also accepts + a list of key, value pairs. + :param str dict_type: The object type of the items in the dictionary. + :return: Deserialized dictionary. + :rtype: dict + """ + if isinstance(attr, list): + return {x["key"]: self.deserialize_data(x["value"], dict_type) for x in attr} + + if isinstance(attr, ET.Element): + # Transform value into {"Key": "value"} + attr = {el.tag: el.text for el in attr} + return {k: self.deserialize_data(v, dict_type) for k, v in attr.items()} + + def deserialize_object(self, attr, **kwargs): # pylint: disable=too-many-return-statements + """Deserialize a generic object. + This will be handled as a dictionary. + + :param dict attr: Dictionary to be deserialized. + :return: Deserialized object. + :rtype: dict + :raises TypeError: if non-builtin datatype encountered. + """ + if attr is None: + return None + if isinstance(attr, ET.Element): + # Do no recurse on XML, just return the tree as-is + return attr + if isinstance(attr, str): + return self.deserialize_basic(attr, "str") + obj_type = type(attr) + if obj_type in self.basic_types: + return self.deserialize_basic(attr, self.basic_types[obj_type]) + if obj_type is _long_type: + return self.deserialize_long(attr) + + if obj_type == dict: + deserialized = {} + for key, value in attr.items(): + try: + deserialized[key] = self.deserialize_object(value, **kwargs) + except ValueError: + deserialized[key] = None + return deserialized + + if obj_type == list: + deserialized = [] + for obj in attr: + try: + deserialized.append(self.deserialize_object(obj, **kwargs)) + except ValueError: + pass + return deserialized + + error = "Cannot deserialize generic object with type: " + raise TypeError(error + str(obj_type)) + + def deserialize_basic(self, attr, data_type): # pylint: disable=too-many-return-statements + """Deserialize basic builtin data type from string. + Will attempt to convert to str, int, float and bool. + This function will also accept '1', '0', 'true' and 'false' as + valid bool values. + + :param str attr: response string to be deserialized. + :param str data_type: deserialization data type. + :return: Deserialized basic type. + :rtype: str, int, float or bool + :raises TypeError: if string format is not valid. + """ + # If we're here, data is supposed to be a basic type. + # If it's still an XML node, take the text + if isinstance(attr, ET.Element): + attr = attr.text + if not attr: + if data_type == "str": + # None or '', node is empty string. + return "" + # None or '', node with a strong type is None. + # Don't try to model "empty bool" or "empty int" + return None + + if data_type == "bool": + if attr in [True, False, 1, 0]: + return bool(attr) + if isinstance(attr, str): + if attr.lower() in ["true", "1"]: + return True + if attr.lower() in ["false", "0"]: + return False + raise TypeError("Invalid boolean value: {}".format(attr)) + + if data_type == "str": + return self.deserialize_unicode(attr) + return eval(data_type)(attr) # nosec # pylint: disable=eval-used + + @staticmethod + def deserialize_unicode(data): + """Preserve unicode objects in Python 2, otherwise return data + as a string. + + :param str data: response string to be deserialized. + :return: Deserialized string. + :rtype: str or unicode + """ + # We might be here because we have an enum modeled as string, + # and we try to deserialize a partial dict with enum inside + if isinstance(data, Enum): + return data + + # Consider this is real string + try: + if isinstance(data, unicode): # type: ignore + return data + except NameError: + return str(data) + return str(data) + + @staticmethod + def deserialize_enum(data, enum_obj): + """Deserialize string into enum object. + + If the string is not a valid enum value it will be returned as-is + and a warning will be logged. + + :param str data: Response string to be deserialized. If this value is + None or invalid it will be returned as-is. + :param Enum enum_obj: Enum object to deserialize to. + :return: Deserialized enum object. + :rtype: Enum + """ + if isinstance(data, enum_obj) or data is None: + return data + if isinstance(data, Enum): + data = data.value + if isinstance(data, int): + # Workaround. We might consider remove it in the future. + try: + return list(enum_obj.__members__.values())[data] + except IndexError as exc: + error = "{!r} is not a valid index for enum {!r}" + raise DeserializationError(error.format(data, enum_obj)) from exc + try: + return enum_obj(str(data)) + except ValueError: + for enum_value in enum_obj: + if enum_value.value.lower() == str(data).lower(): + return enum_value + # We don't fail anymore for unknown value, we deserialize as a string + _LOGGER.warning("Deserializer is not able to find %s as valid enum in %s", data, enum_obj) + return Deserializer.deserialize_unicode(data) + + @staticmethod + def deserialize_bytearray(attr): + """Deserialize string into bytearray. + + :param str attr: response string to be deserialized. + :return: Deserialized bytearray + :rtype: bytearray + :raises TypeError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + return bytearray(b64decode(attr)) # type: ignore + + @staticmethod + def deserialize_base64(attr): + """Deserialize base64 encoded string into string. + + :param str attr: response string to be deserialized. + :return: Deserialized base64 string + :rtype: bytearray + :raises TypeError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + padding = "=" * (3 - (len(attr) + 3) % 4) # type: ignore + attr = attr + padding # type: ignore + encoded = attr.replace("-", "+").replace("_", "/") + return b64decode(encoded) + + @staticmethod + def deserialize_decimal(attr): + """Deserialize string into Decimal object. + + :param str attr: response string to be deserialized. + :return: Deserialized decimal + :raises DeserializationError: if string format invalid. + :rtype: decimal + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + return decimal.Decimal(str(attr)) # type: ignore + except decimal.DecimalException as err: + msg = "Invalid decimal {}".format(attr) + raise DeserializationError(msg) from err + + @staticmethod + def deserialize_long(attr): + """Deserialize string into long (Py2) or int (Py3). + + :param str attr: response string to be deserialized. + :return: Deserialized int + :rtype: long or int + :raises ValueError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + return _long_type(attr) # type: ignore + + @staticmethod + def deserialize_duration(attr): + """Deserialize ISO-8601 formatted string into TimeDelta object. + + :param str attr: response string to be deserialized. + :return: Deserialized duration + :rtype: TimeDelta + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + duration = isodate.parse_duration(attr) + except (ValueError, OverflowError, AttributeError) as err: + msg = "Cannot deserialize duration object." + raise DeserializationError(msg) from err + return duration + + @staticmethod + def deserialize_date(attr): + """Deserialize ISO-8601 formatted string into Date object. + + :param str attr: response string to be deserialized. + :return: Deserialized date + :rtype: Date + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + if re.search(r"[^\W\d_]", attr, re.I + re.U): # type: ignore + raise DeserializationError("Date must have only digits and -. Received: %s" % attr) + # This must NOT use defaultmonth/defaultday. Using None ensure this raises an exception. + return isodate.parse_date(attr, defaultmonth=0, defaultday=0) + + @staticmethod + def deserialize_time(attr): + """Deserialize ISO-8601 formatted string into time object. + + :param str attr: response string to be deserialized. + :return: Deserialized time + :rtype: datetime.time + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + if re.search(r"[^\W\d_]", attr, re.I + re.U): # type: ignore + raise DeserializationError("Date must have only digits and -. Received: %s" % attr) + return isodate.parse_time(attr) + + @staticmethod + def deserialize_rfc(attr): + """Deserialize RFC-1123 formatted string into Datetime object. + + :param str attr: response string to be deserialized. + :return: Deserialized RFC datetime + :rtype: Datetime + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + parsed_date = email.utils.parsedate_tz(attr) # type: ignore + date_obj = datetime.datetime( + *parsed_date[:6], tzinfo=datetime.timezone(datetime.timedelta(minutes=(parsed_date[9] or 0) / 60)) + ) + if not date_obj.tzinfo: + date_obj = date_obj.astimezone(tz=TZ_UTC) + except ValueError as err: + msg = "Cannot deserialize to rfc datetime object." + raise DeserializationError(msg) from err + return date_obj + + @staticmethod + def deserialize_iso(attr): + """Deserialize ISO-8601 formatted string into Datetime object. + + :param str attr: response string to be deserialized. + :return: Deserialized ISO datetime + :rtype: Datetime + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + attr = attr.upper() # type: ignore + match = Deserializer.valid_date.match(attr) + if not match: + raise ValueError("Invalid datetime string: " + attr) + + check_decimal = attr.split(".") + if len(check_decimal) > 1: + decimal_str = "" + for digit in check_decimal[1]: + if digit.isdigit(): + decimal_str += digit + else: + break + if len(decimal_str) > 6: + attr = attr.replace(decimal_str, decimal_str[0:6]) + + date_obj = isodate.parse_datetime(attr) + test_utc = date_obj.utctimetuple() + if test_utc.tm_year > 9999 or test_utc.tm_year < 1: + raise OverflowError("Hit max or min date") + except (ValueError, OverflowError, AttributeError) as err: + msg = "Cannot deserialize datetime object." + raise DeserializationError(msg) from err + return date_obj + + @staticmethod + def deserialize_unix(attr): + """Serialize Datetime object into IntTime format. + This is represented as seconds. + + :param int attr: Object to be serialized. + :return: Deserialized datetime + :rtype: Datetime + :raises DeserializationError: if format invalid + """ + if isinstance(attr, ET.Element): + attr = int(attr.text) # type: ignore + try: + attr = int(attr) + date_obj = datetime.datetime.fromtimestamp(attr, TZ_UTC) + except ValueError as err: + msg = "Cannot deserialize to unix datetime object." + raise DeserializationError(msg) from err + return date_obj diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/HeaderVersionTolerant/headerversiontolerant/aio/_client.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/HeaderVersionTolerant/headerversiontolerant/aio/_client.py index 6b508dc60b7..261d39ffcfb 100644 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/HeaderVersionTolerant/headerversiontolerant/aio/_client.py +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/HeaderVersionTolerant/headerversiontolerant/aio/_client.py @@ -14,7 +14,7 @@ from azure.core.pipeline import policies from azure.core.rest import AsyncHttpResponse, HttpRequest -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import AutoRestSwaggerBATHeaderServiceConfiguration from .operations import HeaderOperations diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/HeaderVersionTolerant/headerversiontolerant/aio/operations/_operations.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/HeaderVersionTolerant/headerversiontolerant/aio/operations/_operations.py index bc285785e84..3efe5e2eb49 100644 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/HeaderVersionTolerant/headerversiontolerant/aio/operations/_operations.py +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/HeaderVersionTolerant/headerversiontolerant/aio/operations/_operations.py @@ -23,7 +23,7 @@ from azure.core.rest import AsyncHttpResponse, HttpRequest from azure.core.tracing.decorator_async import distributed_trace_async -from ..._serialization import Deserializer, Serializer +from ..._utils.serialization import Deserializer, Serializer from ...operations._operations import ( build_header_custom_request_id_request, build_header_param_bool_request, diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/HeaderVersionTolerant/headerversiontolerant/operations/_operations.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/HeaderVersionTolerant/headerversiontolerant/operations/_operations.py index 0b1d92f08a7..a7cefc9cb07 100644 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/HeaderVersionTolerant/headerversiontolerant/operations/_operations.py +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/HeaderVersionTolerant/headerversiontolerant/operations/_operations.py @@ -25,7 +25,7 @@ from azure.core.utils import case_insensitive_dict from .._configuration import AutoRestSwaggerBATHeaderServiceConfiguration -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/HttpVersionTolerant/httpinfrastructureversiontolerant/_client.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/HttpVersionTolerant/httpinfrastructureversiontolerant/_client.py index 805e44def7e..da057a813b2 100644 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/HttpVersionTolerant/httpinfrastructureversiontolerant/_client.py +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/HttpVersionTolerant/httpinfrastructureversiontolerant/_client.py @@ -16,7 +16,7 @@ from azure.core.rest import HttpRequest, HttpResponse from ._configuration import AutoRestHttpInfrastructureTestServiceConfiguration -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer from .operations import ( HttpClientFailureOperations, HttpFailureOperations, diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/HttpVersionTolerant/httpinfrastructureversiontolerant/_utils/__init__.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/HttpVersionTolerant/httpinfrastructureversiontolerant/_utils/__init__.py new file mode 100644 index 00000000000..0af9b28f660 --- /dev/null +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/HttpVersionTolerant/httpinfrastructureversiontolerant/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/HttpVersionTolerant/httpinfrastructureversiontolerant/_utils/serialization.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/HttpVersionTolerant/httpinfrastructureversiontolerant/_utils/serialization.py new file mode 100644 index 00000000000..f5187701d7b --- /dev/null +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/HttpVersionTolerant/httpinfrastructureversiontolerant/_utils/serialization.py @@ -0,0 +1,2032 @@ +# pylint: disable=line-too-long,useless-suppression,too-many-lines +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +# pyright: reportUnnecessaryTypeIgnoreComment=false + +from base64 import b64decode, b64encode +import calendar +import datetime +import decimal +import email +from enum import Enum +import json +import logging +import re +import sys +import codecs +from typing import ( + Dict, + Any, + cast, + Optional, + Union, + AnyStr, + IO, + Mapping, + Callable, + MutableMapping, + List, +) + +try: + from urllib import quote # type: ignore +except ImportError: + from urllib.parse import quote +import xml.etree.ElementTree as ET + +import isodate # type: ignore +from typing_extensions import Self + +from azure.core.exceptions import DeserializationError, SerializationError +from azure.core.serialization import NULL as CoreNull + +_BOM = codecs.BOM_UTF8.decode(encoding="utf-8") + +JSON = MutableMapping[str, Any] + + +class RawDeserializer: + + # Accept "text" because we're open minded people... + JSON_REGEXP = re.compile(r"^(application|text)/([a-z+.]+\+)?json$") + + # Name used in context + CONTEXT_NAME = "deserialized_data" + + @classmethod + def deserialize_from_text(cls, data: Optional[Union[AnyStr, IO]], content_type: Optional[str] = None) -> Any: + """Decode data according to content-type. + + Accept a stream of data as well, but will be load at once in memory for now. + + If no content-type, will return the string version (not bytes, not stream) + + :param data: Input, could be bytes or stream (will be decoded with UTF8) or text + :type data: str or bytes or IO + :param str content_type: The content type. + :return: The deserialized data. + :rtype: object + """ + if hasattr(data, "read"): + # Assume a stream + data = cast(IO, data).read() + + if isinstance(data, bytes): + data_as_str = data.decode(encoding="utf-8-sig") + else: + # Explain to mypy the correct type. + data_as_str = cast(str, data) + + # Remove Byte Order Mark if present in string + data_as_str = data_as_str.lstrip(_BOM) + + if content_type is None: + return data + + if cls.JSON_REGEXP.match(content_type): + try: + return json.loads(data_as_str) + except ValueError as err: + raise DeserializationError("JSON is invalid: {}".format(err), err) from err + elif "xml" in (content_type or []): + try: + + try: + if isinstance(data, unicode): # type: ignore + # If I'm Python 2.7 and unicode XML will scream if I try a "fromstring" on unicode string + data_as_str = data_as_str.encode(encoding="utf-8") # type: ignore + except NameError: + pass + + return ET.fromstring(data_as_str) # nosec + except ET.ParseError as err: + # It might be because the server has an issue, and returned JSON with + # content-type XML.... + # So let's try a JSON load, and if it's still broken + # let's flow the initial exception + def _json_attemp(data): + try: + return True, json.loads(data) + except ValueError: + return False, None # Don't care about this one + + success, json_result = _json_attemp(data) + if success: + return json_result + # If i'm here, it's not JSON, it's not XML, let's scream + # and raise the last context in this block (the XML exception) + # The function hack is because Py2.7 messes up with exception + # context otherwise. + _LOGGER.critical("Wasn't XML not JSON, failing") + raise DeserializationError("XML is invalid") from err + elif content_type.startswith("text/"): + return data_as_str + raise DeserializationError("Cannot deserialize content-type: {}".format(content_type)) + + @classmethod + def deserialize_from_http_generics(cls, body_bytes: Optional[Union[AnyStr, IO]], headers: Mapping) -> Any: + """Deserialize from HTTP response. + + Use bytes and headers to NOT use any requests/aiohttp or whatever + specific implementation. + Headers will tested for "content-type" + + :param bytes body_bytes: The body of the response. + :param dict headers: The headers of the response. + :returns: The deserialized data. + :rtype: object + """ + # Try to use content-type from headers if available + content_type = None + if "content-type" in headers: + content_type = headers["content-type"].split(";")[0].strip().lower() + # Ouch, this server did not declare what it sent... + # Let's guess it's JSON... + # Also, since Autorest was considering that an empty body was a valid JSON, + # need that test as well.... + else: + content_type = "application/json" + + if body_bytes: + return cls.deserialize_from_text(body_bytes, content_type) + return None + + +_LOGGER = logging.getLogger(__name__) + +try: + _long_type = long # type: ignore +except NameError: + _long_type = int + +TZ_UTC = datetime.timezone.utc + +_FLATTEN = re.compile(r"(? None: + self.additional_properties: Optional[Dict[str, Any]] = {} + for k in kwargs: # pylint: disable=consider-using-dict-items + if k not in self._attribute_map: + _LOGGER.warning("%s is not a known attribute of class %s and will be ignored", k, self.__class__) + elif k in self._validation and self._validation[k].get("readonly", False): + _LOGGER.warning("Readonly attribute %s will be ignored in class %s", k, self.__class__) + else: + setattr(self, k, kwargs[k]) + + def __eq__(self, other: Any) -> bool: + """Compare objects by comparing all attributes. + + :param object other: The object to compare + :returns: True if objects are equal + :rtype: bool + """ + if isinstance(other, self.__class__): + return self.__dict__ == other.__dict__ + return False + + def __ne__(self, other: Any) -> bool: + """Compare objects by comparing all attributes. + + :param object other: The object to compare + :returns: True if objects are not equal + :rtype: bool + """ + return not self.__eq__(other) + + def __str__(self) -> str: + return str(self.__dict__) + + @classmethod + def enable_additional_properties_sending(cls) -> None: + cls._attribute_map["additional_properties"] = {"key": "", "type": "{object}"} + + @classmethod + def is_xml_model(cls) -> bool: + try: + cls._xml_map # type: ignore + except AttributeError: + return False + return True + + @classmethod + def _create_xml_node(cls): + """Create XML node. + + :returns: The XML node + :rtype: xml.etree.ElementTree.Element + """ + try: + xml_map = cls._xml_map # type: ignore + except AttributeError: + xml_map = {} + + return _create_xml_node(xml_map.get("name", cls.__name__), xml_map.get("prefix", None), xml_map.get("ns", None)) + + def serialize(self, keep_readonly: bool = False, **kwargs: Any) -> JSON: + """Return the JSON that would be sent to server from this model. + + This is an alias to `as_dict(full_restapi_key_transformer, keep_readonly=False)`. + + If you want XML serialization, you can pass the kwargs is_xml=True. + + :param bool keep_readonly: If you want to serialize the readonly attributes + :returns: A dict JSON compatible object + :rtype: dict + """ + serializer = Serializer(self._infer_class_models()) + return serializer._serialize( # type: ignore # pylint: disable=protected-access + self, keep_readonly=keep_readonly, **kwargs + ) + + def as_dict( + self, + keep_readonly: bool = True, + key_transformer: Callable[[str, Dict[str, Any], Any], Any] = attribute_transformer, + **kwargs: Any + ) -> JSON: + """Return a dict that can be serialized using json.dump. + + Advanced usage might optionally use a callback as parameter: + + .. code::python + + def my_key_transformer(key, attr_desc, value): + return key + + Key is the attribute name used in Python. Attr_desc + is a dict of metadata. Currently contains 'type' with the + msrest type and 'key' with the RestAPI encoded key. + Value is the current value in this object. + + The string returned will be used to serialize the key. + If the return type is a list, this is considered hierarchical + result dict. + + See the three examples in this file: + + - attribute_transformer + - full_restapi_key_transformer + - last_restapi_key_transformer + + If you want XML serialization, you can pass the kwargs is_xml=True. + + :param bool keep_readonly: If you want to serialize the readonly attributes + :param function key_transformer: A key transformer function. + :returns: A dict JSON compatible object + :rtype: dict + """ + serializer = Serializer(self._infer_class_models()) + return serializer._serialize( # type: ignore # pylint: disable=protected-access + self, key_transformer=key_transformer, keep_readonly=keep_readonly, **kwargs + ) + + @classmethod + def _infer_class_models(cls): + try: + str_models = cls.__module__.rsplit(".", 1)[0] + models = sys.modules[str_models] + client_models = {k: v for k, v in models.__dict__.items() if isinstance(v, type)} + if cls.__name__ not in client_models: + raise ValueError("Not Autorest generated code") + except Exception: # pylint: disable=broad-exception-caught + # Assume it's not Autorest generated (tests?). Add ourselves as dependencies. + client_models = {cls.__name__: cls} + return client_models + + @classmethod + def deserialize(cls, data: Any, content_type: Optional[str] = None) -> Self: + """Parse a str using the RestAPI syntax and return a model. + + :param str data: A str using RestAPI structure. JSON by default. + :param str content_type: JSON by default, set application/xml if XML. + :returns: An instance of this model + :raises DeserializationError: if something went wrong + :rtype: Self + """ + deserializer = Deserializer(cls._infer_class_models()) + return deserializer(cls.__name__, data, content_type=content_type) # type: ignore + + @classmethod + def from_dict( + cls, + data: Any, + key_extractors: Optional[Callable[[str, Dict[str, Any], Any], Any]] = None, + content_type: Optional[str] = None, + ) -> Self: + """Parse a dict using given key extractor return a model. + + By default consider key + extractors (rest_key_case_insensitive_extractor, attribute_key_case_insensitive_extractor + and last_rest_key_case_insensitive_extractor) + + :param dict data: A dict using RestAPI structure + :param function key_extractors: A key extractor function. + :param str content_type: JSON by default, set application/xml if XML. + :returns: An instance of this model + :raises DeserializationError: if something went wrong + :rtype: Self + """ + deserializer = Deserializer(cls._infer_class_models()) + deserializer.key_extractors = ( # type: ignore + [ # type: ignore + attribute_key_case_insensitive_extractor, + rest_key_case_insensitive_extractor, + last_rest_key_case_insensitive_extractor, + ] + if key_extractors is None + else key_extractors + ) + return deserializer(cls.__name__, data, content_type=content_type) # type: ignore + + @classmethod + def _flatten_subtype(cls, key, objects): + if "_subtype_map" not in cls.__dict__: + return {} + result = dict(cls._subtype_map[key]) + for valuetype in cls._subtype_map[key].values(): + result.update(objects[valuetype]._flatten_subtype(key, objects)) # pylint: disable=protected-access + return result + + @classmethod + def _classify(cls, response, objects): + """Check the class _subtype_map for any child classes. + We want to ignore any inherited _subtype_maps. + + :param dict response: The initial data + :param dict objects: The class objects + :returns: The class to be used + :rtype: class + """ + for subtype_key in cls.__dict__.get("_subtype_map", {}).keys(): + subtype_value = None + + if not isinstance(response, ET.Element): + rest_api_response_key = cls._get_rest_key_parts(subtype_key)[-1] + subtype_value = response.get(rest_api_response_key, None) or response.get(subtype_key, None) + else: + subtype_value = xml_key_extractor(subtype_key, cls._attribute_map[subtype_key], response) + if subtype_value: + # Try to match base class. Can be class name only + # (bug to fix in Autorest to support x-ms-discriminator-name) + if cls.__name__ == subtype_value: + return cls + flatten_mapping_type = cls._flatten_subtype(subtype_key, objects) + try: + return objects[flatten_mapping_type[subtype_value]] # type: ignore + except KeyError: + _LOGGER.warning( + "Subtype value %s has no mapping, use base class %s.", + subtype_value, + cls.__name__, + ) + break + else: + _LOGGER.warning("Discriminator %s is absent or null, use base class %s.", subtype_key, cls.__name__) + break + return cls + + @classmethod + def _get_rest_key_parts(cls, attr_key): + """Get the RestAPI key of this attr, split it and decode part + :param str attr_key: Attribute key must be in attribute_map. + :returns: A list of RestAPI part + :rtype: list + """ + rest_split_key = _FLATTEN.split(cls._attribute_map[attr_key]["key"]) + return [_decode_attribute_map_key(key_part) for key_part in rest_split_key] + + +def _decode_attribute_map_key(key): + """This decode a key in an _attribute_map to the actual key we want to look at + inside the received data. + + :param str key: A key string from the generated code + :returns: The decoded key + :rtype: str + """ + return key.replace("\\.", ".") + + +class Serializer: # pylint: disable=too-many-public-methods + """Request object model serializer.""" + + basic_types = {str: "str", int: "int", bool: "bool", float: "float"} + + _xml_basic_types_serializers = {"bool": lambda x: str(x).lower()} + days = {0: "Mon", 1: "Tue", 2: "Wed", 3: "Thu", 4: "Fri", 5: "Sat", 6: "Sun"} + months = { + 1: "Jan", + 2: "Feb", + 3: "Mar", + 4: "Apr", + 5: "May", + 6: "Jun", + 7: "Jul", + 8: "Aug", + 9: "Sep", + 10: "Oct", + 11: "Nov", + 12: "Dec", + } + validation = { + "min_length": lambda x, y: len(x) < y, + "max_length": lambda x, y: len(x) > y, + "minimum": lambda x, y: x < y, + "maximum": lambda x, y: x > y, + "minimum_ex": lambda x, y: x <= y, + "maximum_ex": lambda x, y: x >= y, + "min_items": lambda x, y: len(x) < y, + "max_items": lambda x, y: len(x) > y, + "pattern": lambda x, y: not re.match(y, x, re.UNICODE), + "unique": lambda x, y: len(x) != len(set(x)), + "multiple": lambda x, y: x % y != 0, + } + + def __init__(self, classes: Optional[Mapping[str, type]] = None) -> None: + self.serialize_type = { + "iso-8601": Serializer.serialize_iso, + "rfc-1123": Serializer.serialize_rfc, + "unix-time": Serializer.serialize_unix, + "duration": Serializer.serialize_duration, + "date": Serializer.serialize_date, + "time": Serializer.serialize_time, + "decimal": Serializer.serialize_decimal, + "long": Serializer.serialize_long, + "bytearray": Serializer.serialize_bytearray, + "base64": Serializer.serialize_base64, + "object": self.serialize_object, + "[]": self.serialize_iter, + "{}": self.serialize_dict, + } + self.dependencies: Dict[str, type] = dict(classes) if classes else {} + self.key_transformer = full_restapi_key_transformer + self.client_side_validation = True + + def _serialize( # pylint: disable=too-many-nested-blocks, too-many-branches, too-many-statements, too-many-locals + self, target_obj, data_type=None, **kwargs + ): + """Serialize data into a string according to type. + + :param object target_obj: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str, dict + :raises SerializationError: if serialization fails. + :returns: The serialized data. + """ + key_transformer = kwargs.get("key_transformer", self.key_transformer) + keep_readonly = kwargs.get("keep_readonly", False) + if target_obj is None: + return None + + attr_name = None + class_name = target_obj.__class__.__name__ + + if data_type: + return self.serialize_data(target_obj, data_type, **kwargs) + + if not hasattr(target_obj, "_attribute_map"): + data_type = type(target_obj).__name__ + if data_type in self.basic_types.values(): + return self.serialize_data(target_obj, data_type, **kwargs) + + # Force "is_xml" kwargs if we detect a XML model + try: + is_xml_model_serialization = kwargs["is_xml"] + except KeyError: + is_xml_model_serialization = kwargs.setdefault("is_xml", target_obj.is_xml_model()) + + serialized = {} + if is_xml_model_serialization: + serialized = target_obj._create_xml_node() # pylint: disable=protected-access + try: + attributes = target_obj._attribute_map # pylint: disable=protected-access + for attr, attr_desc in attributes.items(): + attr_name = attr + if not keep_readonly and target_obj._validation.get( # pylint: disable=protected-access + attr_name, {} + ).get("readonly", False): + continue + + if attr_name == "additional_properties" and attr_desc["key"] == "": + if target_obj.additional_properties is not None: + serialized.update(target_obj.additional_properties) + continue + try: + + orig_attr = getattr(target_obj, attr) + if is_xml_model_serialization: + pass # Don't provide "transformer" for XML for now. Keep "orig_attr" + else: # JSON + keys, orig_attr = key_transformer(attr, attr_desc.copy(), orig_attr) + keys = keys if isinstance(keys, list) else [keys] + + kwargs["serialization_ctxt"] = attr_desc + new_attr = self.serialize_data(orig_attr, attr_desc["type"], **kwargs) + + if is_xml_model_serialization: + xml_desc = attr_desc.get("xml", {}) + xml_name = xml_desc.get("name", attr_desc["key"]) + xml_prefix = xml_desc.get("prefix", None) + xml_ns = xml_desc.get("ns", None) + if xml_desc.get("attr", False): + if xml_ns: + ET.register_namespace(xml_prefix, xml_ns) + xml_name = "{{{}}}{}".format(xml_ns, xml_name) + serialized.set(xml_name, new_attr) # type: ignore + continue + if xml_desc.get("text", False): + serialized.text = new_attr # type: ignore + continue + if isinstance(new_attr, list): + serialized.extend(new_attr) # type: ignore + elif isinstance(new_attr, ET.Element): + # If the down XML has no XML/Name, + # we MUST replace the tag with the local tag. But keeping the namespaces. + if "name" not in getattr(orig_attr, "_xml_map", {}): + splitted_tag = new_attr.tag.split("}") + if len(splitted_tag) == 2: # Namespace + new_attr.tag = "}".join([splitted_tag[0], xml_name]) + else: + new_attr.tag = xml_name + serialized.append(new_attr) # type: ignore + else: # That's a basic type + # Integrate namespace if necessary + local_node = _create_xml_node(xml_name, xml_prefix, xml_ns) + local_node.text = str(new_attr) + serialized.append(local_node) # type: ignore + else: # JSON + for k in reversed(keys): # type: ignore + new_attr = {k: new_attr} + + _new_attr = new_attr + _serialized = serialized + for k in keys: # type: ignore + if k not in _serialized: + _serialized.update(_new_attr) # type: ignore + _new_attr = _new_attr[k] # type: ignore + _serialized = _serialized[k] + except ValueError as err: + if isinstance(err, SerializationError): + raise + + except (AttributeError, KeyError, TypeError) as err: + msg = "Attribute {} in object {} cannot be serialized.\n{}".format(attr_name, class_name, str(target_obj)) + raise SerializationError(msg) from err + return serialized + + def body(self, data, data_type, **kwargs): + """Serialize data intended for a request body. + + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: dict + :raises SerializationError: if serialization fails. + :raises ValueError: if data is None + :returns: The serialized request body + """ + + # Just in case this is a dict + internal_data_type_str = data_type.strip("[]{}") + internal_data_type = self.dependencies.get(internal_data_type_str, None) + try: + is_xml_model_serialization = kwargs["is_xml"] + except KeyError: + if internal_data_type and issubclass(internal_data_type, Model): + is_xml_model_serialization = kwargs.setdefault("is_xml", internal_data_type.is_xml_model()) + else: + is_xml_model_serialization = False + if internal_data_type and not isinstance(internal_data_type, Enum): + try: + deserializer = Deserializer(self.dependencies) + # Since it's on serialization, it's almost sure that format is not JSON REST + # We're not able to deal with additional properties for now. + deserializer.additional_properties_detection = False + if is_xml_model_serialization: + deserializer.key_extractors = [ # type: ignore + attribute_key_case_insensitive_extractor, + ] + else: + deserializer.key_extractors = [ + rest_key_case_insensitive_extractor, + attribute_key_case_insensitive_extractor, + last_rest_key_case_insensitive_extractor, + ] + data = deserializer._deserialize(data_type, data) # pylint: disable=protected-access + except DeserializationError as err: + raise SerializationError("Unable to build a model: " + str(err)) from err + + return self._serialize(data, data_type, **kwargs) + + def url(self, name, data, data_type, **kwargs): + """Serialize data intended for a URL path. + + :param str name: The name of the URL path parameter. + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str + :returns: The serialized URL path + :raises TypeError: if serialization fails. + :raises ValueError: if data is None + """ + try: + output = self.serialize_data(data, data_type, **kwargs) + if data_type == "bool": + output = json.dumps(output) + + if kwargs.get("skip_quote") is True: + output = str(output) + output = output.replace("{", quote("{")).replace("}", quote("}")) + else: + output = quote(str(output), safe="") + except SerializationError as exc: + raise TypeError("{} must be type {}.".format(name, data_type)) from exc + return output + + def query(self, name, data, data_type, **kwargs): + """Serialize data intended for a URL query. + + :param str name: The name of the query parameter. + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str, list + :raises TypeError: if serialization fails. + :raises ValueError: if data is None + :returns: The serialized query parameter + """ + try: + # Treat the list aside, since we don't want to encode the div separator + if data_type.startswith("["): + internal_data_type = data_type[1:-1] + do_quote = not kwargs.get("skip_quote", False) + return self.serialize_iter(data, internal_data_type, do_quote=do_quote, **kwargs) + + # Not a list, regular serialization + output = self.serialize_data(data, data_type, **kwargs) + if data_type == "bool": + output = json.dumps(output) + if kwargs.get("skip_quote") is True: + output = str(output) + else: + output = quote(str(output), safe="") + except SerializationError as exc: + raise TypeError("{} must be type {}.".format(name, data_type)) from exc + return str(output) + + def header(self, name, data, data_type, **kwargs): + """Serialize data intended for a request header. + + :param str name: The name of the header. + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str + :raises TypeError: if serialization fails. + :raises ValueError: if data is None + :returns: The serialized header + """ + try: + if data_type in ["[str]"]: + data = ["" if d is None else d for d in data] + + output = self.serialize_data(data, data_type, **kwargs) + if data_type == "bool": + output = json.dumps(output) + except SerializationError as exc: + raise TypeError("{} must be type {}.".format(name, data_type)) from exc + return str(output) + + def serialize_data(self, data, data_type, **kwargs): + """Serialize generic data according to supplied data type. + + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :raises AttributeError: if required data is None. + :raises ValueError: if data is None + :raises SerializationError: if serialization fails. + :returns: The serialized data. + :rtype: str, int, float, bool, dict, list + """ + if data is None: + raise ValueError("No value for given attribute") + + try: + if data is CoreNull: + return None + if data_type in self.basic_types.values(): + return self.serialize_basic(data, data_type, **kwargs) + + if data_type in self.serialize_type: + return self.serialize_type[data_type](data, **kwargs) + + # If dependencies is empty, try with current data class + # It has to be a subclass of Enum anyway + enum_type = self.dependencies.get(data_type, data.__class__) + if issubclass(enum_type, Enum): + return Serializer.serialize_enum(data, enum_obj=enum_type) + + iter_type = data_type[0] + data_type[-1] + if iter_type in self.serialize_type: + return self.serialize_type[iter_type](data, data_type[1:-1], **kwargs) + + except (ValueError, TypeError) as err: + msg = "Unable to serialize value: {!r} as type: {!r}." + raise SerializationError(msg.format(data, data_type)) from err + return self._serialize(data, **kwargs) + + @classmethod + def _get_custom_serializers(cls, data_type, **kwargs): # pylint: disable=inconsistent-return-statements + custom_serializer = kwargs.get("basic_types_serializers", {}).get(data_type) + if custom_serializer: + return custom_serializer + if kwargs.get("is_xml", False): + return cls._xml_basic_types_serializers.get(data_type) + + @classmethod + def serialize_basic(cls, data, data_type, **kwargs): + """Serialize basic builting data type. + Serializes objects to str, int, float or bool. + + Possible kwargs: + - basic_types_serializers dict[str, callable] : If set, use the callable as serializer + - is_xml bool : If set, use xml_basic_types_serializers + + :param obj data: Object to be serialized. + :param str data_type: Type of object in the iterable. + :rtype: str, int, float, bool + :return: serialized object + """ + custom_serializer = cls._get_custom_serializers(data_type, **kwargs) + if custom_serializer: + return custom_serializer(data) + if data_type == "str": + return cls.serialize_unicode(data) + return eval(data_type)(data) # nosec # pylint: disable=eval-used + + @classmethod + def serialize_unicode(cls, data): + """Special handling for serializing unicode strings in Py2. + Encode to UTF-8 if unicode, otherwise handle as a str. + + :param str data: Object to be serialized. + :rtype: str + :return: serialized object + """ + try: # If I received an enum, return its value + return data.value + except AttributeError: + pass + + try: + if isinstance(data, unicode): # type: ignore + # Don't change it, JSON and XML ElementTree are totally able + # to serialize correctly u'' strings + return data + except NameError: + return str(data) + return str(data) + + def serialize_iter(self, data, iter_type, div=None, **kwargs): + """Serialize iterable. + + Supported kwargs: + - serialization_ctxt dict : The current entry of _attribute_map, or same format. + serialization_ctxt['type'] should be same as data_type. + - is_xml bool : If set, serialize as XML + + :param list data: Object to be serialized. + :param str iter_type: Type of object in the iterable. + :param str div: If set, this str will be used to combine the elements + in the iterable into a combined string. Default is 'None'. + Defaults to False. + :rtype: list, str + :return: serialized iterable + """ + if isinstance(data, str): + raise SerializationError("Refuse str type as a valid iter type.") + + serialization_ctxt = kwargs.get("serialization_ctxt", {}) + is_xml = kwargs.get("is_xml", False) + + serialized = [] + for d in data: + try: + serialized.append(self.serialize_data(d, iter_type, **kwargs)) + except ValueError as err: + if isinstance(err, SerializationError): + raise + serialized.append(None) + + if kwargs.get("do_quote", False): + serialized = ["" if s is None else quote(str(s), safe="") for s in serialized] + + if div: + serialized = ["" if s is None else str(s) for s in serialized] + serialized = div.join(serialized) + + if "xml" in serialization_ctxt or is_xml: + # XML serialization is more complicated + xml_desc = serialization_ctxt.get("xml", {}) + xml_name = xml_desc.get("name") + if not xml_name: + xml_name = serialization_ctxt["key"] + + # Create a wrap node if necessary (use the fact that Element and list have "append") + is_wrapped = xml_desc.get("wrapped", False) + node_name = xml_desc.get("itemsName", xml_name) + if is_wrapped: + final_result = _create_xml_node(xml_name, xml_desc.get("prefix", None), xml_desc.get("ns", None)) + else: + final_result = [] + # All list elements to "local_node" + for el in serialized: + if isinstance(el, ET.Element): + el_node = el + else: + el_node = _create_xml_node(node_name, xml_desc.get("prefix", None), xml_desc.get("ns", None)) + if el is not None: # Otherwise it writes "None" :-p + el_node.text = str(el) + final_result.append(el_node) + return final_result + return serialized + + def serialize_dict(self, attr, dict_type, **kwargs): + """Serialize a dictionary of objects. + + :param dict attr: Object to be serialized. + :param str dict_type: Type of object in the dictionary. + :rtype: dict + :return: serialized dictionary + """ + serialization_ctxt = kwargs.get("serialization_ctxt", {}) + serialized = {} + for key, value in attr.items(): + try: + serialized[self.serialize_unicode(key)] = self.serialize_data(value, dict_type, **kwargs) + except ValueError as err: + if isinstance(err, SerializationError): + raise + serialized[self.serialize_unicode(key)] = None + + if "xml" in serialization_ctxt: + # XML serialization is more complicated + xml_desc = serialization_ctxt["xml"] + xml_name = xml_desc["name"] + + final_result = _create_xml_node(xml_name, xml_desc.get("prefix", None), xml_desc.get("ns", None)) + for key, value in serialized.items(): + ET.SubElement(final_result, key).text = value + return final_result + + return serialized + + def serialize_object(self, attr, **kwargs): # pylint: disable=too-many-return-statements + """Serialize a generic object. + This will be handled as a dictionary. If object passed in is not + a basic type (str, int, float, dict, list) it will simply be + cast to str. + + :param dict attr: Object to be serialized. + :rtype: dict or str + :return: serialized object + """ + if attr is None: + return None + if isinstance(attr, ET.Element): + return attr + obj_type = type(attr) + if obj_type in self.basic_types: + return self.serialize_basic(attr, self.basic_types[obj_type], **kwargs) + if obj_type is _long_type: + return self.serialize_long(attr) + if obj_type is str: + return self.serialize_unicode(attr) + if obj_type is datetime.datetime: + return self.serialize_iso(attr) + if obj_type is datetime.date: + return self.serialize_date(attr) + if obj_type is datetime.time: + return self.serialize_time(attr) + if obj_type is datetime.timedelta: + return self.serialize_duration(attr) + if obj_type is decimal.Decimal: + return self.serialize_decimal(attr) + + # If it's a model or I know this dependency, serialize as a Model + if obj_type in self.dependencies.values() or isinstance(attr, Model): + return self._serialize(attr) + + if obj_type == dict: + serialized = {} + for key, value in attr.items(): + try: + serialized[self.serialize_unicode(key)] = self.serialize_object(value, **kwargs) + except ValueError: + serialized[self.serialize_unicode(key)] = None + return serialized + + if obj_type == list: + serialized = [] + for obj in attr: + try: + serialized.append(self.serialize_object(obj, **kwargs)) + except ValueError: + pass + return serialized + return str(attr) + + @staticmethod + def serialize_enum(attr, enum_obj=None): + try: + result = attr.value + except AttributeError: + result = attr + try: + enum_obj(result) # type: ignore + return result + except ValueError as exc: + for enum_value in enum_obj: # type: ignore + if enum_value.value.lower() == str(attr).lower(): + return enum_value.value + error = "{!r} is not valid value for enum {!r}" + raise SerializationError(error.format(attr, enum_obj)) from exc + + @staticmethod + def serialize_bytearray(attr, **kwargs): # pylint: disable=unused-argument + """Serialize bytearray into base-64 string. + + :param str attr: Object to be serialized. + :rtype: str + :return: serialized base64 + """ + return b64encode(attr).decode() + + @staticmethod + def serialize_base64(attr, **kwargs): # pylint: disable=unused-argument + """Serialize str into base-64 string. + + :param str attr: Object to be serialized. + :rtype: str + :return: serialized base64 + """ + encoded = b64encode(attr).decode("ascii") + return encoded.strip("=").replace("+", "-").replace("/", "_") + + @staticmethod + def serialize_decimal(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Decimal object to float. + + :param decimal attr: Object to be serialized. + :rtype: float + :return: serialized decimal + """ + return float(attr) + + @staticmethod + def serialize_long(attr, **kwargs): # pylint: disable=unused-argument + """Serialize long (Py2) or int (Py3). + + :param int attr: Object to be serialized. + :rtype: int/long + :return: serialized long + """ + return _long_type(attr) + + @staticmethod + def serialize_date(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Date object into ISO-8601 formatted string. + + :param Date attr: Object to be serialized. + :rtype: str + :return: serialized date + """ + if isinstance(attr, str): + attr = isodate.parse_date(attr) + t = "{:04}-{:02}-{:02}".format(attr.year, attr.month, attr.day) + return t + + @staticmethod + def serialize_time(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Time object into ISO-8601 formatted string. + + :param datetime.time attr: Object to be serialized. + :rtype: str + :return: serialized time + """ + if isinstance(attr, str): + attr = isodate.parse_time(attr) + t = "{:02}:{:02}:{:02}".format(attr.hour, attr.minute, attr.second) + if attr.microsecond: + t += ".{:02}".format(attr.microsecond) + return t + + @staticmethod + def serialize_duration(attr, **kwargs): # pylint: disable=unused-argument + """Serialize TimeDelta object into ISO-8601 formatted string. + + :param TimeDelta attr: Object to be serialized. + :rtype: str + :return: serialized duration + """ + if isinstance(attr, str): + attr = isodate.parse_duration(attr) + return isodate.duration_isoformat(attr) + + @staticmethod + def serialize_rfc(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Datetime object into RFC-1123 formatted string. + + :param Datetime attr: Object to be serialized. + :rtype: str + :raises TypeError: if format invalid. + :return: serialized rfc + """ + try: + if not attr.tzinfo: + _LOGGER.warning("Datetime with no tzinfo will be considered UTC.") + utc = attr.utctimetuple() + except AttributeError as exc: + raise TypeError("RFC1123 object must be valid Datetime object.") from exc + + return "{}, {:02} {} {:04} {:02}:{:02}:{:02} GMT".format( + Serializer.days[utc.tm_wday], + utc.tm_mday, + Serializer.months[utc.tm_mon], + utc.tm_year, + utc.tm_hour, + utc.tm_min, + utc.tm_sec, + ) + + @staticmethod + def serialize_iso(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Datetime object into ISO-8601 formatted string. + + :param Datetime attr: Object to be serialized. + :rtype: str + :raises SerializationError: if format invalid. + :return: serialized iso + """ + if isinstance(attr, str): + attr = isodate.parse_datetime(attr) + try: + if not attr.tzinfo: + _LOGGER.warning("Datetime with no tzinfo will be considered UTC.") + utc = attr.utctimetuple() + if utc.tm_year > 9999 or utc.tm_year < 1: + raise OverflowError("Hit max or min date") + + microseconds = str(attr.microsecond).rjust(6, "0").rstrip("0").ljust(3, "0") + if microseconds: + microseconds = "." + microseconds + date = "{:04}-{:02}-{:02}T{:02}:{:02}:{:02}".format( + utc.tm_year, utc.tm_mon, utc.tm_mday, utc.tm_hour, utc.tm_min, utc.tm_sec + ) + return date + microseconds + "Z" + except (ValueError, OverflowError) as err: + msg = "Unable to serialize datetime object." + raise SerializationError(msg) from err + except AttributeError as err: + msg = "ISO-8601 object must be valid Datetime object." + raise TypeError(msg) from err + + @staticmethod + def serialize_unix(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Datetime object into IntTime format. + This is represented as seconds. + + :param Datetime attr: Object to be serialized. + :rtype: int + :raises SerializationError: if format invalid + :return: serialied unix + """ + if isinstance(attr, int): + return attr + try: + if not attr.tzinfo: + _LOGGER.warning("Datetime with no tzinfo will be considered UTC.") + return int(calendar.timegm(attr.utctimetuple())) + except AttributeError as exc: + raise TypeError("Unix time object must be valid Datetime object.") from exc + + +def rest_key_extractor(attr, attr_desc, data): # pylint: disable=unused-argument + key = attr_desc["key"] + working_data = data + + while "." in key: + # Need the cast, as for some reasons "split" is typed as list[str | Any] + dict_keys = cast(List[str], _FLATTEN.split(key)) + if len(dict_keys) == 1: + key = _decode_attribute_map_key(dict_keys[0]) + break + working_key = _decode_attribute_map_key(dict_keys[0]) + working_data = working_data.get(working_key, data) + if working_data is None: + # If at any point while following flatten JSON path see None, it means + # that all properties under are None as well + return None + key = ".".join(dict_keys[1:]) + + return working_data.get(key) + + +def rest_key_case_insensitive_extractor( # pylint: disable=unused-argument, inconsistent-return-statements + attr, attr_desc, data +): + key = attr_desc["key"] + working_data = data + + while "." in key: + dict_keys = _FLATTEN.split(key) + if len(dict_keys) == 1: + key = _decode_attribute_map_key(dict_keys[0]) + break + working_key = _decode_attribute_map_key(dict_keys[0]) + working_data = attribute_key_case_insensitive_extractor(working_key, None, working_data) + if working_data is None: + # If at any point while following flatten JSON path see None, it means + # that all properties under are None as well + return None + key = ".".join(dict_keys[1:]) + + if working_data: + return attribute_key_case_insensitive_extractor(key, None, working_data) + + +def last_rest_key_extractor(attr, attr_desc, data): # pylint: disable=unused-argument + """Extract the attribute in "data" based on the last part of the JSON path key. + + :param str attr: The attribute to extract + :param dict attr_desc: The attribute description + :param dict data: The data to extract from + :rtype: object + :returns: The extracted attribute + """ + key = attr_desc["key"] + dict_keys = _FLATTEN.split(key) + return attribute_key_extractor(dict_keys[-1], None, data) + + +def last_rest_key_case_insensitive_extractor(attr, attr_desc, data): # pylint: disable=unused-argument + """Extract the attribute in "data" based on the last part of the JSON path key. + + This is the case insensitive version of "last_rest_key_extractor" + :param str attr: The attribute to extract + :param dict attr_desc: The attribute description + :param dict data: The data to extract from + :rtype: object + :returns: The extracted attribute + """ + key = attr_desc["key"] + dict_keys = _FLATTEN.split(key) + return attribute_key_case_insensitive_extractor(dict_keys[-1], None, data) + + +def attribute_key_extractor(attr, _, data): + return data.get(attr) + + +def attribute_key_case_insensitive_extractor(attr, _, data): + found_key = None + lower_attr = attr.lower() + for key in data: + if lower_attr == key.lower(): + found_key = key + break + + return data.get(found_key) + + +def _extract_name_from_internal_type(internal_type): + """Given an internal type XML description, extract correct XML name with namespace. + + :param dict internal_type: An model type + :rtype: tuple + :returns: A tuple XML name + namespace dict + """ + internal_type_xml_map = getattr(internal_type, "_xml_map", {}) + xml_name = internal_type_xml_map.get("name", internal_type.__name__) + xml_ns = internal_type_xml_map.get("ns", None) + if xml_ns: + xml_name = "{{{}}}{}".format(xml_ns, xml_name) + return xml_name + + +def xml_key_extractor(attr, attr_desc, data): # pylint: disable=unused-argument,too-many-return-statements + if isinstance(data, dict): + return None + + # Test if this model is XML ready first + if not isinstance(data, ET.Element): + return None + + xml_desc = attr_desc.get("xml", {}) + xml_name = xml_desc.get("name", attr_desc["key"]) + + # Look for a children + is_iter_type = attr_desc["type"].startswith("[") + is_wrapped = xml_desc.get("wrapped", False) + internal_type = attr_desc.get("internalType", None) + internal_type_xml_map = getattr(internal_type, "_xml_map", {}) + + # Integrate namespace if necessary + xml_ns = xml_desc.get("ns", internal_type_xml_map.get("ns", None)) + if xml_ns: + xml_name = "{{{}}}{}".format(xml_ns, xml_name) + + # If it's an attribute, that's simple + if xml_desc.get("attr", False): + return data.get(xml_name) + + # If it's x-ms-text, that's simple too + if xml_desc.get("text", False): + return data.text + + # Scenario where I take the local name: + # - Wrapped node + # - Internal type is an enum (considered basic types) + # - Internal type has no XML/Name node + if is_wrapped or (internal_type and (issubclass(internal_type, Enum) or "name" not in internal_type_xml_map)): + children = data.findall(xml_name) + # If internal type has a local name and it's not a list, I use that name + elif not is_iter_type and internal_type and "name" in internal_type_xml_map: + xml_name = _extract_name_from_internal_type(internal_type) + children = data.findall(xml_name) + # That's an array + else: + if internal_type: # Complex type, ignore itemsName and use the complex type name + items_name = _extract_name_from_internal_type(internal_type) + else: + items_name = xml_desc.get("itemsName", xml_name) + children = data.findall(items_name) + + if len(children) == 0: + if is_iter_type: + if is_wrapped: + return None # is_wrapped no node, we want None + return [] # not wrapped, assume empty list + return None # Assume it's not there, maybe an optional node. + + # If is_iter_type and not wrapped, return all found children + if is_iter_type: + if not is_wrapped: + return children + # Iter and wrapped, should have found one node only (the wrap one) + if len(children) != 1: + raise DeserializationError( + "Tried to deserialize an array not wrapped, and found several nodes '{}'. Maybe you should declare this array as wrapped?".format( + xml_name + ) + ) + return list(children[0]) # Might be empty list and that's ok. + + # Here it's not a itertype, we should have found one element only or empty + if len(children) > 1: + raise DeserializationError("Find several XML '{}' where it was not expected".format(xml_name)) + return children[0] + + +class Deserializer: + """Response object model deserializer. + + :param dict classes: Class type dictionary for deserializing complex types. + :ivar list key_extractors: Ordered list of extractors to be used by this deserializer. + """ + + basic_types = {str: "str", int: "int", bool: "bool", float: "float"} + + valid_date = re.compile(r"\d{4}[-]\d{2}[-]\d{2}T\d{2}:\d{2}:\d{2}\.?\d*Z?[-+]?[\d{2}]?:?[\d{2}]?") + + def __init__(self, classes: Optional[Mapping[str, type]] = None) -> None: + self.deserialize_type = { + "iso-8601": Deserializer.deserialize_iso, + "rfc-1123": Deserializer.deserialize_rfc, + "unix-time": Deserializer.deserialize_unix, + "duration": Deserializer.deserialize_duration, + "date": Deserializer.deserialize_date, + "time": Deserializer.deserialize_time, + "decimal": Deserializer.deserialize_decimal, + "long": Deserializer.deserialize_long, + "bytearray": Deserializer.deserialize_bytearray, + "base64": Deserializer.deserialize_base64, + "object": self.deserialize_object, + "[]": self.deserialize_iter, + "{}": self.deserialize_dict, + } + self.deserialize_expected_types = { + "duration": (isodate.Duration, datetime.timedelta), + "iso-8601": (datetime.datetime), + } + self.dependencies: Dict[str, type] = dict(classes) if classes else {} + self.key_extractors = [rest_key_extractor, xml_key_extractor] + # Additional properties only works if the "rest_key_extractor" is used to + # extract the keys. Making it to work whatever the key extractor is too much + # complicated, with no real scenario for now. + # So adding a flag to disable additional properties detection. This flag should be + # used if your expect the deserialization to NOT come from a JSON REST syntax. + # Otherwise, result are unexpected + self.additional_properties_detection = True + + def __call__(self, target_obj, response_data, content_type=None): + """Call the deserializer to process a REST response. + + :param str target_obj: Target data type to deserialize to. + :param requests.Response response_data: REST response object. + :param str content_type: Swagger "produces" if available. + :raises DeserializationError: if deserialization fails. + :return: Deserialized object. + :rtype: object + """ + data = self._unpack_content(response_data, content_type) + return self._deserialize(target_obj, data) + + def _deserialize(self, target_obj, data): # pylint: disable=inconsistent-return-statements + """Call the deserializer on a model. + + Data needs to be already deserialized as JSON or XML ElementTree + + :param str target_obj: Target data type to deserialize to. + :param object data: Object to deserialize. + :raises DeserializationError: if deserialization fails. + :return: Deserialized object. + :rtype: object + """ + # This is already a model, go recursive just in case + if hasattr(data, "_attribute_map"): + constants = [name for name, config in getattr(data, "_validation", {}).items() if config.get("constant")] + try: + for attr, mapconfig in data._attribute_map.items(): # pylint: disable=protected-access + if attr in constants: + continue + value = getattr(data, attr) + if value is None: + continue + local_type = mapconfig["type"] + internal_data_type = local_type.strip("[]{}") + if internal_data_type not in self.dependencies or isinstance(internal_data_type, Enum): + continue + setattr(data, attr, self._deserialize(local_type, value)) + return data + except AttributeError: + return + + response, class_name = self._classify_target(target_obj, data) + + if isinstance(response, str): + return self.deserialize_data(data, response) + if isinstance(response, type) and issubclass(response, Enum): + return self.deserialize_enum(data, response) + + if data is None or data is CoreNull: + return data + try: + attributes = response._attribute_map # type: ignore # pylint: disable=protected-access + d_attrs = {} + for attr, attr_desc in attributes.items(): + # Check empty string. If it's not empty, someone has a real "additionalProperties"... + if attr == "additional_properties" and attr_desc["key"] == "": + continue + raw_value = None + # Enhance attr_desc with some dynamic data + attr_desc = attr_desc.copy() # Do a copy, do not change the real one + internal_data_type = attr_desc["type"].strip("[]{}") + if internal_data_type in self.dependencies: + attr_desc["internalType"] = self.dependencies[internal_data_type] + + for key_extractor in self.key_extractors: + found_value = key_extractor(attr, attr_desc, data) + if found_value is not None: + if raw_value is not None and raw_value != found_value: + msg = ( + "Ignoring extracted value '%s' from %s for key '%s'" + " (duplicate extraction, follow extractors order)" + ) + _LOGGER.warning(msg, found_value, key_extractor, attr) + continue + raw_value = found_value + + value = self.deserialize_data(raw_value, attr_desc["type"]) + d_attrs[attr] = value + except (AttributeError, TypeError, KeyError) as err: + msg = "Unable to deserialize to object: " + class_name # type: ignore + raise DeserializationError(msg) from err + additional_properties = self._build_additional_properties(attributes, data) + return self._instantiate_model(response, d_attrs, additional_properties) + + def _build_additional_properties(self, attribute_map, data): + if not self.additional_properties_detection: + return None + if "additional_properties" in attribute_map and attribute_map.get("additional_properties", {}).get("key") != "": + # Check empty string. If it's not empty, someone has a real "additionalProperties" + return None + if isinstance(data, ET.Element): + data = {el.tag: el.text for el in data} + + known_keys = { + _decode_attribute_map_key(_FLATTEN.split(desc["key"])[0]) + for desc in attribute_map.values() + if desc["key"] != "" + } + present_keys = set(data.keys()) + missing_keys = present_keys - known_keys + return {key: data[key] for key in missing_keys} + + def _classify_target(self, target, data): + """Check to see whether the deserialization target object can + be classified into a subclass. + Once classification has been determined, initialize object. + + :param str target: The target object type to deserialize to. + :param str/dict data: The response data to deserialize. + :return: The classified target object and its class name. + :rtype: tuple + """ + if target is None: + return None, None + + if isinstance(target, str): + try: + target = self.dependencies[target] + except KeyError: + return target, target + + try: + target = target._classify(data, self.dependencies) # type: ignore # pylint: disable=protected-access + except AttributeError: + pass # Target is not a Model, no classify + return target, target.__class__.__name__ # type: ignore + + def failsafe_deserialize(self, target_obj, data, content_type=None): + """Ignores any errors encountered in deserialization, + and falls back to not deserializing the object. Recommended + for use in error deserialization, as we want to return the + HttpResponseError to users, and not have them deal with + a deserialization error. + + :param str target_obj: The target object type to deserialize to. + :param str/dict data: The response data to deserialize. + :param str content_type: Swagger "produces" if available. + :return: Deserialized object. + :rtype: object + """ + try: + return self(target_obj, data, content_type=content_type) + except: # pylint: disable=bare-except + _LOGGER.debug( + "Ran into a deserialization error. Ignoring since this is failsafe deserialization", exc_info=True + ) + return None + + @staticmethod + def _unpack_content(raw_data, content_type=None): + """Extract the correct structure for deserialization. + + If raw_data is a PipelineResponse, try to extract the result of RawDeserializer. + if we can't, raise. Your Pipeline should have a RawDeserializer. + + If not a pipeline response and raw_data is bytes or string, use content-type + to decode it. If no content-type, try JSON. + + If raw_data is something else, bypass all logic and return it directly. + + :param obj raw_data: Data to be processed. + :param str content_type: How to parse if raw_data is a string/bytes. + :raises JSONDecodeError: If JSON is requested and parsing is impossible. + :raises UnicodeDecodeError: If bytes is not UTF8 + :rtype: object + :return: Unpacked content. + """ + # Assume this is enough to detect a Pipeline Response without importing it + context = getattr(raw_data, "context", {}) + if context: + if RawDeserializer.CONTEXT_NAME in context: + return context[RawDeserializer.CONTEXT_NAME] + raise ValueError("This pipeline didn't have the RawDeserializer policy; can't deserialize") + + # Assume this is enough to recognize universal_http.ClientResponse without importing it + if hasattr(raw_data, "body"): + return RawDeserializer.deserialize_from_http_generics(raw_data.text(), raw_data.headers) + + # Assume this enough to recognize requests.Response without importing it. + if hasattr(raw_data, "_content_consumed"): + return RawDeserializer.deserialize_from_http_generics(raw_data.text, raw_data.headers) + + if isinstance(raw_data, (str, bytes)) or hasattr(raw_data, "read"): + return RawDeserializer.deserialize_from_text(raw_data, content_type) # type: ignore + return raw_data + + def _instantiate_model(self, response, attrs, additional_properties=None): + """Instantiate a response model passing in deserialized args. + + :param Response response: The response model class. + :param dict attrs: The deserialized response attributes. + :param dict additional_properties: Additional properties to be set. + :rtype: Response + :return: The instantiated response model. + """ + if callable(response): + subtype = getattr(response, "_subtype_map", {}) + try: + readonly = [ + k + for k, v in response._validation.items() # pylint: disable=protected-access # type: ignore + if v.get("readonly") + ] + const = [ + k + for k, v in response._validation.items() # pylint: disable=protected-access # type: ignore + if v.get("constant") + ] + kwargs = {k: v for k, v in attrs.items() if k not in subtype and k not in readonly + const} + response_obj = response(**kwargs) + for attr in readonly: + setattr(response_obj, attr, attrs.get(attr)) + if additional_properties: + response_obj.additional_properties = additional_properties # type: ignore + return response_obj + except TypeError as err: + msg = "Unable to deserialize {} into model {}. ".format(kwargs, response) # type: ignore + raise DeserializationError(msg + str(err)) from err + else: + try: + for attr, value in attrs.items(): + setattr(response, attr, value) + return response + except Exception as exp: + msg = "Unable to populate response model. " + msg += "Type: {}, Error: {}".format(type(response), exp) + raise DeserializationError(msg) from exp + + def deserialize_data(self, data, data_type): # pylint: disable=too-many-return-statements + """Process data for deserialization according to data type. + + :param str data: The response string to be deserialized. + :param str data_type: The type to deserialize to. + :raises DeserializationError: if deserialization fails. + :return: Deserialized object. + :rtype: object + """ + if data is None: + return data + + try: + if not data_type: + return data + if data_type in self.basic_types.values(): + return self.deserialize_basic(data, data_type) + if data_type in self.deserialize_type: + if isinstance(data, self.deserialize_expected_types.get(data_type, tuple())): + return data + + is_a_text_parsing_type = lambda x: x not in [ # pylint: disable=unnecessary-lambda-assignment + "object", + "[]", + r"{}", + ] + if isinstance(data, ET.Element) and is_a_text_parsing_type(data_type) and not data.text: + return None + data_val = self.deserialize_type[data_type](data) + return data_val + + iter_type = data_type[0] + data_type[-1] + if iter_type in self.deserialize_type: + return self.deserialize_type[iter_type](data, data_type[1:-1]) + + obj_type = self.dependencies[data_type] + if issubclass(obj_type, Enum): + if isinstance(data, ET.Element): + data = data.text + return self.deserialize_enum(data, obj_type) + + except (ValueError, TypeError, AttributeError) as err: + msg = "Unable to deserialize response data." + msg += " Data: {}, {}".format(data, data_type) + raise DeserializationError(msg) from err + return self._deserialize(obj_type, data) + + def deserialize_iter(self, attr, iter_type): + """Deserialize an iterable. + + :param list attr: Iterable to be deserialized. + :param str iter_type: The type of object in the iterable. + :return: Deserialized iterable. + :rtype: list + """ + if attr is None: + return None + if isinstance(attr, ET.Element): # If I receive an element here, get the children + attr = list(attr) + if not isinstance(attr, (list, set)): + raise DeserializationError("Cannot deserialize as [{}] an object of type {}".format(iter_type, type(attr))) + return [self.deserialize_data(a, iter_type) for a in attr] + + def deserialize_dict(self, attr, dict_type): + """Deserialize a dictionary. + + :param dict/list attr: Dictionary to be deserialized. Also accepts + a list of key, value pairs. + :param str dict_type: The object type of the items in the dictionary. + :return: Deserialized dictionary. + :rtype: dict + """ + if isinstance(attr, list): + return {x["key"]: self.deserialize_data(x["value"], dict_type) for x in attr} + + if isinstance(attr, ET.Element): + # Transform value into {"Key": "value"} + attr = {el.tag: el.text for el in attr} + return {k: self.deserialize_data(v, dict_type) for k, v in attr.items()} + + def deserialize_object(self, attr, **kwargs): # pylint: disable=too-many-return-statements + """Deserialize a generic object. + This will be handled as a dictionary. + + :param dict attr: Dictionary to be deserialized. + :return: Deserialized object. + :rtype: dict + :raises TypeError: if non-builtin datatype encountered. + """ + if attr is None: + return None + if isinstance(attr, ET.Element): + # Do no recurse on XML, just return the tree as-is + return attr + if isinstance(attr, str): + return self.deserialize_basic(attr, "str") + obj_type = type(attr) + if obj_type in self.basic_types: + return self.deserialize_basic(attr, self.basic_types[obj_type]) + if obj_type is _long_type: + return self.deserialize_long(attr) + + if obj_type == dict: + deserialized = {} + for key, value in attr.items(): + try: + deserialized[key] = self.deserialize_object(value, **kwargs) + except ValueError: + deserialized[key] = None + return deserialized + + if obj_type == list: + deserialized = [] + for obj in attr: + try: + deserialized.append(self.deserialize_object(obj, **kwargs)) + except ValueError: + pass + return deserialized + + error = "Cannot deserialize generic object with type: " + raise TypeError(error + str(obj_type)) + + def deserialize_basic(self, attr, data_type): # pylint: disable=too-many-return-statements + """Deserialize basic builtin data type from string. + Will attempt to convert to str, int, float and bool. + This function will also accept '1', '0', 'true' and 'false' as + valid bool values. + + :param str attr: response string to be deserialized. + :param str data_type: deserialization data type. + :return: Deserialized basic type. + :rtype: str, int, float or bool + :raises TypeError: if string format is not valid. + """ + # If we're here, data is supposed to be a basic type. + # If it's still an XML node, take the text + if isinstance(attr, ET.Element): + attr = attr.text + if not attr: + if data_type == "str": + # None or '', node is empty string. + return "" + # None or '', node with a strong type is None. + # Don't try to model "empty bool" or "empty int" + return None + + if data_type == "bool": + if attr in [True, False, 1, 0]: + return bool(attr) + if isinstance(attr, str): + if attr.lower() in ["true", "1"]: + return True + if attr.lower() in ["false", "0"]: + return False + raise TypeError("Invalid boolean value: {}".format(attr)) + + if data_type == "str": + return self.deserialize_unicode(attr) + return eval(data_type)(attr) # nosec # pylint: disable=eval-used + + @staticmethod + def deserialize_unicode(data): + """Preserve unicode objects in Python 2, otherwise return data + as a string. + + :param str data: response string to be deserialized. + :return: Deserialized string. + :rtype: str or unicode + """ + # We might be here because we have an enum modeled as string, + # and we try to deserialize a partial dict with enum inside + if isinstance(data, Enum): + return data + + # Consider this is real string + try: + if isinstance(data, unicode): # type: ignore + return data + except NameError: + return str(data) + return str(data) + + @staticmethod + def deserialize_enum(data, enum_obj): + """Deserialize string into enum object. + + If the string is not a valid enum value it will be returned as-is + and a warning will be logged. + + :param str data: Response string to be deserialized. If this value is + None or invalid it will be returned as-is. + :param Enum enum_obj: Enum object to deserialize to. + :return: Deserialized enum object. + :rtype: Enum + """ + if isinstance(data, enum_obj) or data is None: + return data + if isinstance(data, Enum): + data = data.value + if isinstance(data, int): + # Workaround. We might consider remove it in the future. + try: + return list(enum_obj.__members__.values())[data] + except IndexError as exc: + error = "{!r} is not a valid index for enum {!r}" + raise DeserializationError(error.format(data, enum_obj)) from exc + try: + return enum_obj(str(data)) + except ValueError: + for enum_value in enum_obj: + if enum_value.value.lower() == str(data).lower(): + return enum_value + # We don't fail anymore for unknown value, we deserialize as a string + _LOGGER.warning("Deserializer is not able to find %s as valid enum in %s", data, enum_obj) + return Deserializer.deserialize_unicode(data) + + @staticmethod + def deserialize_bytearray(attr): + """Deserialize string into bytearray. + + :param str attr: response string to be deserialized. + :return: Deserialized bytearray + :rtype: bytearray + :raises TypeError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + return bytearray(b64decode(attr)) # type: ignore + + @staticmethod + def deserialize_base64(attr): + """Deserialize base64 encoded string into string. + + :param str attr: response string to be deserialized. + :return: Deserialized base64 string + :rtype: bytearray + :raises TypeError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + padding = "=" * (3 - (len(attr) + 3) % 4) # type: ignore + attr = attr + padding # type: ignore + encoded = attr.replace("-", "+").replace("_", "/") + return b64decode(encoded) + + @staticmethod + def deserialize_decimal(attr): + """Deserialize string into Decimal object. + + :param str attr: response string to be deserialized. + :return: Deserialized decimal + :raises DeserializationError: if string format invalid. + :rtype: decimal + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + return decimal.Decimal(str(attr)) # type: ignore + except decimal.DecimalException as err: + msg = "Invalid decimal {}".format(attr) + raise DeserializationError(msg) from err + + @staticmethod + def deserialize_long(attr): + """Deserialize string into long (Py2) or int (Py3). + + :param str attr: response string to be deserialized. + :return: Deserialized int + :rtype: long or int + :raises ValueError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + return _long_type(attr) # type: ignore + + @staticmethod + def deserialize_duration(attr): + """Deserialize ISO-8601 formatted string into TimeDelta object. + + :param str attr: response string to be deserialized. + :return: Deserialized duration + :rtype: TimeDelta + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + duration = isodate.parse_duration(attr) + except (ValueError, OverflowError, AttributeError) as err: + msg = "Cannot deserialize duration object." + raise DeserializationError(msg) from err + return duration + + @staticmethod + def deserialize_date(attr): + """Deserialize ISO-8601 formatted string into Date object. + + :param str attr: response string to be deserialized. + :return: Deserialized date + :rtype: Date + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + if re.search(r"[^\W\d_]", attr, re.I + re.U): # type: ignore + raise DeserializationError("Date must have only digits and -. Received: %s" % attr) + # This must NOT use defaultmonth/defaultday. Using None ensure this raises an exception. + return isodate.parse_date(attr, defaultmonth=0, defaultday=0) + + @staticmethod + def deserialize_time(attr): + """Deserialize ISO-8601 formatted string into time object. + + :param str attr: response string to be deserialized. + :return: Deserialized time + :rtype: datetime.time + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + if re.search(r"[^\W\d_]", attr, re.I + re.U): # type: ignore + raise DeserializationError("Date must have only digits and -. Received: %s" % attr) + return isodate.parse_time(attr) + + @staticmethod + def deserialize_rfc(attr): + """Deserialize RFC-1123 formatted string into Datetime object. + + :param str attr: response string to be deserialized. + :return: Deserialized RFC datetime + :rtype: Datetime + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + parsed_date = email.utils.parsedate_tz(attr) # type: ignore + date_obj = datetime.datetime( + *parsed_date[:6], tzinfo=datetime.timezone(datetime.timedelta(minutes=(parsed_date[9] or 0) / 60)) + ) + if not date_obj.tzinfo: + date_obj = date_obj.astimezone(tz=TZ_UTC) + except ValueError as err: + msg = "Cannot deserialize to rfc datetime object." + raise DeserializationError(msg) from err + return date_obj + + @staticmethod + def deserialize_iso(attr): + """Deserialize ISO-8601 formatted string into Datetime object. + + :param str attr: response string to be deserialized. + :return: Deserialized ISO datetime + :rtype: Datetime + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + attr = attr.upper() # type: ignore + match = Deserializer.valid_date.match(attr) + if not match: + raise ValueError("Invalid datetime string: " + attr) + + check_decimal = attr.split(".") + if len(check_decimal) > 1: + decimal_str = "" + for digit in check_decimal[1]: + if digit.isdigit(): + decimal_str += digit + else: + break + if len(decimal_str) > 6: + attr = attr.replace(decimal_str, decimal_str[0:6]) + + date_obj = isodate.parse_datetime(attr) + test_utc = date_obj.utctimetuple() + if test_utc.tm_year > 9999 or test_utc.tm_year < 1: + raise OverflowError("Hit max or min date") + except (ValueError, OverflowError, AttributeError) as err: + msg = "Cannot deserialize datetime object." + raise DeserializationError(msg) from err + return date_obj + + @staticmethod + def deserialize_unix(attr): + """Serialize Datetime object into IntTime format. + This is represented as seconds. + + :param int attr: Object to be serialized. + :return: Deserialized datetime + :rtype: Datetime + :raises DeserializationError: if format invalid + """ + if isinstance(attr, ET.Element): + attr = int(attr.text) # type: ignore + try: + attr = int(attr) + date_obj = datetime.datetime.fromtimestamp(attr, TZ_UTC) + except ValueError as err: + msg = "Cannot deserialize to unix datetime object." + raise DeserializationError(msg) from err + return date_obj diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/HttpVersionTolerant/httpinfrastructureversiontolerant/aio/_client.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/HttpVersionTolerant/httpinfrastructureversiontolerant/aio/_client.py index a9752a7d72c..711f61fca1e 100644 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/HttpVersionTolerant/httpinfrastructureversiontolerant/aio/_client.py +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/HttpVersionTolerant/httpinfrastructureversiontolerant/aio/_client.py @@ -15,7 +15,7 @@ from azure.core.pipeline import policies from azure.core.rest import AsyncHttpResponse, HttpRequest -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import AutoRestHttpInfrastructureTestServiceConfiguration from .operations import ( HttpClientFailureOperations, diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/HttpVersionTolerant/httpinfrastructureversiontolerant/aio/operations/_operations.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/HttpVersionTolerant/httpinfrastructureversiontolerant/aio/operations/_operations.py index 94387c58169..7f7f58ba6f7 100644 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/HttpVersionTolerant/httpinfrastructureversiontolerant/aio/operations/_operations.py +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/HttpVersionTolerant/httpinfrastructureversiontolerant/aio/operations/_operations.py @@ -23,7 +23,7 @@ from azure.core.tracing.decorator_async import distributed_trace_async from azure.core.utils import case_insensitive_dict -from ..._serialization import Deserializer, Serializer +from ..._utils.serialization import Deserializer, Serializer from ...operations._operations import ( build_http_client_failure_delete400_request, build_http_client_failure_delete407_request, diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/HttpVersionTolerant/httpinfrastructureversiontolerant/operations/_operations.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/HttpVersionTolerant/httpinfrastructureversiontolerant/operations/_operations.py index 7c3e3c1eef5..404029b586a 100644 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/HttpVersionTolerant/httpinfrastructureversiontolerant/operations/_operations.py +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/HttpVersionTolerant/httpinfrastructureversiontolerant/operations/_operations.py @@ -24,7 +24,7 @@ from azure.core.utils import case_insensitive_dict from .._configuration import AutoRestHttpInfrastructureTestServiceConfiguration -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/IncorrectErrorResponseVersionTolerant/incorrecterrorresponseversiontolerant/_client.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/IncorrectErrorResponseVersionTolerant/incorrecterrorresponseversiontolerant/_client.py index 4012a4d1271..d2fdfc77a49 100644 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/IncorrectErrorResponseVersionTolerant/incorrecterrorresponseversiontolerant/_client.py +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/IncorrectErrorResponseVersionTolerant/incorrecterrorresponseversiontolerant/_client.py @@ -16,7 +16,7 @@ from ._configuration import IncorrectReturnedErrorModelConfiguration from ._operations import IncorrectReturnedErrorModelOperationsMixin -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer class IncorrectReturnedErrorModel( diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/IncorrectErrorResponseVersionTolerant/incorrecterrorresponseversiontolerant/_operations/_operations.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/IncorrectErrorResponseVersionTolerant/incorrecterrorresponseversiontolerant/_operations/_operations.py index 19b703809ef..13dc300aebe 100644 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/IncorrectErrorResponseVersionTolerant/incorrecterrorresponseversiontolerant/_operations/_operations.py +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/IncorrectErrorResponseVersionTolerant/incorrecterrorresponseversiontolerant/_operations/_operations.py @@ -8,6 +8,7 @@ from collections.abc import MutableMapping from typing import Any, Callable, Dict, Optional, TypeVar +from azure.core import PipelineClient from azure.core.exceptions import ( ClientAuthenticationError, HttpResponseError, @@ -20,8 +21,9 @@ from azure.core.rest import HttpRequest, HttpResponse from azure.core.tracing.decorator import distributed_trace -from .._serialization import Serializer -from .._vendor import IncorrectReturnedErrorModelMixinABC +from .._configuration import IncorrectReturnedErrorModelConfiguration +from .._utils.serialization import Serializer +from .._utils.utils import ClientMixinABC T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] @@ -39,7 +41,9 @@ def build_incorrect_returned_error_model_get_incorrect_error_from_server_request return HttpRequest(method="GET", url=_url, **kwargs) -class IncorrectReturnedErrorModelOperationsMixin(IncorrectReturnedErrorModelMixinABC): # pylint: disable=name-too-long +class IncorrectReturnedErrorModelOperationsMixin( # pylint: disable=name-too-long + ClientMixinABC[PipelineClient, IncorrectReturnedErrorModelConfiguration] +): @distributed_trace def get_incorrect_error_from_server(self, **kwargs: Any) -> None: # pylint: disable=inconsistent-return-statements diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/IncorrectErrorResponseVersionTolerant/incorrecterrorresponseversiontolerant/_utils/__init__.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/IncorrectErrorResponseVersionTolerant/incorrecterrorresponseversiontolerant/_utils/__init__.py new file mode 100644 index 00000000000..0af9b28f660 --- /dev/null +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/IncorrectErrorResponseVersionTolerant/incorrecterrorresponseversiontolerant/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/IncorrectErrorResponseVersionTolerant/incorrecterrorresponseversiontolerant/_utils/serialization.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/IncorrectErrorResponseVersionTolerant/incorrecterrorresponseversiontolerant/_utils/serialization.py new file mode 100644 index 00000000000..f5187701d7b --- /dev/null +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/IncorrectErrorResponseVersionTolerant/incorrecterrorresponseversiontolerant/_utils/serialization.py @@ -0,0 +1,2032 @@ +# pylint: disable=line-too-long,useless-suppression,too-many-lines +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +# pyright: reportUnnecessaryTypeIgnoreComment=false + +from base64 import b64decode, b64encode +import calendar +import datetime +import decimal +import email +from enum import Enum +import json +import logging +import re +import sys +import codecs +from typing import ( + Dict, + Any, + cast, + Optional, + Union, + AnyStr, + IO, + Mapping, + Callable, + MutableMapping, + List, +) + +try: + from urllib import quote # type: ignore +except ImportError: + from urllib.parse import quote +import xml.etree.ElementTree as ET + +import isodate # type: ignore +from typing_extensions import Self + +from azure.core.exceptions import DeserializationError, SerializationError +from azure.core.serialization import NULL as CoreNull + +_BOM = codecs.BOM_UTF8.decode(encoding="utf-8") + +JSON = MutableMapping[str, Any] + + +class RawDeserializer: + + # Accept "text" because we're open minded people... + JSON_REGEXP = re.compile(r"^(application|text)/([a-z+.]+\+)?json$") + + # Name used in context + CONTEXT_NAME = "deserialized_data" + + @classmethod + def deserialize_from_text(cls, data: Optional[Union[AnyStr, IO]], content_type: Optional[str] = None) -> Any: + """Decode data according to content-type. + + Accept a stream of data as well, but will be load at once in memory for now. + + If no content-type, will return the string version (not bytes, not stream) + + :param data: Input, could be bytes or stream (will be decoded with UTF8) or text + :type data: str or bytes or IO + :param str content_type: The content type. + :return: The deserialized data. + :rtype: object + """ + if hasattr(data, "read"): + # Assume a stream + data = cast(IO, data).read() + + if isinstance(data, bytes): + data_as_str = data.decode(encoding="utf-8-sig") + else: + # Explain to mypy the correct type. + data_as_str = cast(str, data) + + # Remove Byte Order Mark if present in string + data_as_str = data_as_str.lstrip(_BOM) + + if content_type is None: + return data + + if cls.JSON_REGEXP.match(content_type): + try: + return json.loads(data_as_str) + except ValueError as err: + raise DeserializationError("JSON is invalid: {}".format(err), err) from err + elif "xml" in (content_type or []): + try: + + try: + if isinstance(data, unicode): # type: ignore + # If I'm Python 2.7 and unicode XML will scream if I try a "fromstring" on unicode string + data_as_str = data_as_str.encode(encoding="utf-8") # type: ignore + except NameError: + pass + + return ET.fromstring(data_as_str) # nosec + except ET.ParseError as err: + # It might be because the server has an issue, and returned JSON with + # content-type XML.... + # So let's try a JSON load, and if it's still broken + # let's flow the initial exception + def _json_attemp(data): + try: + return True, json.loads(data) + except ValueError: + return False, None # Don't care about this one + + success, json_result = _json_attemp(data) + if success: + return json_result + # If i'm here, it's not JSON, it's not XML, let's scream + # and raise the last context in this block (the XML exception) + # The function hack is because Py2.7 messes up with exception + # context otherwise. + _LOGGER.critical("Wasn't XML not JSON, failing") + raise DeserializationError("XML is invalid") from err + elif content_type.startswith("text/"): + return data_as_str + raise DeserializationError("Cannot deserialize content-type: {}".format(content_type)) + + @classmethod + def deserialize_from_http_generics(cls, body_bytes: Optional[Union[AnyStr, IO]], headers: Mapping) -> Any: + """Deserialize from HTTP response. + + Use bytes and headers to NOT use any requests/aiohttp or whatever + specific implementation. + Headers will tested for "content-type" + + :param bytes body_bytes: The body of the response. + :param dict headers: The headers of the response. + :returns: The deserialized data. + :rtype: object + """ + # Try to use content-type from headers if available + content_type = None + if "content-type" in headers: + content_type = headers["content-type"].split(";")[0].strip().lower() + # Ouch, this server did not declare what it sent... + # Let's guess it's JSON... + # Also, since Autorest was considering that an empty body was a valid JSON, + # need that test as well.... + else: + content_type = "application/json" + + if body_bytes: + return cls.deserialize_from_text(body_bytes, content_type) + return None + + +_LOGGER = logging.getLogger(__name__) + +try: + _long_type = long # type: ignore +except NameError: + _long_type = int + +TZ_UTC = datetime.timezone.utc + +_FLATTEN = re.compile(r"(? None: + self.additional_properties: Optional[Dict[str, Any]] = {} + for k in kwargs: # pylint: disable=consider-using-dict-items + if k not in self._attribute_map: + _LOGGER.warning("%s is not a known attribute of class %s and will be ignored", k, self.__class__) + elif k in self._validation and self._validation[k].get("readonly", False): + _LOGGER.warning("Readonly attribute %s will be ignored in class %s", k, self.__class__) + else: + setattr(self, k, kwargs[k]) + + def __eq__(self, other: Any) -> bool: + """Compare objects by comparing all attributes. + + :param object other: The object to compare + :returns: True if objects are equal + :rtype: bool + """ + if isinstance(other, self.__class__): + return self.__dict__ == other.__dict__ + return False + + def __ne__(self, other: Any) -> bool: + """Compare objects by comparing all attributes. + + :param object other: The object to compare + :returns: True if objects are not equal + :rtype: bool + """ + return not self.__eq__(other) + + def __str__(self) -> str: + return str(self.__dict__) + + @classmethod + def enable_additional_properties_sending(cls) -> None: + cls._attribute_map["additional_properties"] = {"key": "", "type": "{object}"} + + @classmethod + def is_xml_model(cls) -> bool: + try: + cls._xml_map # type: ignore + except AttributeError: + return False + return True + + @classmethod + def _create_xml_node(cls): + """Create XML node. + + :returns: The XML node + :rtype: xml.etree.ElementTree.Element + """ + try: + xml_map = cls._xml_map # type: ignore + except AttributeError: + xml_map = {} + + return _create_xml_node(xml_map.get("name", cls.__name__), xml_map.get("prefix", None), xml_map.get("ns", None)) + + def serialize(self, keep_readonly: bool = False, **kwargs: Any) -> JSON: + """Return the JSON that would be sent to server from this model. + + This is an alias to `as_dict(full_restapi_key_transformer, keep_readonly=False)`. + + If you want XML serialization, you can pass the kwargs is_xml=True. + + :param bool keep_readonly: If you want to serialize the readonly attributes + :returns: A dict JSON compatible object + :rtype: dict + """ + serializer = Serializer(self._infer_class_models()) + return serializer._serialize( # type: ignore # pylint: disable=protected-access + self, keep_readonly=keep_readonly, **kwargs + ) + + def as_dict( + self, + keep_readonly: bool = True, + key_transformer: Callable[[str, Dict[str, Any], Any], Any] = attribute_transformer, + **kwargs: Any + ) -> JSON: + """Return a dict that can be serialized using json.dump. + + Advanced usage might optionally use a callback as parameter: + + .. code::python + + def my_key_transformer(key, attr_desc, value): + return key + + Key is the attribute name used in Python. Attr_desc + is a dict of metadata. Currently contains 'type' with the + msrest type and 'key' with the RestAPI encoded key. + Value is the current value in this object. + + The string returned will be used to serialize the key. + If the return type is a list, this is considered hierarchical + result dict. + + See the three examples in this file: + + - attribute_transformer + - full_restapi_key_transformer + - last_restapi_key_transformer + + If you want XML serialization, you can pass the kwargs is_xml=True. + + :param bool keep_readonly: If you want to serialize the readonly attributes + :param function key_transformer: A key transformer function. + :returns: A dict JSON compatible object + :rtype: dict + """ + serializer = Serializer(self._infer_class_models()) + return serializer._serialize( # type: ignore # pylint: disable=protected-access + self, key_transformer=key_transformer, keep_readonly=keep_readonly, **kwargs + ) + + @classmethod + def _infer_class_models(cls): + try: + str_models = cls.__module__.rsplit(".", 1)[0] + models = sys.modules[str_models] + client_models = {k: v for k, v in models.__dict__.items() if isinstance(v, type)} + if cls.__name__ not in client_models: + raise ValueError("Not Autorest generated code") + except Exception: # pylint: disable=broad-exception-caught + # Assume it's not Autorest generated (tests?). Add ourselves as dependencies. + client_models = {cls.__name__: cls} + return client_models + + @classmethod + def deserialize(cls, data: Any, content_type: Optional[str] = None) -> Self: + """Parse a str using the RestAPI syntax and return a model. + + :param str data: A str using RestAPI structure. JSON by default. + :param str content_type: JSON by default, set application/xml if XML. + :returns: An instance of this model + :raises DeserializationError: if something went wrong + :rtype: Self + """ + deserializer = Deserializer(cls._infer_class_models()) + return deserializer(cls.__name__, data, content_type=content_type) # type: ignore + + @classmethod + def from_dict( + cls, + data: Any, + key_extractors: Optional[Callable[[str, Dict[str, Any], Any], Any]] = None, + content_type: Optional[str] = None, + ) -> Self: + """Parse a dict using given key extractor return a model. + + By default consider key + extractors (rest_key_case_insensitive_extractor, attribute_key_case_insensitive_extractor + and last_rest_key_case_insensitive_extractor) + + :param dict data: A dict using RestAPI structure + :param function key_extractors: A key extractor function. + :param str content_type: JSON by default, set application/xml if XML. + :returns: An instance of this model + :raises DeserializationError: if something went wrong + :rtype: Self + """ + deserializer = Deserializer(cls._infer_class_models()) + deserializer.key_extractors = ( # type: ignore + [ # type: ignore + attribute_key_case_insensitive_extractor, + rest_key_case_insensitive_extractor, + last_rest_key_case_insensitive_extractor, + ] + if key_extractors is None + else key_extractors + ) + return deserializer(cls.__name__, data, content_type=content_type) # type: ignore + + @classmethod + def _flatten_subtype(cls, key, objects): + if "_subtype_map" not in cls.__dict__: + return {} + result = dict(cls._subtype_map[key]) + for valuetype in cls._subtype_map[key].values(): + result.update(objects[valuetype]._flatten_subtype(key, objects)) # pylint: disable=protected-access + return result + + @classmethod + def _classify(cls, response, objects): + """Check the class _subtype_map for any child classes. + We want to ignore any inherited _subtype_maps. + + :param dict response: The initial data + :param dict objects: The class objects + :returns: The class to be used + :rtype: class + """ + for subtype_key in cls.__dict__.get("_subtype_map", {}).keys(): + subtype_value = None + + if not isinstance(response, ET.Element): + rest_api_response_key = cls._get_rest_key_parts(subtype_key)[-1] + subtype_value = response.get(rest_api_response_key, None) or response.get(subtype_key, None) + else: + subtype_value = xml_key_extractor(subtype_key, cls._attribute_map[subtype_key], response) + if subtype_value: + # Try to match base class. Can be class name only + # (bug to fix in Autorest to support x-ms-discriminator-name) + if cls.__name__ == subtype_value: + return cls + flatten_mapping_type = cls._flatten_subtype(subtype_key, objects) + try: + return objects[flatten_mapping_type[subtype_value]] # type: ignore + except KeyError: + _LOGGER.warning( + "Subtype value %s has no mapping, use base class %s.", + subtype_value, + cls.__name__, + ) + break + else: + _LOGGER.warning("Discriminator %s is absent or null, use base class %s.", subtype_key, cls.__name__) + break + return cls + + @classmethod + def _get_rest_key_parts(cls, attr_key): + """Get the RestAPI key of this attr, split it and decode part + :param str attr_key: Attribute key must be in attribute_map. + :returns: A list of RestAPI part + :rtype: list + """ + rest_split_key = _FLATTEN.split(cls._attribute_map[attr_key]["key"]) + return [_decode_attribute_map_key(key_part) for key_part in rest_split_key] + + +def _decode_attribute_map_key(key): + """This decode a key in an _attribute_map to the actual key we want to look at + inside the received data. + + :param str key: A key string from the generated code + :returns: The decoded key + :rtype: str + """ + return key.replace("\\.", ".") + + +class Serializer: # pylint: disable=too-many-public-methods + """Request object model serializer.""" + + basic_types = {str: "str", int: "int", bool: "bool", float: "float"} + + _xml_basic_types_serializers = {"bool": lambda x: str(x).lower()} + days = {0: "Mon", 1: "Tue", 2: "Wed", 3: "Thu", 4: "Fri", 5: "Sat", 6: "Sun"} + months = { + 1: "Jan", + 2: "Feb", + 3: "Mar", + 4: "Apr", + 5: "May", + 6: "Jun", + 7: "Jul", + 8: "Aug", + 9: "Sep", + 10: "Oct", + 11: "Nov", + 12: "Dec", + } + validation = { + "min_length": lambda x, y: len(x) < y, + "max_length": lambda x, y: len(x) > y, + "minimum": lambda x, y: x < y, + "maximum": lambda x, y: x > y, + "minimum_ex": lambda x, y: x <= y, + "maximum_ex": lambda x, y: x >= y, + "min_items": lambda x, y: len(x) < y, + "max_items": lambda x, y: len(x) > y, + "pattern": lambda x, y: not re.match(y, x, re.UNICODE), + "unique": lambda x, y: len(x) != len(set(x)), + "multiple": lambda x, y: x % y != 0, + } + + def __init__(self, classes: Optional[Mapping[str, type]] = None) -> None: + self.serialize_type = { + "iso-8601": Serializer.serialize_iso, + "rfc-1123": Serializer.serialize_rfc, + "unix-time": Serializer.serialize_unix, + "duration": Serializer.serialize_duration, + "date": Serializer.serialize_date, + "time": Serializer.serialize_time, + "decimal": Serializer.serialize_decimal, + "long": Serializer.serialize_long, + "bytearray": Serializer.serialize_bytearray, + "base64": Serializer.serialize_base64, + "object": self.serialize_object, + "[]": self.serialize_iter, + "{}": self.serialize_dict, + } + self.dependencies: Dict[str, type] = dict(classes) if classes else {} + self.key_transformer = full_restapi_key_transformer + self.client_side_validation = True + + def _serialize( # pylint: disable=too-many-nested-blocks, too-many-branches, too-many-statements, too-many-locals + self, target_obj, data_type=None, **kwargs + ): + """Serialize data into a string according to type. + + :param object target_obj: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str, dict + :raises SerializationError: if serialization fails. + :returns: The serialized data. + """ + key_transformer = kwargs.get("key_transformer", self.key_transformer) + keep_readonly = kwargs.get("keep_readonly", False) + if target_obj is None: + return None + + attr_name = None + class_name = target_obj.__class__.__name__ + + if data_type: + return self.serialize_data(target_obj, data_type, **kwargs) + + if not hasattr(target_obj, "_attribute_map"): + data_type = type(target_obj).__name__ + if data_type in self.basic_types.values(): + return self.serialize_data(target_obj, data_type, **kwargs) + + # Force "is_xml" kwargs if we detect a XML model + try: + is_xml_model_serialization = kwargs["is_xml"] + except KeyError: + is_xml_model_serialization = kwargs.setdefault("is_xml", target_obj.is_xml_model()) + + serialized = {} + if is_xml_model_serialization: + serialized = target_obj._create_xml_node() # pylint: disable=protected-access + try: + attributes = target_obj._attribute_map # pylint: disable=protected-access + for attr, attr_desc in attributes.items(): + attr_name = attr + if not keep_readonly and target_obj._validation.get( # pylint: disable=protected-access + attr_name, {} + ).get("readonly", False): + continue + + if attr_name == "additional_properties" and attr_desc["key"] == "": + if target_obj.additional_properties is not None: + serialized.update(target_obj.additional_properties) + continue + try: + + orig_attr = getattr(target_obj, attr) + if is_xml_model_serialization: + pass # Don't provide "transformer" for XML for now. Keep "orig_attr" + else: # JSON + keys, orig_attr = key_transformer(attr, attr_desc.copy(), orig_attr) + keys = keys if isinstance(keys, list) else [keys] + + kwargs["serialization_ctxt"] = attr_desc + new_attr = self.serialize_data(orig_attr, attr_desc["type"], **kwargs) + + if is_xml_model_serialization: + xml_desc = attr_desc.get("xml", {}) + xml_name = xml_desc.get("name", attr_desc["key"]) + xml_prefix = xml_desc.get("prefix", None) + xml_ns = xml_desc.get("ns", None) + if xml_desc.get("attr", False): + if xml_ns: + ET.register_namespace(xml_prefix, xml_ns) + xml_name = "{{{}}}{}".format(xml_ns, xml_name) + serialized.set(xml_name, new_attr) # type: ignore + continue + if xml_desc.get("text", False): + serialized.text = new_attr # type: ignore + continue + if isinstance(new_attr, list): + serialized.extend(new_attr) # type: ignore + elif isinstance(new_attr, ET.Element): + # If the down XML has no XML/Name, + # we MUST replace the tag with the local tag. But keeping the namespaces. + if "name" not in getattr(orig_attr, "_xml_map", {}): + splitted_tag = new_attr.tag.split("}") + if len(splitted_tag) == 2: # Namespace + new_attr.tag = "}".join([splitted_tag[0], xml_name]) + else: + new_attr.tag = xml_name + serialized.append(new_attr) # type: ignore + else: # That's a basic type + # Integrate namespace if necessary + local_node = _create_xml_node(xml_name, xml_prefix, xml_ns) + local_node.text = str(new_attr) + serialized.append(local_node) # type: ignore + else: # JSON + for k in reversed(keys): # type: ignore + new_attr = {k: new_attr} + + _new_attr = new_attr + _serialized = serialized + for k in keys: # type: ignore + if k not in _serialized: + _serialized.update(_new_attr) # type: ignore + _new_attr = _new_attr[k] # type: ignore + _serialized = _serialized[k] + except ValueError as err: + if isinstance(err, SerializationError): + raise + + except (AttributeError, KeyError, TypeError) as err: + msg = "Attribute {} in object {} cannot be serialized.\n{}".format(attr_name, class_name, str(target_obj)) + raise SerializationError(msg) from err + return serialized + + def body(self, data, data_type, **kwargs): + """Serialize data intended for a request body. + + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: dict + :raises SerializationError: if serialization fails. + :raises ValueError: if data is None + :returns: The serialized request body + """ + + # Just in case this is a dict + internal_data_type_str = data_type.strip("[]{}") + internal_data_type = self.dependencies.get(internal_data_type_str, None) + try: + is_xml_model_serialization = kwargs["is_xml"] + except KeyError: + if internal_data_type and issubclass(internal_data_type, Model): + is_xml_model_serialization = kwargs.setdefault("is_xml", internal_data_type.is_xml_model()) + else: + is_xml_model_serialization = False + if internal_data_type and not isinstance(internal_data_type, Enum): + try: + deserializer = Deserializer(self.dependencies) + # Since it's on serialization, it's almost sure that format is not JSON REST + # We're not able to deal with additional properties for now. + deserializer.additional_properties_detection = False + if is_xml_model_serialization: + deserializer.key_extractors = [ # type: ignore + attribute_key_case_insensitive_extractor, + ] + else: + deserializer.key_extractors = [ + rest_key_case_insensitive_extractor, + attribute_key_case_insensitive_extractor, + last_rest_key_case_insensitive_extractor, + ] + data = deserializer._deserialize(data_type, data) # pylint: disable=protected-access + except DeserializationError as err: + raise SerializationError("Unable to build a model: " + str(err)) from err + + return self._serialize(data, data_type, **kwargs) + + def url(self, name, data, data_type, **kwargs): + """Serialize data intended for a URL path. + + :param str name: The name of the URL path parameter. + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str + :returns: The serialized URL path + :raises TypeError: if serialization fails. + :raises ValueError: if data is None + """ + try: + output = self.serialize_data(data, data_type, **kwargs) + if data_type == "bool": + output = json.dumps(output) + + if kwargs.get("skip_quote") is True: + output = str(output) + output = output.replace("{", quote("{")).replace("}", quote("}")) + else: + output = quote(str(output), safe="") + except SerializationError as exc: + raise TypeError("{} must be type {}.".format(name, data_type)) from exc + return output + + def query(self, name, data, data_type, **kwargs): + """Serialize data intended for a URL query. + + :param str name: The name of the query parameter. + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str, list + :raises TypeError: if serialization fails. + :raises ValueError: if data is None + :returns: The serialized query parameter + """ + try: + # Treat the list aside, since we don't want to encode the div separator + if data_type.startswith("["): + internal_data_type = data_type[1:-1] + do_quote = not kwargs.get("skip_quote", False) + return self.serialize_iter(data, internal_data_type, do_quote=do_quote, **kwargs) + + # Not a list, regular serialization + output = self.serialize_data(data, data_type, **kwargs) + if data_type == "bool": + output = json.dumps(output) + if kwargs.get("skip_quote") is True: + output = str(output) + else: + output = quote(str(output), safe="") + except SerializationError as exc: + raise TypeError("{} must be type {}.".format(name, data_type)) from exc + return str(output) + + def header(self, name, data, data_type, **kwargs): + """Serialize data intended for a request header. + + :param str name: The name of the header. + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str + :raises TypeError: if serialization fails. + :raises ValueError: if data is None + :returns: The serialized header + """ + try: + if data_type in ["[str]"]: + data = ["" if d is None else d for d in data] + + output = self.serialize_data(data, data_type, **kwargs) + if data_type == "bool": + output = json.dumps(output) + except SerializationError as exc: + raise TypeError("{} must be type {}.".format(name, data_type)) from exc + return str(output) + + def serialize_data(self, data, data_type, **kwargs): + """Serialize generic data according to supplied data type. + + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :raises AttributeError: if required data is None. + :raises ValueError: if data is None + :raises SerializationError: if serialization fails. + :returns: The serialized data. + :rtype: str, int, float, bool, dict, list + """ + if data is None: + raise ValueError("No value for given attribute") + + try: + if data is CoreNull: + return None + if data_type in self.basic_types.values(): + return self.serialize_basic(data, data_type, **kwargs) + + if data_type in self.serialize_type: + return self.serialize_type[data_type](data, **kwargs) + + # If dependencies is empty, try with current data class + # It has to be a subclass of Enum anyway + enum_type = self.dependencies.get(data_type, data.__class__) + if issubclass(enum_type, Enum): + return Serializer.serialize_enum(data, enum_obj=enum_type) + + iter_type = data_type[0] + data_type[-1] + if iter_type in self.serialize_type: + return self.serialize_type[iter_type](data, data_type[1:-1], **kwargs) + + except (ValueError, TypeError) as err: + msg = "Unable to serialize value: {!r} as type: {!r}." + raise SerializationError(msg.format(data, data_type)) from err + return self._serialize(data, **kwargs) + + @classmethod + def _get_custom_serializers(cls, data_type, **kwargs): # pylint: disable=inconsistent-return-statements + custom_serializer = kwargs.get("basic_types_serializers", {}).get(data_type) + if custom_serializer: + return custom_serializer + if kwargs.get("is_xml", False): + return cls._xml_basic_types_serializers.get(data_type) + + @classmethod + def serialize_basic(cls, data, data_type, **kwargs): + """Serialize basic builting data type. + Serializes objects to str, int, float or bool. + + Possible kwargs: + - basic_types_serializers dict[str, callable] : If set, use the callable as serializer + - is_xml bool : If set, use xml_basic_types_serializers + + :param obj data: Object to be serialized. + :param str data_type: Type of object in the iterable. + :rtype: str, int, float, bool + :return: serialized object + """ + custom_serializer = cls._get_custom_serializers(data_type, **kwargs) + if custom_serializer: + return custom_serializer(data) + if data_type == "str": + return cls.serialize_unicode(data) + return eval(data_type)(data) # nosec # pylint: disable=eval-used + + @classmethod + def serialize_unicode(cls, data): + """Special handling for serializing unicode strings in Py2. + Encode to UTF-8 if unicode, otherwise handle as a str. + + :param str data: Object to be serialized. + :rtype: str + :return: serialized object + """ + try: # If I received an enum, return its value + return data.value + except AttributeError: + pass + + try: + if isinstance(data, unicode): # type: ignore + # Don't change it, JSON and XML ElementTree are totally able + # to serialize correctly u'' strings + return data + except NameError: + return str(data) + return str(data) + + def serialize_iter(self, data, iter_type, div=None, **kwargs): + """Serialize iterable. + + Supported kwargs: + - serialization_ctxt dict : The current entry of _attribute_map, or same format. + serialization_ctxt['type'] should be same as data_type. + - is_xml bool : If set, serialize as XML + + :param list data: Object to be serialized. + :param str iter_type: Type of object in the iterable. + :param str div: If set, this str will be used to combine the elements + in the iterable into a combined string. Default is 'None'. + Defaults to False. + :rtype: list, str + :return: serialized iterable + """ + if isinstance(data, str): + raise SerializationError("Refuse str type as a valid iter type.") + + serialization_ctxt = kwargs.get("serialization_ctxt", {}) + is_xml = kwargs.get("is_xml", False) + + serialized = [] + for d in data: + try: + serialized.append(self.serialize_data(d, iter_type, **kwargs)) + except ValueError as err: + if isinstance(err, SerializationError): + raise + serialized.append(None) + + if kwargs.get("do_quote", False): + serialized = ["" if s is None else quote(str(s), safe="") for s in serialized] + + if div: + serialized = ["" if s is None else str(s) for s in serialized] + serialized = div.join(serialized) + + if "xml" in serialization_ctxt or is_xml: + # XML serialization is more complicated + xml_desc = serialization_ctxt.get("xml", {}) + xml_name = xml_desc.get("name") + if not xml_name: + xml_name = serialization_ctxt["key"] + + # Create a wrap node if necessary (use the fact that Element and list have "append") + is_wrapped = xml_desc.get("wrapped", False) + node_name = xml_desc.get("itemsName", xml_name) + if is_wrapped: + final_result = _create_xml_node(xml_name, xml_desc.get("prefix", None), xml_desc.get("ns", None)) + else: + final_result = [] + # All list elements to "local_node" + for el in serialized: + if isinstance(el, ET.Element): + el_node = el + else: + el_node = _create_xml_node(node_name, xml_desc.get("prefix", None), xml_desc.get("ns", None)) + if el is not None: # Otherwise it writes "None" :-p + el_node.text = str(el) + final_result.append(el_node) + return final_result + return serialized + + def serialize_dict(self, attr, dict_type, **kwargs): + """Serialize a dictionary of objects. + + :param dict attr: Object to be serialized. + :param str dict_type: Type of object in the dictionary. + :rtype: dict + :return: serialized dictionary + """ + serialization_ctxt = kwargs.get("serialization_ctxt", {}) + serialized = {} + for key, value in attr.items(): + try: + serialized[self.serialize_unicode(key)] = self.serialize_data(value, dict_type, **kwargs) + except ValueError as err: + if isinstance(err, SerializationError): + raise + serialized[self.serialize_unicode(key)] = None + + if "xml" in serialization_ctxt: + # XML serialization is more complicated + xml_desc = serialization_ctxt["xml"] + xml_name = xml_desc["name"] + + final_result = _create_xml_node(xml_name, xml_desc.get("prefix", None), xml_desc.get("ns", None)) + for key, value in serialized.items(): + ET.SubElement(final_result, key).text = value + return final_result + + return serialized + + def serialize_object(self, attr, **kwargs): # pylint: disable=too-many-return-statements + """Serialize a generic object. + This will be handled as a dictionary. If object passed in is not + a basic type (str, int, float, dict, list) it will simply be + cast to str. + + :param dict attr: Object to be serialized. + :rtype: dict or str + :return: serialized object + """ + if attr is None: + return None + if isinstance(attr, ET.Element): + return attr + obj_type = type(attr) + if obj_type in self.basic_types: + return self.serialize_basic(attr, self.basic_types[obj_type], **kwargs) + if obj_type is _long_type: + return self.serialize_long(attr) + if obj_type is str: + return self.serialize_unicode(attr) + if obj_type is datetime.datetime: + return self.serialize_iso(attr) + if obj_type is datetime.date: + return self.serialize_date(attr) + if obj_type is datetime.time: + return self.serialize_time(attr) + if obj_type is datetime.timedelta: + return self.serialize_duration(attr) + if obj_type is decimal.Decimal: + return self.serialize_decimal(attr) + + # If it's a model or I know this dependency, serialize as a Model + if obj_type in self.dependencies.values() or isinstance(attr, Model): + return self._serialize(attr) + + if obj_type == dict: + serialized = {} + for key, value in attr.items(): + try: + serialized[self.serialize_unicode(key)] = self.serialize_object(value, **kwargs) + except ValueError: + serialized[self.serialize_unicode(key)] = None + return serialized + + if obj_type == list: + serialized = [] + for obj in attr: + try: + serialized.append(self.serialize_object(obj, **kwargs)) + except ValueError: + pass + return serialized + return str(attr) + + @staticmethod + def serialize_enum(attr, enum_obj=None): + try: + result = attr.value + except AttributeError: + result = attr + try: + enum_obj(result) # type: ignore + return result + except ValueError as exc: + for enum_value in enum_obj: # type: ignore + if enum_value.value.lower() == str(attr).lower(): + return enum_value.value + error = "{!r} is not valid value for enum {!r}" + raise SerializationError(error.format(attr, enum_obj)) from exc + + @staticmethod + def serialize_bytearray(attr, **kwargs): # pylint: disable=unused-argument + """Serialize bytearray into base-64 string. + + :param str attr: Object to be serialized. + :rtype: str + :return: serialized base64 + """ + return b64encode(attr).decode() + + @staticmethod + def serialize_base64(attr, **kwargs): # pylint: disable=unused-argument + """Serialize str into base-64 string. + + :param str attr: Object to be serialized. + :rtype: str + :return: serialized base64 + """ + encoded = b64encode(attr).decode("ascii") + return encoded.strip("=").replace("+", "-").replace("/", "_") + + @staticmethod + def serialize_decimal(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Decimal object to float. + + :param decimal attr: Object to be serialized. + :rtype: float + :return: serialized decimal + """ + return float(attr) + + @staticmethod + def serialize_long(attr, **kwargs): # pylint: disable=unused-argument + """Serialize long (Py2) or int (Py3). + + :param int attr: Object to be serialized. + :rtype: int/long + :return: serialized long + """ + return _long_type(attr) + + @staticmethod + def serialize_date(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Date object into ISO-8601 formatted string. + + :param Date attr: Object to be serialized. + :rtype: str + :return: serialized date + """ + if isinstance(attr, str): + attr = isodate.parse_date(attr) + t = "{:04}-{:02}-{:02}".format(attr.year, attr.month, attr.day) + return t + + @staticmethod + def serialize_time(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Time object into ISO-8601 formatted string. + + :param datetime.time attr: Object to be serialized. + :rtype: str + :return: serialized time + """ + if isinstance(attr, str): + attr = isodate.parse_time(attr) + t = "{:02}:{:02}:{:02}".format(attr.hour, attr.minute, attr.second) + if attr.microsecond: + t += ".{:02}".format(attr.microsecond) + return t + + @staticmethod + def serialize_duration(attr, **kwargs): # pylint: disable=unused-argument + """Serialize TimeDelta object into ISO-8601 formatted string. + + :param TimeDelta attr: Object to be serialized. + :rtype: str + :return: serialized duration + """ + if isinstance(attr, str): + attr = isodate.parse_duration(attr) + return isodate.duration_isoformat(attr) + + @staticmethod + def serialize_rfc(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Datetime object into RFC-1123 formatted string. + + :param Datetime attr: Object to be serialized. + :rtype: str + :raises TypeError: if format invalid. + :return: serialized rfc + """ + try: + if not attr.tzinfo: + _LOGGER.warning("Datetime with no tzinfo will be considered UTC.") + utc = attr.utctimetuple() + except AttributeError as exc: + raise TypeError("RFC1123 object must be valid Datetime object.") from exc + + return "{}, {:02} {} {:04} {:02}:{:02}:{:02} GMT".format( + Serializer.days[utc.tm_wday], + utc.tm_mday, + Serializer.months[utc.tm_mon], + utc.tm_year, + utc.tm_hour, + utc.tm_min, + utc.tm_sec, + ) + + @staticmethod + def serialize_iso(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Datetime object into ISO-8601 formatted string. + + :param Datetime attr: Object to be serialized. + :rtype: str + :raises SerializationError: if format invalid. + :return: serialized iso + """ + if isinstance(attr, str): + attr = isodate.parse_datetime(attr) + try: + if not attr.tzinfo: + _LOGGER.warning("Datetime with no tzinfo will be considered UTC.") + utc = attr.utctimetuple() + if utc.tm_year > 9999 or utc.tm_year < 1: + raise OverflowError("Hit max or min date") + + microseconds = str(attr.microsecond).rjust(6, "0").rstrip("0").ljust(3, "0") + if microseconds: + microseconds = "." + microseconds + date = "{:04}-{:02}-{:02}T{:02}:{:02}:{:02}".format( + utc.tm_year, utc.tm_mon, utc.tm_mday, utc.tm_hour, utc.tm_min, utc.tm_sec + ) + return date + microseconds + "Z" + except (ValueError, OverflowError) as err: + msg = "Unable to serialize datetime object." + raise SerializationError(msg) from err + except AttributeError as err: + msg = "ISO-8601 object must be valid Datetime object." + raise TypeError(msg) from err + + @staticmethod + def serialize_unix(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Datetime object into IntTime format. + This is represented as seconds. + + :param Datetime attr: Object to be serialized. + :rtype: int + :raises SerializationError: if format invalid + :return: serialied unix + """ + if isinstance(attr, int): + return attr + try: + if not attr.tzinfo: + _LOGGER.warning("Datetime with no tzinfo will be considered UTC.") + return int(calendar.timegm(attr.utctimetuple())) + except AttributeError as exc: + raise TypeError("Unix time object must be valid Datetime object.") from exc + + +def rest_key_extractor(attr, attr_desc, data): # pylint: disable=unused-argument + key = attr_desc["key"] + working_data = data + + while "." in key: + # Need the cast, as for some reasons "split" is typed as list[str | Any] + dict_keys = cast(List[str], _FLATTEN.split(key)) + if len(dict_keys) == 1: + key = _decode_attribute_map_key(dict_keys[0]) + break + working_key = _decode_attribute_map_key(dict_keys[0]) + working_data = working_data.get(working_key, data) + if working_data is None: + # If at any point while following flatten JSON path see None, it means + # that all properties under are None as well + return None + key = ".".join(dict_keys[1:]) + + return working_data.get(key) + + +def rest_key_case_insensitive_extractor( # pylint: disable=unused-argument, inconsistent-return-statements + attr, attr_desc, data +): + key = attr_desc["key"] + working_data = data + + while "." in key: + dict_keys = _FLATTEN.split(key) + if len(dict_keys) == 1: + key = _decode_attribute_map_key(dict_keys[0]) + break + working_key = _decode_attribute_map_key(dict_keys[0]) + working_data = attribute_key_case_insensitive_extractor(working_key, None, working_data) + if working_data is None: + # If at any point while following flatten JSON path see None, it means + # that all properties under are None as well + return None + key = ".".join(dict_keys[1:]) + + if working_data: + return attribute_key_case_insensitive_extractor(key, None, working_data) + + +def last_rest_key_extractor(attr, attr_desc, data): # pylint: disable=unused-argument + """Extract the attribute in "data" based on the last part of the JSON path key. + + :param str attr: The attribute to extract + :param dict attr_desc: The attribute description + :param dict data: The data to extract from + :rtype: object + :returns: The extracted attribute + """ + key = attr_desc["key"] + dict_keys = _FLATTEN.split(key) + return attribute_key_extractor(dict_keys[-1], None, data) + + +def last_rest_key_case_insensitive_extractor(attr, attr_desc, data): # pylint: disable=unused-argument + """Extract the attribute in "data" based on the last part of the JSON path key. + + This is the case insensitive version of "last_rest_key_extractor" + :param str attr: The attribute to extract + :param dict attr_desc: The attribute description + :param dict data: The data to extract from + :rtype: object + :returns: The extracted attribute + """ + key = attr_desc["key"] + dict_keys = _FLATTEN.split(key) + return attribute_key_case_insensitive_extractor(dict_keys[-1], None, data) + + +def attribute_key_extractor(attr, _, data): + return data.get(attr) + + +def attribute_key_case_insensitive_extractor(attr, _, data): + found_key = None + lower_attr = attr.lower() + for key in data: + if lower_attr == key.lower(): + found_key = key + break + + return data.get(found_key) + + +def _extract_name_from_internal_type(internal_type): + """Given an internal type XML description, extract correct XML name with namespace. + + :param dict internal_type: An model type + :rtype: tuple + :returns: A tuple XML name + namespace dict + """ + internal_type_xml_map = getattr(internal_type, "_xml_map", {}) + xml_name = internal_type_xml_map.get("name", internal_type.__name__) + xml_ns = internal_type_xml_map.get("ns", None) + if xml_ns: + xml_name = "{{{}}}{}".format(xml_ns, xml_name) + return xml_name + + +def xml_key_extractor(attr, attr_desc, data): # pylint: disable=unused-argument,too-many-return-statements + if isinstance(data, dict): + return None + + # Test if this model is XML ready first + if not isinstance(data, ET.Element): + return None + + xml_desc = attr_desc.get("xml", {}) + xml_name = xml_desc.get("name", attr_desc["key"]) + + # Look for a children + is_iter_type = attr_desc["type"].startswith("[") + is_wrapped = xml_desc.get("wrapped", False) + internal_type = attr_desc.get("internalType", None) + internal_type_xml_map = getattr(internal_type, "_xml_map", {}) + + # Integrate namespace if necessary + xml_ns = xml_desc.get("ns", internal_type_xml_map.get("ns", None)) + if xml_ns: + xml_name = "{{{}}}{}".format(xml_ns, xml_name) + + # If it's an attribute, that's simple + if xml_desc.get("attr", False): + return data.get(xml_name) + + # If it's x-ms-text, that's simple too + if xml_desc.get("text", False): + return data.text + + # Scenario where I take the local name: + # - Wrapped node + # - Internal type is an enum (considered basic types) + # - Internal type has no XML/Name node + if is_wrapped or (internal_type and (issubclass(internal_type, Enum) or "name" not in internal_type_xml_map)): + children = data.findall(xml_name) + # If internal type has a local name and it's not a list, I use that name + elif not is_iter_type and internal_type and "name" in internal_type_xml_map: + xml_name = _extract_name_from_internal_type(internal_type) + children = data.findall(xml_name) + # That's an array + else: + if internal_type: # Complex type, ignore itemsName and use the complex type name + items_name = _extract_name_from_internal_type(internal_type) + else: + items_name = xml_desc.get("itemsName", xml_name) + children = data.findall(items_name) + + if len(children) == 0: + if is_iter_type: + if is_wrapped: + return None # is_wrapped no node, we want None + return [] # not wrapped, assume empty list + return None # Assume it's not there, maybe an optional node. + + # If is_iter_type and not wrapped, return all found children + if is_iter_type: + if not is_wrapped: + return children + # Iter and wrapped, should have found one node only (the wrap one) + if len(children) != 1: + raise DeserializationError( + "Tried to deserialize an array not wrapped, and found several nodes '{}'. Maybe you should declare this array as wrapped?".format( + xml_name + ) + ) + return list(children[0]) # Might be empty list and that's ok. + + # Here it's not a itertype, we should have found one element only or empty + if len(children) > 1: + raise DeserializationError("Find several XML '{}' where it was not expected".format(xml_name)) + return children[0] + + +class Deserializer: + """Response object model deserializer. + + :param dict classes: Class type dictionary for deserializing complex types. + :ivar list key_extractors: Ordered list of extractors to be used by this deserializer. + """ + + basic_types = {str: "str", int: "int", bool: "bool", float: "float"} + + valid_date = re.compile(r"\d{4}[-]\d{2}[-]\d{2}T\d{2}:\d{2}:\d{2}\.?\d*Z?[-+]?[\d{2}]?:?[\d{2}]?") + + def __init__(self, classes: Optional[Mapping[str, type]] = None) -> None: + self.deserialize_type = { + "iso-8601": Deserializer.deserialize_iso, + "rfc-1123": Deserializer.deserialize_rfc, + "unix-time": Deserializer.deserialize_unix, + "duration": Deserializer.deserialize_duration, + "date": Deserializer.deserialize_date, + "time": Deserializer.deserialize_time, + "decimal": Deserializer.deserialize_decimal, + "long": Deserializer.deserialize_long, + "bytearray": Deserializer.deserialize_bytearray, + "base64": Deserializer.deserialize_base64, + "object": self.deserialize_object, + "[]": self.deserialize_iter, + "{}": self.deserialize_dict, + } + self.deserialize_expected_types = { + "duration": (isodate.Duration, datetime.timedelta), + "iso-8601": (datetime.datetime), + } + self.dependencies: Dict[str, type] = dict(classes) if classes else {} + self.key_extractors = [rest_key_extractor, xml_key_extractor] + # Additional properties only works if the "rest_key_extractor" is used to + # extract the keys. Making it to work whatever the key extractor is too much + # complicated, with no real scenario for now. + # So adding a flag to disable additional properties detection. This flag should be + # used if your expect the deserialization to NOT come from a JSON REST syntax. + # Otherwise, result are unexpected + self.additional_properties_detection = True + + def __call__(self, target_obj, response_data, content_type=None): + """Call the deserializer to process a REST response. + + :param str target_obj: Target data type to deserialize to. + :param requests.Response response_data: REST response object. + :param str content_type: Swagger "produces" if available. + :raises DeserializationError: if deserialization fails. + :return: Deserialized object. + :rtype: object + """ + data = self._unpack_content(response_data, content_type) + return self._deserialize(target_obj, data) + + def _deserialize(self, target_obj, data): # pylint: disable=inconsistent-return-statements + """Call the deserializer on a model. + + Data needs to be already deserialized as JSON or XML ElementTree + + :param str target_obj: Target data type to deserialize to. + :param object data: Object to deserialize. + :raises DeserializationError: if deserialization fails. + :return: Deserialized object. + :rtype: object + """ + # This is already a model, go recursive just in case + if hasattr(data, "_attribute_map"): + constants = [name for name, config in getattr(data, "_validation", {}).items() if config.get("constant")] + try: + for attr, mapconfig in data._attribute_map.items(): # pylint: disable=protected-access + if attr in constants: + continue + value = getattr(data, attr) + if value is None: + continue + local_type = mapconfig["type"] + internal_data_type = local_type.strip("[]{}") + if internal_data_type not in self.dependencies or isinstance(internal_data_type, Enum): + continue + setattr(data, attr, self._deserialize(local_type, value)) + return data + except AttributeError: + return + + response, class_name = self._classify_target(target_obj, data) + + if isinstance(response, str): + return self.deserialize_data(data, response) + if isinstance(response, type) and issubclass(response, Enum): + return self.deserialize_enum(data, response) + + if data is None or data is CoreNull: + return data + try: + attributes = response._attribute_map # type: ignore # pylint: disable=protected-access + d_attrs = {} + for attr, attr_desc in attributes.items(): + # Check empty string. If it's not empty, someone has a real "additionalProperties"... + if attr == "additional_properties" and attr_desc["key"] == "": + continue + raw_value = None + # Enhance attr_desc with some dynamic data + attr_desc = attr_desc.copy() # Do a copy, do not change the real one + internal_data_type = attr_desc["type"].strip("[]{}") + if internal_data_type in self.dependencies: + attr_desc["internalType"] = self.dependencies[internal_data_type] + + for key_extractor in self.key_extractors: + found_value = key_extractor(attr, attr_desc, data) + if found_value is not None: + if raw_value is not None and raw_value != found_value: + msg = ( + "Ignoring extracted value '%s' from %s for key '%s'" + " (duplicate extraction, follow extractors order)" + ) + _LOGGER.warning(msg, found_value, key_extractor, attr) + continue + raw_value = found_value + + value = self.deserialize_data(raw_value, attr_desc["type"]) + d_attrs[attr] = value + except (AttributeError, TypeError, KeyError) as err: + msg = "Unable to deserialize to object: " + class_name # type: ignore + raise DeserializationError(msg) from err + additional_properties = self._build_additional_properties(attributes, data) + return self._instantiate_model(response, d_attrs, additional_properties) + + def _build_additional_properties(self, attribute_map, data): + if not self.additional_properties_detection: + return None + if "additional_properties" in attribute_map and attribute_map.get("additional_properties", {}).get("key") != "": + # Check empty string. If it's not empty, someone has a real "additionalProperties" + return None + if isinstance(data, ET.Element): + data = {el.tag: el.text for el in data} + + known_keys = { + _decode_attribute_map_key(_FLATTEN.split(desc["key"])[0]) + for desc in attribute_map.values() + if desc["key"] != "" + } + present_keys = set(data.keys()) + missing_keys = present_keys - known_keys + return {key: data[key] for key in missing_keys} + + def _classify_target(self, target, data): + """Check to see whether the deserialization target object can + be classified into a subclass. + Once classification has been determined, initialize object. + + :param str target: The target object type to deserialize to. + :param str/dict data: The response data to deserialize. + :return: The classified target object and its class name. + :rtype: tuple + """ + if target is None: + return None, None + + if isinstance(target, str): + try: + target = self.dependencies[target] + except KeyError: + return target, target + + try: + target = target._classify(data, self.dependencies) # type: ignore # pylint: disable=protected-access + except AttributeError: + pass # Target is not a Model, no classify + return target, target.__class__.__name__ # type: ignore + + def failsafe_deserialize(self, target_obj, data, content_type=None): + """Ignores any errors encountered in deserialization, + and falls back to not deserializing the object. Recommended + for use in error deserialization, as we want to return the + HttpResponseError to users, and not have them deal with + a deserialization error. + + :param str target_obj: The target object type to deserialize to. + :param str/dict data: The response data to deserialize. + :param str content_type: Swagger "produces" if available. + :return: Deserialized object. + :rtype: object + """ + try: + return self(target_obj, data, content_type=content_type) + except: # pylint: disable=bare-except + _LOGGER.debug( + "Ran into a deserialization error. Ignoring since this is failsafe deserialization", exc_info=True + ) + return None + + @staticmethod + def _unpack_content(raw_data, content_type=None): + """Extract the correct structure for deserialization. + + If raw_data is a PipelineResponse, try to extract the result of RawDeserializer. + if we can't, raise. Your Pipeline should have a RawDeserializer. + + If not a pipeline response and raw_data is bytes or string, use content-type + to decode it. If no content-type, try JSON. + + If raw_data is something else, bypass all logic and return it directly. + + :param obj raw_data: Data to be processed. + :param str content_type: How to parse if raw_data is a string/bytes. + :raises JSONDecodeError: If JSON is requested and parsing is impossible. + :raises UnicodeDecodeError: If bytes is not UTF8 + :rtype: object + :return: Unpacked content. + """ + # Assume this is enough to detect a Pipeline Response without importing it + context = getattr(raw_data, "context", {}) + if context: + if RawDeserializer.CONTEXT_NAME in context: + return context[RawDeserializer.CONTEXT_NAME] + raise ValueError("This pipeline didn't have the RawDeserializer policy; can't deserialize") + + # Assume this is enough to recognize universal_http.ClientResponse without importing it + if hasattr(raw_data, "body"): + return RawDeserializer.deserialize_from_http_generics(raw_data.text(), raw_data.headers) + + # Assume this enough to recognize requests.Response without importing it. + if hasattr(raw_data, "_content_consumed"): + return RawDeserializer.deserialize_from_http_generics(raw_data.text, raw_data.headers) + + if isinstance(raw_data, (str, bytes)) or hasattr(raw_data, "read"): + return RawDeserializer.deserialize_from_text(raw_data, content_type) # type: ignore + return raw_data + + def _instantiate_model(self, response, attrs, additional_properties=None): + """Instantiate a response model passing in deserialized args. + + :param Response response: The response model class. + :param dict attrs: The deserialized response attributes. + :param dict additional_properties: Additional properties to be set. + :rtype: Response + :return: The instantiated response model. + """ + if callable(response): + subtype = getattr(response, "_subtype_map", {}) + try: + readonly = [ + k + for k, v in response._validation.items() # pylint: disable=protected-access # type: ignore + if v.get("readonly") + ] + const = [ + k + for k, v in response._validation.items() # pylint: disable=protected-access # type: ignore + if v.get("constant") + ] + kwargs = {k: v for k, v in attrs.items() if k not in subtype and k not in readonly + const} + response_obj = response(**kwargs) + for attr in readonly: + setattr(response_obj, attr, attrs.get(attr)) + if additional_properties: + response_obj.additional_properties = additional_properties # type: ignore + return response_obj + except TypeError as err: + msg = "Unable to deserialize {} into model {}. ".format(kwargs, response) # type: ignore + raise DeserializationError(msg + str(err)) from err + else: + try: + for attr, value in attrs.items(): + setattr(response, attr, value) + return response + except Exception as exp: + msg = "Unable to populate response model. " + msg += "Type: {}, Error: {}".format(type(response), exp) + raise DeserializationError(msg) from exp + + def deserialize_data(self, data, data_type): # pylint: disable=too-many-return-statements + """Process data for deserialization according to data type. + + :param str data: The response string to be deserialized. + :param str data_type: The type to deserialize to. + :raises DeserializationError: if deserialization fails. + :return: Deserialized object. + :rtype: object + """ + if data is None: + return data + + try: + if not data_type: + return data + if data_type in self.basic_types.values(): + return self.deserialize_basic(data, data_type) + if data_type in self.deserialize_type: + if isinstance(data, self.deserialize_expected_types.get(data_type, tuple())): + return data + + is_a_text_parsing_type = lambda x: x not in [ # pylint: disable=unnecessary-lambda-assignment + "object", + "[]", + r"{}", + ] + if isinstance(data, ET.Element) and is_a_text_parsing_type(data_type) and not data.text: + return None + data_val = self.deserialize_type[data_type](data) + return data_val + + iter_type = data_type[0] + data_type[-1] + if iter_type in self.deserialize_type: + return self.deserialize_type[iter_type](data, data_type[1:-1]) + + obj_type = self.dependencies[data_type] + if issubclass(obj_type, Enum): + if isinstance(data, ET.Element): + data = data.text + return self.deserialize_enum(data, obj_type) + + except (ValueError, TypeError, AttributeError) as err: + msg = "Unable to deserialize response data." + msg += " Data: {}, {}".format(data, data_type) + raise DeserializationError(msg) from err + return self._deserialize(obj_type, data) + + def deserialize_iter(self, attr, iter_type): + """Deserialize an iterable. + + :param list attr: Iterable to be deserialized. + :param str iter_type: The type of object in the iterable. + :return: Deserialized iterable. + :rtype: list + """ + if attr is None: + return None + if isinstance(attr, ET.Element): # If I receive an element here, get the children + attr = list(attr) + if not isinstance(attr, (list, set)): + raise DeserializationError("Cannot deserialize as [{}] an object of type {}".format(iter_type, type(attr))) + return [self.deserialize_data(a, iter_type) for a in attr] + + def deserialize_dict(self, attr, dict_type): + """Deserialize a dictionary. + + :param dict/list attr: Dictionary to be deserialized. Also accepts + a list of key, value pairs. + :param str dict_type: The object type of the items in the dictionary. + :return: Deserialized dictionary. + :rtype: dict + """ + if isinstance(attr, list): + return {x["key"]: self.deserialize_data(x["value"], dict_type) for x in attr} + + if isinstance(attr, ET.Element): + # Transform value into {"Key": "value"} + attr = {el.tag: el.text for el in attr} + return {k: self.deserialize_data(v, dict_type) for k, v in attr.items()} + + def deserialize_object(self, attr, **kwargs): # pylint: disable=too-many-return-statements + """Deserialize a generic object. + This will be handled as a dictionary. + + :param dict attr: Dictionary to be deserialized. + :return: Deserialized object. + :rtype: dict + :raises TypeError: if non-builtin datatype encountered. + """ + if attr is None: + return None + if isinstance(attr, ET.Element): + # Do no recurse on XML, just return the tree as-is + return attr + if isinstance(attr, str): + return self.deserialize_basic(attr, "str") + obj_type = type(attr) + if obj_type in self.basic_types: + return self.deserialize_basic(attr, self.basic_types[obj_type]) + if obj_type is _long_type: + return self.deserialize_long(attr) + + if obj_type == dict: + deserialized = {} + for key, value in attr.items(): + try: + deserialized[key] = self.deserialize_object(value, **kwargs) + except ValueError: + deserialized[key] = None + return deserialized + + if obj_type == list: + deserialized = [] + for obj in attr: + try: + deserialized.append(self.deserialize_object(obj, **kwargs)) + except ValueError: + pass + return deserialized + + error = "Cannot deserialize generic object with type: " + raise TypeError(error + str(obj_type)) + + def deserialize_basic(self, attr, data_type): # pylint: disable=too-many-return-statements + """Deserialize basic builtin data type from string. + Will attempt to convert to str, int, float and bool. + This function will also accept '1', '0', 'true' and 'false' as + valid bool values. + + :param str attr: response string to be deserialized. + :param str data_type: deserialization data type. + :return: Deserialized basic type. + :rtype: str, int, float or bool + :raises TypeError: if string format is not valid. + """ + # If we're here, data is supposed to be a basic type. + # If it's still an XML node, take the text + if isinstance(attr, ET.Element): + attr = attr.text + if not attr: + if data_type == "str": + # None or '', node is empty string. + return "" + # None or '', node with a strong type is None. + # Don't try to model "empty bool" or "empty int" + return None + + if data_type == "bool": + if attr in [True, False, 1, 0]: + return bool(attr) + if isinstance(attr, str): + if attr.lower() in ["true", "1"]: + return True + if attr.lower() in ["false", "0"]: + return False + raise TypeError("Invalid boolean value: {}".format(attr)) + + if data_type == "str": + return self.deserialize_unicode(attr) + return eval(data_type)(attr) # nosec # pylint: disable=eval-used + + @staticmethod + def deserialize_unicode(data): + """Preserve unicode objects in Python 2, otherwise return data + as a string. + + :param str data: response string to be deserialized. + :return: Deserialized string. + :rtype: str or unicode + """ + # We might be here because we have an enum modeled as string, + # and we try to deserialize a partial dict with enum inside + if isinstance(data, Enum): + return data + + # Consider this is real string + try: + if isinstance(data, unicode): # type: ignore + return data + except NameError: + return str(data) + return str(data) + + @staticmethod + def deserialize_enum(data, enum_obj): + """Deserialize string into enum object. + + If the string is not a valid enum value it will be returned as-is + and a warning will be logged. + + :param str data: Response string to be deserialized. If this value is + None or invalid it will be returned as-is. + :param Enum enum_obj: Enum object to deserialize to. + :return: Deserialized enum object. + :rtype: Enum + """ + if isinstance(data, enum_obj) or data is None: + return data + if isinstance(data, Enum): + data = data.value + if isinstance(data, int): + # Workaround. We might consider remove it in the future. + try: + return list(enum_obj.__members__.values())[data] + except IndexError as exc: + error = "{!r} is not a valid index for enum {!r}" + raise DeserializationError(error.format(data, enum_obj)) from exc + try: + return enum_obj(str(data)) + except ValueError: + for enum_value in enum_obj: + if enum_value.value.lower() == str(data).lower(): + return enum_value + # We don't fail anymore for unknown value, we deserialize as a string + _LOGGER.warning("Deserializer is not able to find %s as valid enum in %s", data, enum_obj) + return Deserializer.deserialize_unicode(data) + + @staticmethod + def deserialize_bytearray(attr): + """Deserialize string into bytearray. + + :param str attr: response string to be deserialized. + :return: Deserialized bytearray + :rtype: bytearray + :raises TypeError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + return bytearray(b64decode(attr)) # type: ignore + + @staticmethod + def deserialize_base64(attr): + """Deserialize base64 encoded string into string. + + :param str attr: response string to be deserialized. + :return: Deserialized base64 string + :rtype: bytearray + :raises TypeError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + padding = "=" * (3 - (len(attr) + 3) % 4) # type: ignore + attr = attr + padding # type: ignore + encoded = attr.replace("-", "+").replace("_", "/") + return b64decode(encoded) + + @staticmethod + def deserialize_decimal(attr): + """Deserialize string into Decimal object. + + :param str attr: response string to be deserialized. + :return: Deserialized decimal + :raises DeserializationError: if string format invalid. + :rtype: decimal + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + return decimal.Decimal(str(attr)) # type: ignore + except decimal.DecimalException as err: + msg = "Invalid decimal {}".format(attr) + raise DeserializationError(msg) from err + + @staticmethod + def deserialize_long(attr): + """Deserialize string into long (Py2) or int (Py3). + + :param str attr: response string to be deserialized. + :return: Deserialized int + :rtype: long or int + :raises ValueError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + return _long_type(attr) # type: ignore + + @staticmethod + def deserialize_duration(attr): + """Deserialize ISO-8601 formatted string into TimeDelta object. + + :param str attr: response string to be deserialized. + :return: Deserialized duration + :rtype: TimeDelta + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + duration = isodate.parse_duration(attr) + except (ValueError, OverflowError, AttributeError) as err: + msg = "Cannot deserialize duration object." + raise DeserializationError(msg) from err + return duration + + @staticmethod + def deserialize_date(attr): + """Deserialize ISO-8601 formatted string into Date object. + + :param str attr: response string to be deserialized. + :return: Deserialized date + :rtype: Date + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + if re.search(r"[^\W\d_]", attr, re.I + re.U): # type: ignore + raise DeserializationError("Date must have only digits and -. Received: %s" % attr) + # This must NOT use defaultmonth/defaultday. Using None ensure this raises an exception. + return isodate.parse_date(attr, defaultmonth=0, defaultday=0) + + @staticmethod + def deserialize_time(attr): + """Deserialize ISO-8601 formatted string into time object. + + :param str attr: response string to be deserialized. + :return: Deserialized time + :rtype: datetime.time + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + if re.search(r"[^\W\d_]", attr, re.I + re.U): # type: ignore + raise DeserializationError("Date must have only digits and -. Received: %s" % attr) + return isodate.parse_time(attr) + + @staticmethod + def deserialize_rfc(attr): + """Deserialize RFC-1123 formatted string into Datetime object. + + :param str attr: response string to be deserialized. + :return: Deserialized RFC datetime + :rtype: Datetime + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + parsed_date = email.utils.parsedate_tz(attr) # type: ignore + date_obj = datetime.datetime( + *parsed_date[:6], tzinfo=datetime.timezone(datetime.timedelta(minutes=(parsed_date[9] or 0) / 60)) + ) + if not date_obj.tzinfo: + date_obj = date_obj.astimezone(tz=TZ_UTC) + except ValueError as err: + msg = "Cannot deserialize to rfc datetime object." + raise DeserializationError(msg) from err + return date_obj + + @staticmethod + def deserialize_iso(attr): + """Deserialize ISO-8601 formatted string into Datetime object. + + :param str attr: response string to be deserialized. + :return: Deserialized ISO datetime + :rtype: Datetime + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + attr = attr.upper() # type: ignore + match = Deserializer.valid_date.match(attr) + if not match: + raise ValueError("Invalid datetime string: " + attr) + + check_decimal = attr.split(".") + if len(check_decimal) > 1: + decimal_str = "" + for digit in check_decimal[1]: + if digit.isdigit(): + decimal_str += digit + else: + break + if len(decimal_str) > 6: + attr = attr.replace(decimal_str, decimal_str[0:6]) + + date_obj = isodate.parse_datetime(attr) + test_utc = date_obj.utctimetuple() + if test_utc.tm_year > 9999 or test_utc.tm_year < 1: + raise OverflowError("Hit max or min date") + except (ValueError, OverflowError, AttributeError) as err: + msg = "Cannot deserialize datetime object." + raise DeserializationError(msg) from err + return date_obj + + @staticmethod + def deserialize_unix(attr): + """Serialize Datetime object into IntTime format. + This is represented as seconds. + + :param int attr: Object to be serialized. + :return: Deserialized datetime + :rtype: Datetime + :raises DeserializationError: if format invalid + """ + if isinstance(attr, ET.Element): + attr = int(attr.text) # type: ignore + try: + attr = int(attr) + date_obj = datetime.datetime.fromtimestamp(attr, TZ_UTC) + except ValueError as err: + msg = "Cannot deserialize to unix datetime object." + raise DeserializationError(msg) from err + return date_obj diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/IncorrectErrorResponseVersionTolerant/incorrecterrorresponseversiontolerant/_utils/utils.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/IncorrectErrorResponseVersionTolerant/incorrecterrorresponseversiontolerant/_utils/utils.py new file mode 100644 index 00000000000..39b612f39a9 --- /dev/null +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/IncorrectErrorResponseVersionTolerant/incorrecterrorresponseversiontolerant/_utils/utils.py @@ -0,0 +1,25 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from abc import ABC +from typing import Generic, TYPE_CHECKING, TypeVar + +if TYPE_CHECKING: + from .serialization import Deserializer, Serializer + + +TClient = TypeVar("TClient") +TConfig = TypeVar("TConfig") + + +class ClientMixinABC(ABC, Generic[TClient, TConfig]): + """DO NOT use this class. It is for internal typing use only.""" + + _client: TClient + _config: TConfig + _serialize: "Serializer" + _deserialize: "Deserializer" diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/IncorrectErrorResponseVersionTolerant/incorrecterrorresponseversiontolerant/_vendor.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/IncorrectErrorResponseVersionTolerant/incorrecterrorresponseversiontolerant/_vendor.py deleted file mode 100644 index dc5c02fbead..00000000000 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/IncorrectErrorResponseVersionTolerant/incorrecterrorresponseversiontolerant/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) AutoRest Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import IncorrectReturnedErrorModelConfiguration - -if TYPE_CHECKING: - from azure.core import PipelineClient - - from ._serialization import Deserializer, Serializer - - -class IncorrectReturnedErrorModelMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "PipelineClient" - _config: IncorrectReturnedErrorModelConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/IncorrectErrorResponseVersionTolerant/incorrecterrorresponseversiontolerant/aio/_client.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/IncorrectErrorResponseVersionTolerant/incorrecterrorresponseversiontolerant/aio/_client.py index 4e8cf77d9e6..7009e595ff0 100644 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/IncorrectErrorResponseVersionTolerant/incorrecterrorresponseversiontolerant/aio/_client.py +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/IncorrectErrorResponseVersionTolerant/incorrecterrorresponseversiontolerant/aio/_client.py @@ -14,7 +14,7 @@ from azure.core.pipeline import policies from azure.core.rest import AsyncHttpResponse, HttpRequest -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import IncorrectReturnedErrorModelConfiguration from ._operations import IncorrectReturnedErrorModelOperationsMixin diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/IncorrectErrorResponseVersionTolerant/incorrecterrorresponseversiontolerant/aio/_operations/_operations.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/IncorrectErrorResponseVersionTolerant/incorrecterrorresponseversiontolerant/aio/_operations/_operations.py index afd291e942f..03834d4a31c 100644 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/IncorrectErrorResponseVersionTolerant/incorrecterrorresponseversiontolerant/aio/_operations/_operations.py +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/IncorrectErrorResponseVersionTolerant/incorrecterrorresponseversiontolerant/aio/_operations/_operations.py @@ -9,6 +9,7 @@ from collections.abc import MutableMapping from typing import Any, Callable, Dict, Optional, TypeVar +from azure.core import AsyncPipelineClient from azure.core.exceptions import ( ClientAuthenticationError, HttpResponseError, @@ -22,13 +23,16 @@ from azure.core.tracing.decorator_async import distributed_trace_async from ..._operations._operations import build_incorrect_returned_error_model_get_incorrect_error_from_server_request -from .._vendor import IncorrectReturnedErrorModelMixinABC +from ..._utils.utils import ClientMixinABC +from .._configuration import IncorrectReturnedErrorModelConfiguration T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, AsyncHttpResponse], T, Dict[str, Any]], Any]] -class IncorrectReturnedErrorModelOperationsMixin(IncorrectReturnedErrorModelMixinABC): # pylint: disable=name-too-long +class IncorrectReturnedErrorModelOperationsMixin( # pylint: disable=name-too-long + ClientMixinABC[AsyncPipelineClient, IncorrectReturnedErrorModelConfiguration] +): @distributed_trace_async async def get_incorrect_error_from_server(self, **kwargs: Any) -> None: diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/IncorrectErrorResponseVersionTolerant/incorrecterrorresponseversiontolerant/aio/_vendor.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/IncorrectErrorResponseVersionTolerant/incorrecterrorresponseversiontolerant/aio/_vendor.py deleted file mode 100644 index 5f03a29a82f..00000000000 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/IncorrectErrorResponseVersionTolerant/incorrecterrorresponseversiontolerant/aio/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) AutoRest Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import IncorrectReturnedErrorModelConfiguration - -if TYPE_CHECKING: - from azure.core import AsyncPipelineClient - - from .._serialization import Deserializer, Serializer - - -class IncorrectReturnedErrorModelMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "AsyncPipelineClient" - _config: IncorrectReturnedErrorModelConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/MediaTypesVersionTolerant/mediatypesversiontolerant/_client.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/MediaTypesVersionTolerant/mediatypesversiontolerant/_client.py index 6f9979a68fc..0bb32b4034c 100644 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/MediaTypesVersionTolerant/mediatypesversiontolerant/_client.py +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/MediaTypesVersionTolerant/mediatypesversiontolerant/_client.py @@ -16,7 +16,7 @@ from ._configuration import MediaTypesClientConfiguration from ._operations import MediaTypesClientOperationsMixin -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer class MediaTypesClient(MediaTypesClientOperationsMixin): # pylint: disable=client-accepts-api-version-keyword diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/MediaTypesVersionTolerant/mediatypesversiontolerant/_operations/_operations.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/MediaTypesVersionTolerant/mediatypesversiontolerant/_operations/_operations.py index 37ba3f97f43..869b54867c0 100644 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/MediaTypesVersionTolerant/mediatypesversiontolerant/_operations/_operations.py +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/MediaTypesVersionTolerant/mediatypesversiontolerant/_operations/_operations.py @@ -9,6 +9,7 @@ from io import IOBase from typing import Any, Callable, Dict, IO, Optional, TypeVar, Union, cast, overload +from azure.core import PipelineClient from azure.core.exceptions import ( ClientAuthenticationError, HttpResponseError, @@ -22,8 +23,9 @@ from azure.core.tracing.decorator import distributed_trace from azure.core.utils import case_insensitive_dict -from .._serialization import Serializer -from .._vendor import MediaTypesClientMixinABC, raise_if_not_implemented +from .._configuration import MediaTypesClientConfiguration +from .._utils.serialization import Serializer +from .._utils.utils import ClientMixinABC, raise_if_not_implemented JSON = MutableMapping[str, Any] T = TypeVar("T") @@ -142,7 +144,9 @@ def build_media_types_put_text_and_json_body_request( # pylint: disable=name-to return HttpRequest(method="POST", url=_url, headers=_headers, content=content, **kwargs) -class MediaTypesClientOperationsMixin(MediaTypesClientMixinABC): # pylint: disable=abstract-class-instantiated +class MediaTypesClientOperationsMixin( # pylint: disable=abstract-class-instantiated + ClientMixinABC[PipelineClient, MediaTypesClientConfiguration] +): def __init__(self): raise_if_not_implemented( diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/MediaTypesVersionTolerant/mediatypesversiontolerant/_operations/_patch.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/MediaTypesVersionTolerant/mediatypesversiontolerant/_operations/_patch.py index f4d73b2f362..46c0e405158 100644 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/MediaTypesVersionTolerant/mediatypesversiontolerant/_operations/_patch.py +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/MediaTypesVersionTolerant/mediatypesversiontolerant/_operations/_patch.py @@ -23,7 +23,7 @@ from azure.core.pipeline import PipelineResponse from ._operations import MediaTypesClientOperationsMixin as _MediaTypesClientOperationsMixin -from .._serialization import Serializer +from .._utils.serialization import Serializer _SERIALIZER = Serializer() _SERIALIZER.client_side_validation = False diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/MediaTypesVersionTolerant/mediatypesversiontolerant/_utils/__init__.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/MediaTypesVersionTolerant/mediatypesversiontolerant/_utils/__init__.py new file mode 100644 index 00000000000..0af9b28f660 --- /dev/null +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/MediaTypesVersionTolerant/mediatypesversiontolerant/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/MediaTypesVersionTolerant/mediatypesversiontolerant/_utils/serialization.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/MediaTypesVersionTolerant/mediatypesversiontolerant/_utils/serialization.py new file mode 100644 index 00000000000..f5187701d7b --- /dev/null +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/MediaTypesVersionTolerant/mediatypesversiontolerant/_utils/serialization.py @@ -0,0 +1,2032 @@ +# pylint: disable=line-too-long,useless-suppression,too-many-lines +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +# pyright: reportUnnecessaryTypeIgnoreComment=false + +from base64 import b64decode, b64encode +import calendar +import datetime +import decimal +import email +from enum import Enum +import json +import logging +import re +import sys +import codecs +from typing import ( + Dict, + Any, + cast, + Optional, + Union, + AnyStr, + IO, + Mapping, + Callable, + MutableMapping, + List, +) + +try: + from urllib import quote # type: ignore +except ImportError: + from urllib.parse import quote +import xml.etree.ElementTree as ET + +import isodate # type: ignore +from typing_extensions import Self + +from azure.core.exceptions import DeserializationError, SerializationError +from azure.core.serialization import NULL as CoreNull + +_BOM = codecs.BOM_UTF8.decode(encoding="utf-8") + +JSON = MutableMapping[str, Any] + + +class RawDeserializer: + + # Accept "text" because we're open minded people... + JSON_REGEXP = re.compile(r"^(application|text)/([a-z+.]+\+)?json$") + + # Name used in context + CONTEXT_NAME = "deserialized_data" + + @classmethod + def deserialize_from_text(cls, data: Optional[Union[AnyStr, IO]], content_type: Optional[str] = None) -> Any: + """Decode data according to content-type. + + Accept a stream of data as well, but will be load at once in memory for now. + + If no content-type, will return the string version (not bytes, not stream) + + :param data: Input, could be bytes or stream (will be decoded with UTF8) or text + :type data: str or bytes or IO + :param str content_type: The content type. + :return: The deserialized data. + :rtype: object + """ + if hasattr(data, "read"): + # Assume a stream + data = cast(IO, data).read() + + if isinstance(data, bytes): + data_as_str = data.decode(encoding="utf-8-sig") + else: + # Explain to mypy the correct type. + data_as_str = cast(str, data) + + # Remove Byte Order Mark if present in string + data_as_str = data_as_str.lstrip(_BOM) + + if content_type is None: + return data + + if cls.JSON_REGEXP.match(content_type): + try: + return json.loads(data_as_str) + except ValueError as err: + raise DeserializationError("JSON is invalid: {}".format(err), err) from err + elif "xml" in (content_type or []): + try: + + try: + if isinstance(data, unicode): # type: ignore + # If I'm Python 2.7 and unicode XML will scream if I try a "fromstring" on unicode string + data_as_str = data_as_str.encode(encoding="utf-8") # type: ignore + except NameError: + pass + + return ET.fromstring(data_as_str) # nosec + except ET.ParseError as err: + # It might be because the server has an issue, and returned JSON with + # content-type XML.... + # So let's try a JSON load, and if it's still broken + # let's flow the initial exception + def _json_attemp(data): + try: + return True, json.loads(data) + except ValueError: + return False, None # Don't care about this one + + success, json_result = _json_attemp(data) + if success: + return json_result + # If i'm here, it's not JSON, it's not XML, let's scream + # and raise the last context in this block (the XML exception) + # The function hack is because Py2.7 messes up with exception + # context otherwise. + _LOGGER.critical("Wasn't XML not JSON, failing") + raise DeserializationError("XML is invalid") from err + elif content_type.startswith("text/"): + return data_as_str + raise DeserializationError("Cannot deserialize content-type: {}".format(content_type)) + + @classmethod + def deserialize_from_http_generics(cls, body_bytes: Optional[Union[AnyStr, IO]], headers: Mapping) -> Any: + """Deserialize from HTTP response. + + Use bytes and headers to NOT use any requests/aiohttp or whatever + specific implementation. + Headers will tested for "content-type" + + :param bytes body_bytes: The body of the response. + :param dict headers: The headers of the response. + :returns: The deserialized data. + :rtype: object + """ + # Try to use content-type from headers if available + content_type = None + if "content-type" in headers: + content_type = headers["content-type"].split(";")[0].strip().lower() + # Ouch, this server did not declare what it sent... + # Let's guess it's JSON... + # Also, since Autorest was considering that an empty body was a valid JSON, + # need that test as well.... + else: + content_type = "application/json" + + if body_bytes: + return cls.deserialize_from_text(body_bytes, content_type) + return None + + +_LOGGER = logging.getLogger(__name__) + +try: + _long_type = long # type: ignore +except NameError: + _long_type = int + +TZ_UTC = datetime.timezone.utc + +_FLATTEN = re.compile(r"(? None: + self.additional_properties: Optional[Dict[str, Any]] = {} + for k in kwargs: # pylint: disable=consider-using-dict-items + if k not in self._attribute_map: + _LOGGER.warning("%s is not a known attribute of class %s and will be ignored", k, self.__class__) + elif k in self._validation and self._validation[k].get("readonly", False): + _LOGGER.warning("Readonly attribute %s will be ignored in class %s", k, self.__class__) + else: + setattr(self, k, kwargs[k]) + + def __eq__(self, other: Any) -> bool: + """Compare objects by comparing all attributes. + + :param object other: The object to compare + :returns: True if objects are equal + :rtype: bool + """ + if isinstance(other, self.__class__): + return self.__dict__ == other.__dict__ + return False + + def __ne__(self, other: Any) -> bool: + """Compare objects by comparing all attributes. + + :param object other: The object to compare + :returns: True if objects are not equal + :rtype: bool + """ + return not self.__eq__(other) + + def __str__(self) -> str: + return str(self.__dict__) + + @classmethod + def enable_additional_properties_sending(cls) -> None: + cls._attribute_map["additional_properties"] = {"key": "", "type": "{object}"} + + @classmethod + def is_xml_model(cls) -> bool: + try: + cls._xml_map # type: ignore + except AttributeError: + return False + return True + + @classmethod + def _create_xml_node(cls): + """Create XML node. + + :returns: The XML node + :rtype: xml.etree.ElementTree.Element + """ + try: + xml_map = cls._xml_map # type: ignore + except AttributeError: + xml_map = {} + + return _create_xml_node(xml_map.get("name", cls.__name__), xml_map.get("prefix", None), xml_map.get("ns", None)) + + def serialize(self, keep_readonly: bool = False, **kwargs: Any) -> JSON: + """Return the JSON that would be sent to server from this model. + + This is an alias to `as_dict(full_restapi_key_transformer, keep_readonly=False)`. + + If you want XML serialization, you can pass the kwargs is_xml=True. + + :param bool keep_readonly: If you want to serialize the readonly attributes + :returns: A dict JSON compatible object + :rtype: dict + """ + serializer = Serializer(self._infer_class_models()) + return serializer._serialize( # type: ignore # pylint: disable=protected-access + self, keep_readonly=keep_readonly, **kwargs + ) + + def as_dict( + self, + keep_readonly: bool = True, + key_transformer: Callable[[str, Dict[str, Any], Any], Any] = attribute_transformer, + **kwargs: Any + ) -> JSON: + """Return a dict that can be serialized using json.dump. + + Advanced usage might optionally use a callback as parameter: + + .. code::python + + def my_key_transformer(key, attr_desc, value): + return key + + Key is the attribute name used in Python. Attr_desc + is a dict of metadata. Currently contains 'type' with the + msrest type and 'key' with the RestAPI encoded key. + Value is the current value in this object. + + The string returned will be used to serialize the key. + If the return type is a list, this is considered hierarchical + result dict. + + See the three examples in this file: + + - attribute_transformer + - full_restapi_key_transformer + - last_restapi_key_transformer + + If you want XML serialization, you can pass the kwargs is_xml=True. + + :param bool keep_readonly: If you want to serialize the readonly attributes + :param function key_transformer: A key transformer function. + :returns: A dict JSON compatible object + :rtype: dict + """ + serializer = Serializer(self._infer_class_models()) + return serializer._serialize( # type: ignore # pylint: disable=protected-access + self, key_transformer=key_transformer, keep_readonly=keep_readonly, **kwargs + ) + + @classmethod + def _infer_class_models(cls): + try: + str_models = cls.__module__.rsplit(".", 1)[0] + models = sys.modules[str_models] + client_models = {k: v for k, v in models.__dict__.items() if isinstance(v, type)} + if cls.__name__ not in client_models: + raise ValueError("Not Autorest generated code") + except Exception: # pylint: disable=broad-exception-caught + # Assume it's not Autorest generated (tests?). Add ourselves as dependencies. + client_models = {cls.__name__: cls} + return client_models + + @classmethod + def deserialize(cls, data: Any, content_type: Optional[str] = None) -> Self: + """Parse a str using the RestAPI syntax and return a model. + + :param str data: A str using RestAPI structure. JSON by default. + :param str content_type: JSON by default, set application/xml if XML. + :returns: An instance of this model + :raises DeserializationError: if something went wrong + :rtype: Self + """ + deserializer = Deserializer(cls._infer_class_models()) + return deserializer(cls.__name__, data, content_type=content_type) # type: ignore + + @classmethod + def from_dict( + cls, + data: Any, + key_extractors: Optional[Callable[[str, Dict[str, Any], Any], Any]] = None, + content_type: Optional[str] = None, + ) -> Self: + """Parse a dict using given key extractor return a model. + + By default consider key + extractors (rest_key_case_insensitive_extractor, attribute_key_case_insensitive_extractor + and last_rest_key_case_insensitive_extractor) + + :param dict data: A dict using RestAPI structure + :param function key_extractors: A key extractor function. + :param str content_type: JSON by default, set application/xml if XML. + :returns: An instance of this model + :raises DeserializationError: if something went wrong + :rtype: Self + """ + deserializer = Deserializer(cls._infer_class_models()) + deserializer.key_extractors = ( # type: ignore + [ # type: ignore + attribute_key_case_insensitive_extractor, + rest_key_case_insensitive_extractor, + last_rest_key_case_insensitive_extractor, + ] + if key_extractors is None + else key_extractors + ) + return deserializer(cls.__name__, data, content_type=content_type) # type: ignore + + @classmethod + def _flatten_subtype(cls, key, objects): + if "_subtype_map" not in cls.__dict__: + return {} + result = dict(cls._subtype_map[key]) + for valuetype in cls._subtype_map[key].values(): + result.update(objects[valuetype]._flatten_subtype(key, objects)) # pylint: disable=protected-access + return result + + @classmethod + def _classify(cls, response, objects): + """Check the class _subtype_map for any child classes. + We want to ignore any inherited _subtype_maps. + + :param dict response: The initial data + :param dict objects: The class objects + :returns: The class to be used + :rtype: class + """ + for subtype_key in cls.__dict__.get("_subtype_map", {}).keys(): + subtype_value = None + + if not isinstance(response, ET.Element): + rest_api_response_key = cls._get_rest_key_parts(subtype_key)[-1] + subtype_value = response.get(rest_api_response_key, None) or response.get(subtype_key, None) + else: + subtype_value = xml_key_extractor(subtype_key, cls._attribute_map[subtype_key], response) + if subtype_value: + # Try to match base class. Can be class name only + # (bug to fix in Autorest to support x-ms-discriminator-name) + if cls.__name__ == subtype_value: + return cls + flatten_mapping_type = cls._flatten_subtype(subtype_key, objects) + try: + return objects[flatten_mapping_type[subtype_value]] # type: ignore + except KeyError: + _LOGGER.warning( + "Subtype value %s has no mapping, use base class %s.", + subtype_value, + cls.__name__, + ) + break + else: + _LOGGER.warning("Discriminator %s is absent or null, use base class %s.", subtype_key, cls.__name__) + break + return cls + + @classmethod + def _get_rest_key_parts(cls, attr_key): + """Get the RestAPI key of this attr, split it and decode part + :param str attr_key: Attribute key must be in attribute_map. + :returns: A list of RestAPI part + :rtype: list + """ + rest_split_key = _FLATTEN.split(cls._attribute_map[attr_key]["key"]) + return [_decode_attribute_map_key(key_part) for key_part in rest_split_key] + + +def _decode_attribute_map_key(key): + """This decode a key in an _attribute_map to the actual key we want to look at + inside the received data. + + :param str key: A key string from the generated code + :returns: The decoded key + :rtype: str + """ + return key.replace("\\.", ".") + + +class Serializer: # pylint: disable=too-many-public-methods + """Request object model serializer.""" + + basic_types = {str: "str", int: "int", bool: "bool", float: "float"} + + _xml_basic_types_serializers = {"bool": lambda x: str(x).lower()} + days = {0: "Mon", 1: "Tue", 2: "Wed", 3: "Thu", 4: "Fri", 5: "Sat", 6: "Sun"} + months = { + 1: "Jan", + 2: "Feb", + 3: "Mar", + 4: "Apr", + 5: "May", + 6: "Jun", + 7: "Jul", + 8: "Aug", + 9: "Sep", + 10: "Oct", + 11: "Nov", + 12: "Dec", + } + validation = { + "min_length": lambda x, y: len(x) < y, + "max_length": lambda x, y: len(x) > y, + "minimum": lambda x, y: x < y, + "maximum": lambda x, y: x > y, + "minimum_ex": lambda x, y: x <= y, + "maximum_ex": lambda x, y: x >= y, + "min_items": lambda x, y: len(x) < y, + "max_items": lambda x, y: len(x) > y, + "pattern": lambda x, y: not re.match(y, x, re.UNICODE), + "unique": lambda x, y: len(x) != len(set(x)), + "multiple": lambda x, y: x % y != 0, + } + + def __init__(self, classes: Optional[Mapping[str, type]] = None) -> None: + self.serialize_type = { + "iso-8601": Serializer.serialize_iso, + "rfc-1123": Serializer.serialize_rfc, + "unix-time": Serializer.serialize_unix, + "duration": Serializer.serialize_duration, + "date": Serializer.serialize_date, + "time": Serializer.serialize_time, + "decimal": Serializer.serialize_decimal, + "long": Serializer.serialize_long, + "bytearray": Serializer.serialize_bytearray, + "base64": Serializer.serialize_base64, + "object": self.serialize_object, + "[]": self.serialize_iter, + "{}": self.serialize_dict, + } + self.dependencies: Dict[str, type] = dict(classes) if classes else {} + self.key_transformer = full_restapi_key_transformer + self.client_side_validation = True + + def _serialize( # pylint: disable=too-many-nested-blocks, too-many-branches, too-many-statements, too-many-locals + self, target_obj, data_type=None, **kwargs + ): + """Serialize data into a string according to type. + + :param object target_obj: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str, dict + :raises SerializationError: if serialization fails. + :returns: The serialized data. + """ + key_transformer = kwargs.get("key_transformer", self.key_transformer) + keep_readonly = kwargs.get("keep_readonly", False) + if target_obj is None: + return None + + attr_name = None + class_name = target_obj.__class__.__name__ + + if data_type: + return self.serialize_data(target_obj, data_type, **kwargs) + + if not hasattr(target_obj, "_attribute_map"): + data_type = type(target_obj).__name__ + if data_type in self.basic_types.values(): + return self.serialize_data(target_obj, data_type, **kwargs) + + # Force "is_xml" kwargs if we detect a XML model + try: + is_xml_model_serialization = kwargs["is_xml"] + except KeyError: + is_xml_model_serialization = kwargs.setdefault("is_xml", target_obj.is_xml_model()) + + serialized = {} + if is_xml_model_serialization: + serialized = target_obj._create_xml_node() # pylint: disable=protected-access + try: + attributes = target_obj._attribute_map # pylint: disable=protected-access + for attr, attr_desc in attributes.items(): + attr_name = attr + if not keep_readonly and target_obj._validation.get( # pylint: disable=protected-access + attr_name, {} + ).get("readonly", False): + continue + + if attr_name == "additional_properties" and attr_desc["key"] == "": + if target_obj.additional_properties is not None: + serialized.update(target_obj.additional_properties) + continue + try: + + orig_attr = getattr(target_obj, attr) + if is_xml_model_serialization: + pass # Don't provide "transformer" for XML for now. Keep "orig_attr" + else: # JSON + keys, orig_attr = key_transformer(attr, attr_desc.copy(), orig_attr) + keys = keys if isinstance(keys, list) else [keys] + + kwargs["serialization_ctxt"] = attr_desc + new_attr = self.serialize_data(orig_attr, attr_desc["type"], **kwargs) + + if is_xml_model_serialization: + xml_desc = attr_desc.get("xml", {}) + xml_name = xml_desc.get("name", attr_desc["key"]) + xml_prefix = xml_desc.get("prefix", None) + xml_ns = xml_desc.get("ns", None) + if xml_desc.get("attr", False): + if xml_ns: + ET.register_namespace(xml_prefix, xml_ns) + xml_name = "{{{}}}{}".format(xml_ns, xml_name) + serialized.set(xml_name, new_attr) # type: ignore + continue + if xml_desc.get("text", False): + serialized.text = new_attr # type: ignore + continue + if isinstance(new_attr, list): + serialized.extend(new_attr) # type: ignore + elif isinstance(new_attr, ET.Element): + # If the down XML has no XML/Name, + # we MUST replace the tag with the local tag. But keeping the namespaces. + if "name" not in getattr(orig_attr, "_xml_map", {}): + splitted_tag = new_attr.tag.split("}") + if len(splitted_tag) == 2: # Namespace + new_attr.tag = "}".join([splitted_tag[0], xml_name]) + else: + new_attr.tag = xml_name + serialized.append(new_attr) # type: ignore + else: # That's a basic type + # Integrate namespace if necessary + local_node = _create_xml_node(xml_name, xml_prefix, xml_ns) + local_node.text = str(new_attr) + serialized.append(local_node) # type: ignore + else: # JSON + for k in reversed(keys): # type: ignore + new_attr = {k: new_attr} + + _new_attr = new_attr + _serialized = serialized + for k in keys: # type: ignore + if k not in _serialized: + _serialized.update(_new_attr) # type: ignore + _new_attr = _new_attr[k] # type: ignore + _serialized = _serialized[k] + except ValueError as err: + if isinstance(err, SerializationError): + raise + + except (AttributeError, KeyError, TypeError) as err: + msg = "Attribute {} in object {} cannot be serialized.\n{}".format(attr_name, class_name, str(target_obj)) + raise SerializationError(msg) from err + return serialized + + def body(self, data, data_type, **kwargs): + """Serialize data intended for a request body. + + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: dict + :raises SerializationError: if serialization fails. + :raises ValueError: if data is None + :returns: The serialized request body + """ + + # Just in case this is a dict + internal_data_type_str = data_type.strip("[]{}") + internal_data_type = self.dependencies.get(internal_data_type_str, None) + try: + is_xml_model_serialization = kwargs["is_xml"] + except KeyError: + if internal_data_type and issubclass(internal_data_type, Model): + is_xml_model_serialization = kwargs.setdefault("is_xml", internal_data_type.is_xml_model()) + else: + is_xml_model_serialization = False + if internal_data_type and not isinstance(internal_data_type, Enum): + try: + deserializer = Deserializer(self.dependencies) + # Since it's on serialization, it's almost sure that format is not JSON REST + # We're not able to deal with additional properties for now. + deserializer.additional_properties_detection = False + if is_xml_model_serialization: + deserializer.key_extractors = [ # type: ignore + attribute_key_case_insensitive_extractor, + ] + else: + deserializer.key_extractors = [ + rest_key_case_insensitive_extractor, + attribute_key_case_insensitive_extractor, + last_rest_key_case_insensitive_extractor, + ] + data = deserializer._deserialize(data_type, data) # pylint: disable=protected-access + except DeserializationError as err: + raise SerializationError("Unable to build a model: " + str(err)) from err + + return self._serialize(data, data_type, **kwargs) + + def url(self, name, data, data_type, **kwargs): + """Serialize data intended for a URL path. + + :param str name: The name of the URL path parameter. + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str + :returns: The serialized URL path + :raises TypeError: if serialization fails. + :raises ValueError: if data is None + """ + try: + output = self.serialize_data(data, data_type, **kwargs) + if data_type == "bool": + output = json.dumps(output) + + if kwargs.get("skip_quote") is True: + output = str(output) + output = output.replace("{", quote("{")).replace("}", quote("}")) + else: + output = quote(str(output), safe="") + except SerializationError as exc: + raise TypeError("{} must be type {}.".format(name, data_type)) from exc + return output + + def query(self, name, data, data_type, **kwargs): + """Serialize data intended for a URL query. + + :param str name: The name of the query parameter. + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str, list + :raises TypeError: if serialization fails. + :raises ValueError: if data is None + :returns: The serialized query parameter + """ + try: + # Treat the list aside, since we don't want to encode the div separator + if data_type.startswith("["): + internal_data_type = data_type[1:-1] + do_quote = not kwargs.get("skip_quote", False) + return self.serialize_iter(data, internal_data_type, do_quote=do_quote, **kwargs) + + # Not a list, regular serialization + output = self.serialize_data(data, data_type, **kwargs) + if data_type == "bool": + output = json.dumps(output) + if kwargs.get("skip_quote") is True: + output = str(output) + else: + output = quote(str(output), safe="") + except SerializationError as exc: + raise TypeError("{} must be type {}.".format(name, data_type)) from exc + return str(output) + + def header(self, name, data, data_type, **kwargs): + """Serialize data intended for a request header. + + :param str name: The name of the header. + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str + :raises TypeError: if serialization fails. + :raises ValueError: if data is None + :returns: The serialized header + """ + try: + if data_type in ["[str]"]: + data = ["" if d is None else d for d in data] + + output = self.serialize_data(data, data_type, **kwargs) + if data_type == "bool": + output = json.dumps(output) + except SerializationError as exc: + raise TypeError("{} must be type {}.".format(name, data_type)) from exc + return str(output) + + def serialize_data(self, data, data_type, **kwargs): + """Serialize generic data according to supplied data type. + + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :raises AttributeError: if required data is None. + :raises ValueError: if data is None + :raises SerializationError: if serialization fails. + :returns: The serialized data. + :rtype: str, int, float, bool, dict, list + """ + if data is None: + raise ValueError("No value for given attribute") + + try: + if data is CoreNull: + return None + if data_type in self.basic_types.values(): + return self.serialize_basic(data, data_type, **kwargs) + + if data_type in self.serialize_type: + return self.serialize_type[data_type](data, **kwargs) + + # If dependencies is empty, try with current data class + # It has to be a subclass of Enum anyway + enum_type = self.dependencies.get(data_type, data.__class__) + if issubclass(enum_type, Enum): + return Serializer.serialize_enum(data, enum_obj=enum_type) + + iter_type = data_type[0] + data_type[-1] + if iter_type in self.serialize_type: + return self.serialize_type[iter_type](data, data_type[1:-1], **kwargs) + + except (ValueError, TypeError) as err: + msg = "Unable to serialize value: {!r} as type: {!r}." + raise SerializationError(msg.format(data, data_type)) from err + return self._serialize(data, **kwargs) + + @classmethod + def _get_custom_serializers(cls, data_type, **kwargs): # pylint: disable=inconsistent-return-statements + custom_serializer = kwargs.get("basic_types_serializers", {}).get(data_type) + if custom_serializer: + return custom_serializer + if kwargs.get("is_xml", False): + return cls._xml_basic_types_serializers.get(data_type) + + @classmethod + def serialize_basic(cls, data, data_type, **kwargs): + """Serialize basic builting data type. + Serializes objects to str, int, float or bool. + + Possible kwargs: + - basic_types_serializers dict[str, callable] : If set, use the callable as serializer + - is_xml bool : If set, use xml_basic_types_serializers + + :param obj data: Object to be serialized. + :param str data_type: Type of object in the iterable. + :rtype: str, int, float, bool + :return: serialized object + """ + custom_serializer = cls._get_custom_serializers(data_type, **kwargs) + if custom_serializer: + return custom_serializer(data) + if data_type == "str": + return cls.serialize_unicode(data) + return eval(data_type)(data) # nosec # pylint: disable=eval-used + + @classmethod + def serialize_unicode(cls, data): + """Special handling for serializing unicode strings in Py2. + Encode to UTF-8 if unicode, otherwise handle as a str. + + :param str data: Object to be serialized. + :rtype: str + :return: serialized object + """ + try: # If I received an enum, return its value + return data.value + except AttributeError: + pass + + try: + if isinstance(data, unicode): # type: ignore + # Don't change it, JSON and XML ElementTree are totally able + # to serialize correctly u'' strings + return data + except NameError: + return str(data) + return str(data) + + def serialize_iter(self, data, iter_type, div=None, **kwargs): + """Serialize iterable. + + Supported kwargs: + - serialization_ctxt dict : The current entry of _attribute_map, or same format. + serialization_ctxt['type'] should be same as data_type. + - is_xml bool : If set, serialize as XML + + :param list data: Object to be serialized. + :param str iter_type: Type of object in the iterable. + :param str div: If set, this str will be used to combine the elements + in the iterable into a combined string. Default is 'None'. + Defaults to False. + :rtype: list, str + :return: serialized iterable + """ + if isinstance(data, str): + raise SerializationError("Refuse str type as a valid iter type.") + + serialization_ctxt = kwargs.get("serialization_ctxt", {}) + is_xml = kwargs.get("is_xml", False) + + serialized = [] + for d in data: + try: + serialized.append(self.serialize_data(d, iter_type, **kwargs)) + except ValueError as err: + if isinstance(err, SerializationError): + raise + serialized.append(None) + + if kwargs.get("do_quote", False): + serialized = ["" if s is None else quote(str(s), safe="") for s in serialized] + + if div: + serialized = ["" if s is None else str(s) for s in serialized] + serialized = div.join(serialized) + + if "xml" in serialization_ctxt or is_xml: + # XML serialization is more complicated + xml_desc = serialization_ctxt.get("xml", {}) + xml_name = xml_desc.get("name") + if not xml_name: + xml_name = serialization_ctxt["key"] + + # Create a wrap node if necessary (use the fact that Element and list have "append") + is_wrapped = xml_desc.get("wrapped", False) + node_name = xml_desc.get("itemsName", xml_name) + if is_wrapped: + final_result = _create_xml_node(xml_name, xml_desc.get("prefix", None), xml_desc.get("ns", None)) + else: + final_result = [] + # All list elements to "local_node" + for el in serialized: + if isinstance(el, ET.Element): + el_node = el + else: + el_node = _create_xml_node(node_name, xml_desc.get("prefix", None), xml_desc.get("ns", None)) + if el is not None: # Otherwise it writes "None" :-p + el_node.text = str(el) + final_result.append(el_node) + return final_result + return serialized + + def serialize_dict(self, attr, dict_type, **kwargs): + """Serialize a dictionary of objects. + + :param dict attr: Object to be serialized. + :param str dict_type: Type of object in the dictionary. + :rtype: dict + :return: serialized dictionary + """ + serialization_ctxt = kwargs.get("serialization_ctxt", {}) + serialized = {} + for key, value in attr.items(): + try: + serialized[self.serialize_unicode(key)] = self.serialize_data(value, dict_type, **kwargs) + except ValueError as err: + if isinstance(err, SerializationError): + raise + serialized[self.serialize_unicode(key)] = None + + if "xml" in serialization_ctxt: + # XML serialization is more complicated + xml_desc = serialization_ctxt["xml"] + xml_name = xml_desc["name"] + + final_result = _create_xml_node(xml_name, xml_desc.get("prefix", None), xml_desc.get("ns", None)) + for key, value in serialized.items(): + ET.SubElement(final_result, key).text = value + return final_result + + return serialized + + def serialize_object(self, attr, **kwargs): # pylint: disable=too-many-return-statements + """Serialize a generic object. + This will be handled as a dictionary. If object passed in is not + a basic type (str, int, float, dict, list) it will simply be + cast to str. + + :param dict attr: Object to be serialized. + :rtype: dict or str + :return: serialized object + """ + if attr is None: + return None + if isinstance(attr, ET.Element): + return attr + obj_type = type(attr) + if obj_type in self.basic_types: + return self.serialize_basic(attr, self.basic_types[obj_type], **kwargs) + if obj_type is _long_type: + return self.serialize_long(attr) + if obj_type is str: + return self.serialize_unicode(attr) + if obj_type is datetime.datetime: + return self.serialize_iso(attr) + if obj_type is datetime.date: + return self.serialize_date(attr) + if obj_type is datetime.time: + return self.serialize_time(attr) + if obj_type is datetime.timedelta: + return self.serialize_duration(attr) + if obj_type is decimal.Decimal: + return self.serialize_decimal(attr) + + # If it's a model or I know this dependency, serialize as a Model + if obj_type in self.dependencies.values() or isinstance(attr, Model): + return self._serialize(attr) + + if obj_type == dict: + serialized = {} + for key, value in attr.items(): + try: + serialized[self.serialize_unicode(key)] = self.serialize_object(value, **kwargs) + except ValueError: + serialized[self.serialize_unicode(key)] = None + return serialized + + if obj_type == list: + serialized = [] + for obj in attr: + try: + serialized.append(self.serialize_object(obj, **kwargs)) + except ValueError: + pass + return serialized + return str(attr) + + @staticmethod + def serialize_enum(attr, enum_obj=None): + try: + result = attr.value + except AttributeError: + result = attr + try: + enum_obj(result) # type: ignore + return result + except ValueError as exc: + for enum_value in enum_obj: # type: ignore + if enum_value.value.lower() == str(attr).lower(): + return enum_value.value + error = "{!r} is not valid value for enum {!r}" + raise SerializationError(error.format(attr, enum_obj)) from exc + + @staticmethod + def serialize_bytearray(attr, **kwargs): # pylint: disable=unused-argument + """Serialize bytearray into base-64 string. + + :param str attr: Object to be serialized. + :rtype: str + :return: serialized base64 + """ + return b64encode(attr).decode() + + @staticmethod + def serialize_base64(attr, **kwargs): # pylint: disable=unused-argument + """Serialize str into base-64 string. + + :param str attr: Object to be serialized. + :rtype: str + :return: serialized base64 + """ + encoded = b64encode(attr).decode("ascii") + return encoded.strip("=").replace("+", "-").replace("/", "_") + + @staticmethod + def serialize_decimal(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Decimal object to float. + + :param decimal attr: Object to be serialized. + :rtype: float + :return: serialized decimal + """ + return float(attr) + + @staticmethod + def serialize_long(attr, **kwargs): # pylint: disable=unused-argument + """Serialize long (Py2) or int (Py3). + + :param int attr: Object to be serialized. + :rtype: int/long + :return: serialized long + """ + return _long_type(attr) + + @staticmethod + def serialize_date(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Date object into ISO-8601 formatted string. + + :param Date attr: Object to be serialized. + :rtype: str + :return: serialized date + """ + if isinstance(attr, str): + attr = isodate.parse_date(attr) + t = "{:04}-{:02}-{:02}".format(attr.year, attr.month, attr.day) + return t + + @staticmethod + def serialize_time(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Time object into ISO-8601 formatted string. + + :param datetime.time attr: Object to be serialized. + :rtype: str + :return: serialized time + """ + if isinstance(attr, str): + attr = isodate.parse_time(attr) + t = "{:02}:{:02}:{:02}".format(attr.hour, attr.minute, attr.second) + if attr.microsecond: + t += ".{:02}".format(attr.microsecond) + return t + + @staticmethod + def serialize_duration(attr, **kwargs): # pylint: disable=unused-argument + """Serialize TimeDelta object into ISO-8601 formatted string. + + :param TimeDelta attr: Object to be serialized. + :rtype: str + :return: serialized duration + """ + if isinstance(attr, str): + attr = isodate.parse_duration(attr) + return isodate.duration_isoformat(attr) + + @staticmethod + def serialize_rfc(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Datetime object into RFC-1123 formatted string. + + :param Datetime attr: Object to be serialized. + :rtype: str + :raises TypeError: if format invalid. + :return: serialized rfc + """ + try: + if not attr.tzinfo: + _LOGGER.warning("Datetime with no tzinfo will be considered UTC.") + utc = attr.utctimetuple() + except AttributeError as exc: + raise TypeError("RFC1123 object must be valid Datetime object.") from exc + + return "{}, {:02} {} {:04} {:02}:{:02}:{:02} GMT".format( + Serializer.days[utc.tm_wday], + utc.tm_mday, + Serializer.months[utc.tm_mon], + utc.tm_year, + utc.tm_hour, + utc.tm_min, + utc.tm_sec, + ) + + @staticmethod + def serialize_iso(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Datetime object into ISO-8601 formatted string. + + :param Datetime attr: Object to be serialized. + :rtype: str + :raises SerializationError: if format invalid. + :return: serialized iso + """ + if isinstance(attr, str): + attr = isodate.parse_datetime(attr) + try: + if not attr.tzinfo: + _LOGGER.warning("Datetime with no tzinfo will be considered UTC.") + utc = attr.utctimetuple() + if utc.tm_year > 9999 or utc.tm_year < 1: + raise OverflowError("Hit max or min date") + + microseconds = str(attr.microsecond).rjust(6, "0").rstrip("0").ljust(3, "0") + if microseconds: + microseconds = "." + microseconds + date = "{:04}-{:02}-{:02}T{:02}:{:02}:{:02}".format( + utc.tm_year, utc.tm_mon, utc.tm_mday, utc.tm_hour, utc.tm_min, utc.tm_sec + ) + return date + microseconds + "Z" + except (ValueError, OverflowError) as err: + msg = "Unable to serialize datetime object." + raise SerializationError(msg) from err + except AttributeError as err: + msg = "ISO-8601 object must be valid Datetime object." + raise TypeError(msg) from err + + @staticmethod + def serialize_unix(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Datetime object into IntTime format. + This is represented as seconds. + + :param Datetime attr: Object to be serialized. + :rtype: int + :raises SerializationError: if format invalid + :return: serialied unix + """ + if isinstance(attr, int): + return attr + try: + if not attr.tzinfo: + _LOGGER.warning("Datetime with no tzinfo will be considered UTC.") + return int(calendar.timegm(attr.utctimetuple())) + except AttributeError as exc: + raise TypeError("Unix time object must be valid Datetime object.") from exc + + +def rest_key_extractor(attr, attr_desc, data): # pylint: disable=unused-argument + key = attr_desc["key"] + working_data = data + + while "." in key: + # Need the cast, as for some reasons "split" is typed as list[str | Any] + dict_keys = cast(List[str], _FLATTEN.split(key)) + if len(dict_keys) == 1: + key = _decode_attribute_map_key(dict_keys[0]) + break + working_key = _decode_attribute_map_key(dict_keys[0]) + working_data = working_data.get(working_key, data) + if working_data is None: + # If at any point while following flatten JSON path see None, it means + # that all properties under are None as well + return None + key = ".".join(dict_keys[1:]) + + return working_data.get(key) + + +def rest_key_case_insensitive_extractor( # pylint: disable=unused-argument, inconsistent-return-statements + attr, attr_desc, data +): + key = attr_desc["key"] + working_data = data + + while "." in key: + dict_keys = _FLATTEN.split(key) + if len(dict_keys) == 1: + key = _decode_attribute_map_key(dict_keys[0]) + break + working_key = _decode_attribute_map_key(dict_keys[0]) + working_data = attribute_key_case_insensitive_extractor(working_key, None, working_data) + if working_data is None: + # If at any point while following flatten JSON path see None, it means + # that all properties under are None as well + return None + key = ".".join(dict_keys[1:]) + + if working_data: + return attribute_key_case_insensitive_extractor(key, None, working_data) + + +def last_rest_key_extractor(attr, attr_desc, data): # pylint: disable=unused-argument + """Extract the attribute in "data" based on the last part of the JSON path key. + + :param str attr: The attribute to extract + :param dict attr_desc: The attribute description + :param dict data: The data to extract from + :rtype: object + :returns: The extracted attribute + """ + key = attr_desc["key"] + dict_keys = _FLATTEN.split(key) + return attribute_key_extractor(dict_keys[-1], None, data) + + +def last_rest_key_case_insensitive_extractor(attr, attr_desc, data): # pylint: disable=unused-argument + """Extract the attribute in "data" based on the last part of the JSON path key. + + This is the case insensitive version of "last_rest_key_extractor" + :param str attr: The attribute to extract + :param dict attr_desc: The attribute description + :param dict data: The data to extract from + :rtype: object + :returns: The extracted attribute + """ + key = attr_desc["key"] + dict_keys = _FLATTEN.split(key) + return attribute_key_case_insensitive_extractor(dict_keys[-1], None, data) + + +def attribute_key_extractor(attr, _, data): + return data.get(attr) + + +def attribute_key_case_insensitive_extractor(attr, _, data): + found_key = None + lower_attr = attr.lower() + for key in data: + if lower_attr == key.lower(): + found_key = key + break + + return data.get(found_key) + + +def _extract_name_from_internal_type(internal_type): + """Given an internal type XML description, extract correct XML name with namespace. + + :param dict internal_type: An model type + :rtype: tuple + :returns: A tuple XML name + namespace dict + """ + internal_type_xml_map = getattr(internal_type, "_xml_map", {}) + xml_name = internal_type_xml_map.get("name", internal_type.__name__) + xml_ns = internal_type_xml_map.get("ns", None) + if xml_ns: + xml_name = "{{{}}}{}".format(xml_ns, xml_name) + return xml_name + + +def xml_key_extractor(attr, attr_desc, data): # pylint: disable=unused-argument,too-many-return-statements + if isinstance(data, dict): + return None + + # Test if this model is XML ready first + if not isinstance(data, ET.Element): + return None + + xml_desc = attr_desc.get("xml", {}) + xml_name = xml_desc.get("name", attr_desc["key"]) + + # Look for a children + is_iter_type = attr_desc["type"].startswith("[") + is_wrapped = xml_desc.get("wrapped", False) + internal_type = attr_desc.get("internalType", None) + internal_type_xml_map = getattr(internal_type, "_xml_map", {}) + + # Integrate namespace if necessary + xml_ns = xml_desc.get("ns", internal_type_xml_map.get("ns", None)) + if xml_ns: + xml_name = "{{{}}}{}".format(xml_ns, xml_name) + + # If it's an attribute, that's simple + if xml_desc.get("attr", False): + return data.get(xml_name) + + # If it's x-ms-text, that's simple too + if xml_desc.get("text", False): + return data.text + + # Scenario where I take the local name: + # - Wrapped node + # - Internal type is an enum (considered basic types) + # - Internal type has no XML/Name node + if is_wrapped or (internal_type and (issubclass(internal_type, Enum) or "name" not in internal_type_xml_map)): + children = data.findall(xml_name) + # If internal type has a local name and it's not a list, I use that name + elif not is_iter_type and internal_type and "name" in internal_type_xml_map: + xml_name = _extract_name_from_internal_type(internal_type) + children = data.findall(xml_name) + # That's an array + else: + if internal_type: # Complex type, ignore itemsName and use the complex type name + items_name = _extract_name_from_internal_type(internal_type) + else: + items_name = xml_desc.get("itemsName", xml_name) + children = data.findall(items_name) + + if len(children) == 0: + if is_iter_type: + if is_wrapped: + return None # is_wrapped no node, we want None + return [] # not wrapped, assume empty list + return None # Assume it's not there, maybe an optional node. + + # If is_iter_type and not wrapped, return all found children + if is_iter_type: + if not is_wrapped: + return children + # Iter and wrapped, should have found one node only (the wrap one) + if len(children) != 1: + raise DeserializationError( + "Tried to deserialize an array not wrapped, and found several nodes '{}'. Maybe you should declare this array as wrapped?".format( + xml_name + ) + ) + return list(children[0]) # Might be empty list and that's ok. + + # Here it's not a itertype, we should have found one element only or empty + if len(children) > 1: + raise DeserializationError("Find several XML '{}' where it was not expected".format(xml_name)) + return children[0] + + +class Deserializer: + """Response object model deserializer. + + :param dict classes: Class type dictionary for deserializing complex types. + :ivar list key_extractors: Ordered list of extractors to be used by this deserializer. + """ + + basic_types = {str: "str", int: "int", bool: "bool", float: "float"} + + valid_date = re.compile(r"\d{4}[-]\d{2}[-]\d{2}T\d{2}:\d{2}:\d{2}\.?\d*Z?[-+]?[\d{2}]?:?[\d{2}]?") + + def __init__(self, classes: Optional[Mapping[str, type]] = None) -> None: + self.deserialize_type = { + "iso-8601": Deserializer.deserialize_iso, + "rfc-1123": Deserializer.deserialize_rfc, + "unix-time": Deserializer.deserialize_unix, + "duration": Deserializer.deserialize_duration, + "date": Deserializer.deserialize_date, + "time": Deserializer.deserialize_time, + "decimal": Deserializer.deserialize_decimal, + "long": Deserializer.deserialize_long, + "bytearray": Deserializer.deserialize_bytearray, + "base64": Deserializer.deserialize_base64, + "object": self.deserialize_object, + "[]": self.deserialize_iter, + "{}": self.deserialize_dict, + } + self.deserialize_expected_types = { + "duration": (isodate.Duration, datetime.timedelta), + "iso-8601": (datetime.datetime), + } + self.dependencies: Dict[str, type] = dict(classes) if classes else {} + self.key_extractors = [rest_key_extractor, xml_key_extractor] + # Additional properties only works if the "rest_key_extractor" is used to + # extract the keys. Making it to work whatever the key extractor is too much + # complicated, with no real scenario for now. + # So adding a flag to disable additional properties detection. This flag should be + # used if your expect the deserialization to NOT come from a JSON REST syntax. + # Otherwise, result are unexpected + self.additional_properties_detection = True + + def __call__(self, target_obj, response_data, content_type=None): + """Call the deserializer to process a REST response. + + :param str target_obj: Target data type to deserialize to. + :param requests.Response response_data: REST response object. + :param str content_type: Swagger "produces" if available. + :raises DeserializationError: if deserialization fails. + :return: Deserialized object. + :rtype: object + """ + data = self._unpack_content(response_data, content_type) + return self._deserialize(target_obj, data) + + def _deserialize(self, target_obj, data): # pylint: disable=inconsistent-return-statements + """Call the deserializer on a model. + + Data needs to be already deserialized as JSON or XML ElementTree + + :param str target_obj: Target data type to deserialize to. + :param object data: Object to deserialize. + :raises DeserializationError: if deserialization fails. + :return: Deserialized object. + :rtype: object + """ + # This is already a model, go recursive just in case + if hasattr(data, "_attribute_map"): + constants = [name for name, config in getattr(data, "_validation", {}).items() if config.get("constant")] + try: + for attr, mapconfig in data._attribute_map.items(): # pylint: disable=protected-access + if attr in constants: + continue + value = getattr(data, attr) + if value is None: + continue + local_type = mapconfig["type"] + internal_data_type = local_type.strip("[]{}") + if internal_data_type not in self.dependencies or isinstance(internal_data_type, Enum): + continue + setattr(data, attr, self._deserialize(local_type, value)) + return data + except AttributeError: + return + + response, class_name = self._classify_target(target_obj, data) + + if isinstance(response, str): + return self.deserialize_data(data, response) + if isinstance(response, type) and issubclass(response, Enum): + return self.deserialize_enum(data, response) + + if data is None or data is CoreNull: + return data + try: + attributes = response._attribute_map # type: ignore # pylint: disable=protected-access + d_attrs = {} + for attr, attr_desc in attributes.items(): + # Check empty string. If it's not empty, someone has a real "additionalProperties"... + if attr == "additional_properties" and attr_desc["key"] == "": + continue + raw_value = None + # Enhance attr_desc with some dynamic data + attr_desc = attr_desc.copy() # Do a copy, do not change the real one + internal_data_type = attr_desc["type"].strip("[]{}") + if internal_data_type in self.dependencies: + attr_desc["internalType"] = self.dependencies[internal_data_type] + + for key_extractor in self.key_extractors: + found_value = key_extractor(attr, attr_desc, data) + if found_value is not None: + if raw_value is not None and raw_value != found_value: + msg = ( + "Ignoring extracted value '%s' from %s for key '%s'" + " (duplicate extraction, follow extractors order)" + ) + _LOGGER.warning(msg, found_value, key_extractor, attr) + continue + raw_value = found_value + + value = self.deserialize_data(raw_value, attr_desc["type"]) + d_attrs[attr] = value + except (AttributeError, TypeError, KeyError) as err: + msg = "Unable to deserialize to object: " + class_name # type: ignore + raise DeserializationError(msg) from err + additional_properties = self._build_additional_properties(attributes, data) + return self._instantiate_model(response, d_attrs, additional_properties) + + def _build_additional_properties(self, attribute_map, data): + if not self.additional_properties_detection: + return None + if "additional_properties" in attribute_map and attribute_map.get("additional_properties", {}).get("key") != "": + # Check empty string. If it's not empty, someone has a real "additionalProperties" + return None + if isinstance(data, ET.Element): + data = {el.tag: el.text for el in data} + + known_keys = { + _decode_attribute_map_key(_FLATTEN.split(desc["key"])[0]) + for desc in attribute_map.values() + if desc["key"] != "" + } + present_keys = set(data.keys()) + missing_keys = present_keys - known_keys + return {key: data[key] for key in missing_keys} + + def _classify_target(self, target, data): + """Check to see whether the deserialization target object can + be classified into a subclass. + Once classification has been determined, initialize object. + + :param str target: The target object type to deserialize to. + :param str/dict data: The response data to deserialize. + :return: The classified target object and its class name. + :rtype: tuple + """ + if target is None: + return None, None + + if isinstance(target, str): + try: + target = self.dependencies[target] + except KeyError: + return target, target + + try: + target = target._classify(data, self.dependencies) # type: ignore # pylint: disable=protected-access + except AttributeError: + pass # Target is not a Model, no classify + return target, target.__class__.__name__ # type: ignore + + def failsafe_deserialize(self, target_obj, data, content_type=None): + """Ignores any errors encountered in deserialization, + and falls back to not deserializing the object. Recommended + for use in error deserialization, as we want to return the + HttpResponseError to users, and not have them deal with + a deserialization error. + + :param str target_obj: The target object type to deserialize to. + :param str/dict data: The response data to deserialize. + :param str content_type: Swagger "produces" if available. + :return: Deserialized object. + :rtype: object + """ + try: + return self(target_obj, data, content_type=content_type) + except: # pylint: disable=bare-except + _LOGGER.debug( + "Ran into a deserialization error. Ignoring since this is failsafe deserialization", exc_info=True + ) + return None + + @staticmethod + def _unpack_content(raw_data, content_type=None): + """Extract the correct structure for deserialization. + + If raw_data is a PipelineResponse, try to extract the result of RawDeserializer. + if we can't, raise. Your Pipeline should have a RawDeserializer. + + If not a pipeline response and raw_data is bytes or string, use content-type + to decode it. If no content-type, try JSON. + + If raw_data is something else, bypass all logic and return it directly. + + :param obj raw_data: Data to be processed. + :param str content_type: How to parse if raw_data is a string/bytes. + :raises JSONDecodeError: If JSON is requested and parsing is impossible. + :raises UnicodeDecodeError: If bytes is not UTF8 + :rtype: object + :return: Unpacked content. + """ + # Assume this is enough to detect a Pipeline Response without importing it + context = getattr(raw_data, "context", {}) + if context: + if RawDeserializer.CONTEXT_NAME in context: + return context[RawDeserializer.CONTEXT_NAME] + raise ValueError("This pipeline didn't have the RawDeserializer policy; can't deserialize") + + # Assume this is enough to recognize universal_http.ClientResponse without importing it + if hasattr(raw_data, "body"): + return RawDeserializer.deserialize_from_http_generics(raw_data.text(), raw_data.headers) + + # Assume this enough to recognize requests.Response without importing it. + if hasattr(raw_data, "_content_consumed"): + return RawDeserializer.deserialize_from_http_generics(raw_data.text, raw_data.headers) + + if isinstance(raw_data, (str, bytes)) or hasattr(raw_data, "read"): + return RawDeserializer.deserialize_from_text(raw_data, content_type) # type: ignore + return raw_data + + def _instantiate_model(self, response, attrs, additional_properties=None): + """Instantiate a response model passing in deserialized args. + + :param Response response: The response model class. + :param dict attrs: The deserialized response attributes. + :param dict additional_properties: Additional properties to be set. + :rtype: Response + :return: The instantiated response model. + """ + if callable(response): + subtype = getattr(response, "_subtype_map", {}) + try: + readonly = [ + k + for k, v in response._validation.items() # pylint: disable=protected-access # type: ignore + if v.get("readonly") + ] + const = [ + k + for k, v in response._validation.items() # pylint: disable=protected-access # type: ignore + if v.get("constant") + ] + kwargs = {k: v for k, v in attrs.items() if k not in subtype and k not in readonly + const} + response_obj = response(**kwargs) + for attr in readonly: + setattr(response_obj, attr, attrs.get(attr)) + if additional_properties: + response_obj.additional_properties = additional_properties # type: ignore + return response_obj + except TypeError as err: + msg = "Unable to deserialize {} into model {}. ".format(kwargs, response) # type: ignore + raise DeserializationError(msg + str(err)) from err + else: + try: + for attr, value in attrs.items(): + setattr(response, attr, value) + return response + except Exception as exp: + msg = "Unable to populate response model. " + msg += "Type: {}, Error: {}".format(type(response), exp) + raise DeserializationError(msg) from exp + + def deserialize_data(self, data, data_type): # pylint: disable=too-many-return-statements + """Process data for deserialization according to data type. + + :param str data: The response string to be deserialized. + :param str data_type: The type to deserialize to. + :raises DeserializationError: if deserialization fails. + :return: Deserialized object. + :rtype: object + """ + if data is None: + return data + + try: + if not data_type: + return data + if data_type in self.basic_types.values(): + return self.deserialize_basic(data, data_type) + if data_type in self.deserialize_type: + if isinstance(data, self.deserialize_expected_types.get(data_type, tuple())): + return data + + is_a_text_parsing_type = lambda x: x not in [ # pylint: disable=unnecessary-lambda-assignment + "object", + "[]", + r"{}", + ] + if isinstance(data, ET.Element) and is_a_text_parsing_type(data_type) and not data.text: + return None + data_val = self.deserialize_type[data_type](data) + return data_val + + iter_type = data_type[0] + data_type[-1] + if iter_type in self.deserialize_type: + return self.deserialize_type[iter_type](data, data_type[1:-1]) + + obj_type = self.dependencies[data_type] + if issubclass(obj_type, Enum): + if isinstance(data, ET.Element): + data = data.text + return self.deserialize_enum(data, obj_type) + + except (ValueError, TypeError, AttributeError) as err: + msg = "Unable to deserialize response data." + msg += " Data: {}, {}".format(data, data_type) + raise DeserializationError(msg) from err + return self._deserialize(obj_type, data) + + def deserialize_iter(self, attr, iter_type): + """Deserialize an iterable. + + :param list attr: Iterable to be deserialized. + :param str iter_type: The type of object in the iterable. + :return: Deserialized iterable. + :rtype: list + """ + if attr is None: + return None + if isinstance(attr, ET.Element): # If I receive an element here, get the children + attr = list(attr) + if not isinstance(attr, (list, set)): + raise DeserializationError("Cannot deserialize as [{}] an object of type {}".format(iter_type, type(attr))) + return [self.deserialize_data(a, iter_type) for a in attr] + + def deserialize_dict(self, attr, dict_type): + """Deserialize a dictionary. + + :param dict/list attr: Dictionary to be deserialized. Also accepts + a list of key, value pairs. + :param str dict_type: The object type of the items in the dictionary. + :return: Deserialized dictionary. + :rtype: dict + """ + if isinstance(attr, list): + return {x["key"]: self.deserialize_data(x["value"], dict_type) for x in attr} + + if isinstance(attr, ET.Element): + # Transform value into {"Key": "value"} + attr = {el.tag: el.text for el in attr} + return {k: self.deserialize_data(v, dict_type) for k, v in attr.items()} + + def deserialize_object(self, attr, **kwargs): # pylint: disable=too-many-return-statements + """Deserialize a generic object. + This will be handled as a dictionary. + + :param dict attr: Dictionary to be deserialized. + :return: Deserialized object. + :rtype: dict + :raises TypeError: if non-builtin datatype encountered. + """ + if attr is None: + return None + if isinstance(attr, ET.Element): + # Do no recurse on XML, just return the tree as-is + return attr + if isinstance(attr, str): + return self.deserialize_basic(attr, "str") + obj_type = type(attr) + if obj_type in self.basic_types: + return self.deserialize_basic(attr, self.basic_types[obj_type]) + if obj_type is _long_type: + return self.deserialize_long(attr) + + if obj_type == dict: + deserialized = {} + for key, value in attr.items(): + try: + deserialized[key] = self.deserialize_object(value, **kwargs) + except ValueError: + deserialized[key] = None + return deserialized + + if obj_type == list: + deserialized = [] + for obj in attr: + try: + deserialized.append(self.deserialize_object(obj, **kwargs)) + except ValueError: + pass + return deserialized + + error = "Cannot deserialize generic object with type: " + raise TypeError(error + str(obj_type)) + + def deserialize_basic(self, attr, data_type): # pylint: disable=too-many-return-statements + """Deserialize basic builtin data type from string. + Will attempt to convert to str, int, float and bool. + This function will also accept '1', '0', 'true' and 'false' as + valid bool values. + + :param str attr: response string to be deserialized. + :param str data_type: deserialization data type. + :return: Deserialized basic type. + :rtype: str, int, float or bool + :raises TypeError: if string format is not valid. + """ + # If we're here, data is supposed to be a basic type. + # If it's still an XML node, take the text + if isinstance(attr, ET.Element): + attr = attr.text + if not attr: + if data_type == "str": + # None or '', node is empty string. + return "" + # None or '', node with a strong type is None. + # Don't try to model "empty bool" or "empty int" + return None + + if data_type == "bool": + if attr in [True, False, 1, 0]: + return bool(attr) + if isinstance(attr, str): + if attr.lower() in ["true", "1"]: + return True + if attr.lower() in ["false", "0"]: + return False + raise TypeError("Invalid boolean value: {}".format(attr)) + + if data_type == "str": + return self.deserialize_unicode(attr) + return eval(data_type)(attr) # nosec # pylint: disable=eval-used + + @staticmethod + def deserialize_unicode(data): + """Preserve unicode objects in Python 2, otherwise return data + as a string. + + :param str data: response string to be deserialized. + :return: Deserialized string. + :rtype: str or unicode + """ + # We might be here because we have an enum modeled as string, + # and we try to deserialize a partial dict with enum inside + if isinstance(data, Enum): + return data + + # Consider this is real string + try: + if isinstance(data, unicode): # type: ignore + return data + except NameError: + return str(data) + return str(data) + + @staticmethod + def deserialize_enum(data, enum_obj): + """Deserialize string into enum object. + + If the string is not a valid enum value it will be returned as-is + and a warning will be logged. + + :param str data: Response string to be deserialized. If this value is + None or invalid it will be returned as-is. + :param Enum enum_obj: Enum object to deserialize to. + :return: Deserialized enum object. + :rtype: Enum + """ + if isinstance(data, enum_obj) or data is None: + return data + if isinstance(data, Enum): + data = data.value + if isinstance(data, int): + # Workaround. We might consider remove it in the future. + try: + return list(enum_obj.__members__.values())[data] + except IndexError as exc: + error = "{!r} is not a valid index for enum {!r}" + raise DeserializationError(error.format(data, enum_obj)) from exc + try: + return enum_obj(str(data)) + except ValueError: + for enum_value in enum_obj: + if enum_value.value.lower() == str(data).lower(): + return enum_value + # We don't fail anymore for unknown value, we deserialize as a string + _LOGGER.warning("Deserializer is not able to find %s as valid enum in %s", data, enum_obj) + return Deserializer.deserialize_unicode(data) + + @staticmethod + def deserialize_bytearray(attr): + """Deserialize string into bytearray. + + :param str attr: response string to be deserialized. + :return: Deserialized bytearray + :rtype: bytearray + :raises TypeError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + return bytearray(b64decode(attr)) # type: ignore + + @staticmethod + def deserialize_base64(attr): + """Deserialize base64 encoded string into string. + + :param str attr: response string to be deserialized. + :return: Deserialized base64 string + :rtype: bytearray + :raises TypeError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + padding = "=" * (3 - (len(attr) + 3) % 4) # type: ignore + attr = attr + padding # type: ignore + encoded = attr.replace("-", "+").replace("_", "/") + return b64decode(encoded) + + @staticmethod + def deserialize_decimal(attr): + """Deserialize string into Decimal object. + + :param str attr: response string to be deserialized. + :return: Deserialized decimal + :raises DeserializationError: if string format invalid. + :rtype: decimal + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + return decimal.Decimal(str(attr)) # type: ignore + except decimal.DecimalException as err: + msg = "Invalid decimal {}".format(attr) + raise DeserializationError(msg) from err + + @staticmethod + def deserialize_long(attr): + """Deserialize string into long (Py2) or int (Py3). + + :param str attr: response string to be deserialized. + :return: Deserialized int + :rtype: long or int + :raises ValueError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + return _long_type(attr) # type: ignore + + @staticmethod + def deserialize_duration(attr): + """Deserialize ISO-8601 formatted string into TimeDelta object. + + :param str attr: response string to be deserialized. + :return: Deserialized duration + :rtype: TimeDelta + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + duration = isodate.parse_duration(attr) + except (ValueError, OverflowError, AttributeError) as err: + msg = "Cannot deserialize duration object." + raise DeserializationError(msg) from err + return duration + + @staticmethod + def deserialize_date(attr): + """Deserialize ISO-8601 formatted string into Date object. + + :param str attr: response string to be deserialized. + :return: Deserialized date + :rtype: Date + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + if re.search(r"[^\W\d_]", attr, re.I + re.U): # type: ignore + raise DeserializationError("Date must have only digits and -. Received: %s" % attr) + # This must NOT use defaultmonth/defaultday. Using None ensure this raises an exception. + return isodate.parse_date(attr, defaultmonth=0, defaultday=0) + + @staticmethod + def deserialize_time(attr): + """Deserialize ISO-8601 formatted string into time object. + + :param str attr: response string to be deserialized. + :return: Deserialized time + :rtype: datetime.time + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + if re.search(r"[^\W\d_]", attr, re.I + re.U): # type: ignore + raise DeserializationError("Date must have only digits and -. Received: %s" % attr) + return isodate.parse_time(attr) + + @staticmethod + def deserialize_rfc(attr): + """Deserialize RFC-1123 formatted string into Datetime object. + + :param str attr: response string to be deserialized. + :return: Deserialized RFC datetime + :rtype: Datetime + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + parsed_date = email.utils.parsedate_tz(attr) # type: ignore + date_obj = datetime.datetime( + *parsed_date[:6], tzinfo=datetime.timezone(datetime.timedelta(minutes=(parsed_date[9] or 0) / 60)) + ) + if not date_obj.tzinfo: + date_obj = date_obj.astimezone(tz=TZ_UTC) + except ValueError as err: + msg = "Cannot deserialize to rfc datetime object." + raise DeserializationError(msg) from err + return date_obj + + @staticmethod + def deserialize_iso(attr): + """Deserialize ISO-8601 formatted string into Datetime object. + + :param str attr: response string to be deserialized. + :return: Deserialized ISO datetime + :rtype: Datetime + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + attr = attr.upper() # type: ignore + match = Deserializer.valid_date.match(attr) + if not match: + raise ValueError("Invalid datetime string: " + attr) + + check_decimal = attr.split(".") + if len(check_decimal) > 1: + decimal_str = "" + for digit in check_decimal[1]: + if digit.isdigit(): + decimal_str += digit + else: + break + if len(decimal_str) > 6: + attr = attr.replace(decimal_str, decimal_str[0:6]) + + date_obj = isodate.parse_datetime(attr) + test_utc = date_obj.utctimetuple() + if test_utc.tm_year > 9999 or test_utc.tm_year < 1: + raise OverflowError("Hit max or min date") + except (ValueError, OverflowError, AttributeError) as err: + msg = "Cannot deserialize datetime object." + raise DeserializationError(msg) from err + return date_obj + + @staticmethod + def deserialize_unix(attr): + """Serialize Datetime object into IntTime format. + This is represented as seconds. + + :param int attr: Object to be serialized. + :return: Deserialized datetime + :rtype: Datetime + :raises DeserializationError: if format invalid + """ + if isinstance(attr, ET.Element): + attr = int(attr.text) # type: ignore + try: + attr = int(attr) + date_obj = datetime.datetime.fromtimestamp(attr, TZ_UTC) + except ValueError as err: + msg = "Cannot deserialize to unix datetime object." + raise DeserializationError(msg) from err + return date_obj diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/MediaTypesVersionTolerant/mediatypesversiontolerant/_utils/utils.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/MediaTypesVersionTolerant/mediatypesversiontolerant/_utils/utils.py new file mode 100644 index 00000000000..d1f895895c6 --- /dev/null +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/MediaTypesVersionTolerant/mediatypesversiontolerant/_utils/utils.py @@ -0,0 +1,36 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from abc import ABC +from typing import Generic, TYPE_CHECKING, TypeVar + +if TYPE_CHECKING: + from .serialization import Deserializer, Serializer + + +TClient = TypeVar("TClient") +TConfig = TypeVar("TConfig") + + +class ClientMixinABC(ABC, Generic[TClient, TConfig]): + """DO NOT use this class. It is for internal typing use only.""" + + _client: TClient + _config: TConfig + _serialize: "Serializer" + _deserialize: "Deserializer" + + +def raise_if_not_implemented(cls, abstract_methods): + not_implemented = [f for f in abstract_methods if not callable(getattr(cls, f, None))] + if not_implemented: + raise NotImplementedError( + "The following methods on operation group '{}' are not implemented: '{}'." + " Please refer to https://aka.ms/azsdk/python/dpcodegen/python/customize to learn how to customize.".format( + cls.__name__, "', '".join(not_implemented) + ) + ) diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/MediaTypesVersionTolerant/mediatypesversiontolerant/_vendor.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/MediaTypesVersionTolerant/mediatypesversiontolerant/_vendor.py deleted file mode 100644 index 4cda5066f96..00000000000 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/MediaTypesVersionTolerant/mediatypesversiontolerant/_vendor.py +++ /dev/null @@ -1,36 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) AutoRest Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import MediaTypesClientConfiguration - -if TYPE_CHECKING: - from azure.core import PipelineClient - - from ._serialization import Deserializer, Serializer - - -class MediaTypesClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "PipelineClient" - _config: MediaTypesClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" - - -def raise_if_not_implemented(cls, abstract_methods): - not_implemented = [f for f in abstract_methods if not callable(getattr(cls, f, None))] - if not_implemented: - raise NotImplementedError( - "The following methods on operation group '{}' are not implemented: '{}'." - " Please refer to https://aka.ms/azsdk/python/dpcodegen/python/customize to learn how to customize.".format( - cls.__name__, "', '".join(not_implemented) - ) - ) diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/MediaTypesVersionTolerant/mediatypesversiontolerant/aio/_client.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/MediaTypesVersionTolerant/mediatypesversiontolerant/aio/_client.py index f79bc9e395c..a3fdbcaab3a 100644 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/MediaTypesVersionTolerant/mediatypesversiontolerant/aio/_client.py +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/MediaTypesVersionTolerant/mediatypesversiontolerant/aio/_client.py @@ -14,7 +14,7 @@ from azure.core.pipeline import policies from azure.core.rest import AsyncHttpResponse, HttpRequest -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import MediaTypesClientConfiguration from ._operations import MediaTypesClientOperationsMixin diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/MediaTypesVersionTolerant/mediatypesversiontolerant/aio/_operations/_operations.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/MediaTypesVersionTolerant/mediatypesversiontolerant/aio/_operations/_operations.py index bfcea3d16c1..d642a68b10e 100644 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/MediaTypesVersionTolerant/mediatypesversiontolerant/aio/_operations/_operations.py +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/MediaTypesVersionTolerant/mediatypesversiontolerant/aio/_operations/_operations.py @@ -10,6 +10,7 @@ from io import IOBase from typing import Any, Callable, Dict, IO, Optional, TypeVar, Union, cast, overload +from azure.core import AsyncPipelineClient from azure.core.exceptions import ( ClientAuthenticationError, HttpResponseError, @@ -31,14 +32,17 @@ build_media_types_content_type_with_encoding_request, build_media_types_put_text_and_json_body_request, ) -from .._vendor import MediaTypesClientMixinABC, raise_if_not_implemented +from ..._utils.utils import ClientMixinABC, raise_if_not_implemented +from .._configuration import MediaTypesClientConfiguration JSON = MutableMapping[str, Any] T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, AsyncHttpResponse], T, Dict[str, Any]], Any]] -class MediaTypesClientOperationsMixin(MediaTypesClientMixinABC): # pylint: disable=abstract-class-instantiated +class MediaTypesClientOperationsMixin( # pylint: disable=abstract-class-instantiated + ClientMixinABC[AsyncPipelineClient, MediaTypesClientConfiguration] +): def __init__(self) -> None: raise_if_not_implemented( diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/MediaTypesVersionTolerant/mediatypesversiontolerant/aio/_vendor.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/MediaTypesVersionTolerant/mediatypesversiontolerant/aio/_vendor.py deleted file mode 100644 index c151fb621f7..00000000000 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/MediaTypesVersionTolerant/mediatypesversiontolerant/aio/_vendor.py +++ /dev/null @@ -1,36 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) AutoRest Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import MediaTypesClientConfiguration - -if TYPE_CHECKING: - from azure.core import AsyncPipelineClient - - from .._serialization import Deserializer, Serializer - - -class MediaTypesClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "AsyncPipelineClient" - _config: MediaTypesClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" - - -def raise_if_not_implemented(cls, abstract_methods): - not_implemented = [f for f in abstract_methods if not callable(getattr(cls, f, None))] - if not_implemented: - raise NotImplementedError( - "The following methods on operation group '{}' are not implemented: '{}'." - " Please refer to https://aka.ms/azsdk/python/dpcodegen/python/customize to learn how to customize.".format( - cls.__name__, "', '".join(not_implemented) - ) - ) diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/MergePatchJsonVersionTolerant/mergepatchjsonversiontolerant/_client.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/MergePatchJsonVersionTolerant/mergepatchjsonversiontolerant/_client.py index 8d3a58dc3d9..5701fd36290 100644 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/MergePatchJsonVersionTolerant/mergepatchjsonversiontolerant/_client.py +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/MergePatchJsonVersionTolerant/mergepatchjsonversiontolerant/_client.py @@ -16,7 +16,7 @@ from ._configuration import MergePatchJsonClientConfiguration from ._operations import MergePatchJsonClientOperationsMixin -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer class MergePatchJsonClient(MergePatchJsonClientOperationsMixin): # pylint: disable=client-accepts-api-version-keyword diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/MergePatchJsonVersionTolerant/mergepatchjsonversiontolerant/_operations/_operations.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/MergePatchJsonVersionTolerant/mergepatchjsonversiontolerant/_operations/_operations.py index 8c488354f08..d87663100b9 100644 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/MergePatchJsonVersionTolerant/mergepatchjsonversiontolerant/_operations/_operations.py +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/MergePatchJsonVersionTolerant/mergepatchjsonversiontolerant/_operations/_operations.py @@ -8,6 +8,7 @@ from collections.abc import MutableMapping from typing import Any, Callable, Dict, Optional, TypeVar +from azure.core import PipelineClient from azure.core.exceptions import ( ClientAuthenticationError, HttpResponseError, @@ -21,8 +22,9 @@ from azure.core.tracing.decorator import distributed_trace from azure.core.utils import case_insensitive_dict -from .._serialization import Serializer -from .._vendor import MergePatchJsonClientMixinABC +from .._configuration import MergePatchJsonClientConfiguration +from .._utils.serialization import Serializer +from .._utils.utils import ClientMixinABC JSON = MutableMapping[str, Any] T = TypeVar("T") @@ -51,7 +53,7 @@ def build_merge_patch_json_patch_single_request( # pylint: disable=name-too-lon return HttpRequest(method="PATCH", url=_url, headers=_headers, json=json, **kwargs) -class MergePatchJsonClientOperationsMixin(MergePatchJsonClientMixinABC): +class MergePatchJsonClientOperationsMixin(ClientMixinABC[PipelineClient, MergePatchJsonClientConfiguration]): @distributed_trace def patch_single(self, body: JSON, **kwargs: Any) -> None: # pylint: disable=inconsistent-return-statements diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/MergePatchJsonVersionTolerant/mergepatchjsonversiontolerant/_utils/__init__.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/MergePatchJsonVersionTolerant/mergepatchjsonversiontolerant/_utils/__init__.py new file mode 100644 index 00000000000..0af9b28f660 --- /dev/null +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/MergePatchJsonVersionTolerant/mergepatchjsonversiontolerant/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/MergePatchJsonVersionTolerant/mergepatchjsonversiontolerant/_utils/serialization.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/MergePatchJsonVersionTolerant/mergepatchjsonversiontolerant/_utils/serialization.py new file mode 100644 index 00000000000..f5187701d7b --- /dev/null +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/MergePatchJsonVersionTolerant/mergepatchjsonversiontolerant/_utils/serialization.py @@ -0,0 +1,2032 @@ +# pylint: disable=line-too-long,useless-suppression,too-many-lines +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +# pyright: reportUnnecessaryTypeIgnoreComment=false + +from base64 import b64decode, b64encode +import calendar +import datetime +import decimal +import email +from enum import Enum +import json +import logging +import re +import sys +import codecs +from typing import ( + Dict, + Any, + cast, + Optional, + Union, + AnyStr, + IO, + Mapping, + Callable, + MutableMapping, + List, +) + +try: + from urllib import quote # type: ignore +except ImportError: + from urllib.parse import quote +import xml.etree.ElementTree as ET + +import isodate # type: ignore +from typing_extensions import Self + +from azure.core.exceptions import DeserializationError, SerializationError +from azure.core.serialization import NULL as CoreNull + +_BOM = codecs.BOM_UTF8.decode(encoding="utf-8") + +JSON = MutableMapping[str, Any] + + +class RawDeserializer: + + # Accept "text" because we're open minded people... + JSON_REGEXP = re.compile(r"^(application|text)/([a-z+.]+\+)?json$") + + # Name used in context + CONTEXT_NAME = "deserialized_data" + + @classmethod + def deserialize_from_text(cls, data: Optional[Union[AnyStr, IO]], content_type: Optional[str] = None) -> Any: + """Decode data according to content-type. + + Accept a stream of data as well, but will be load at once in memory for now. + + If no content-type, will return the string version (not bytes, not stream) + + :param data: Input, could be bytes or stream (will be decoded with UTF8) or text + :type data: str or bytes or IO + :param str content_type: The content type. + :return: The deserialized data. + :rtype: object + """ + if hasattr(data, "read"): + # Assume a stream + data = cast(IO, data).read() + + if isinstance(data, bytes): + data_as_str = data.decode(encoding="utf-8-sig") + else: + # Explain to mypy the correct type. + data_as_str = cast(str, data) + + # Remove Byte Order Mark if present in string + data_as_str = data_as_str.lstrip(_BOM) + + if content_type is None: + return data + + if cls.JSON_REGEXP.match(content_type): + try: + return json.loads(data_as_str) + except ValueError as err: + raise DeserializationError("JSON is invalid: {}".format(err), err) from err + elif "xml" in (content_type or []): + try: + + try: + if isinstance(data, unicode): # type: ignore + # If I'm Python 2.7 and unicode XML will scream if I try a "fromstring" on unicode string + data_as_str = data_as_str.encode(encoding="utf-8") # type: ignore + except NameError: + pass + + return ET.fromstring(data_as_str) # nosec + except ET.ParseError as err: + # It might be because the server has an issue, and returned JSON with + # content-type XML.... + # So let's try a JSON load, and if it's still broken + # let's flow the initial exception + def _json_attemp(data): + try: + return True, json.loads(data) + except ValueError: + return False, None # Don't care about this one + + success, json_result = _json_attemp(data) + if success: + return json_result + # If i'm here, it's not JSON, it's not XML, let's scream + # and raise the last context in this block (the XML exception) + # The function hack is because Py2.7 messes up with exception + # context otherwise. + _LOGGER.critical("Wasn't XML not JSON, failing") + raise DeserializationError("XML is invalid") from err + elif content_type.startswith("text/"): + return data_as_str + raise DeserializationError("Cannot deserialize content-type: {}".format(content_type)) + + @classmethod + def deserialize_from_http_generics(cls, body_bytes: Optional[Union[AnyStr, IO]], headers: Mapping) -> Any: + """Deserialize from HTTP response. + + Use bytes and headers to NOT use any requests/aiohttp or whatever + specific implementation. + Headers will tested for "content-type" + + :param bytes body_bytes: The body of the response. + :param dict headers: The headers of the response. + :returns: The deserialized data. + :rtype: object + """ + # Try to use content-type from headers if available + content_type = None + if "content-type" in headers: + content_type = headers["content-type"].split(";")[0].strip().lower() + # Ouch, this server did not declare what it sent... + # Let's guess it's JSON... + # Also, since Autorest was considering that an empty body was a valid JSON, + # need that test as well.... + else: + content_type = "application/json" + + if body_bytes: + return cls.deserialize_from_text(body_bytes, content_type) + return None + + +_LOGGER = logging.getLogger(__name__) + +try: + _long_type = long # type: ignore +except NameError: + _long_type = int + +TZ_UTC = datetime.timezone.utc + +_FLATTEN = re.compile(r"(? None: + self.additional_properties: Optional[Dict[str, Any]] = {} + for k in kwargs: # pylint: disable=consider-using-dict-items + if k not in self._attribute_map: + _LOGGER.warning("%s is not a known attribute of class %s and will be ignored", k, self.__class__) + elif k in self._validation and self._validation[k].get("readonly", False): + _LOGGER.warning("Readonly attribute %s will be ignored in class %s", k, self.__class__) + else: + setattr(self, k, kwargs[k]) + + def __eq__(self, other: Any) -> bool: + """Compare objects by comparing all attributes. + + :param object other: The object to compare + :returns: True if objects are equal + :rtype: bool + """ + if isinstance(other, self.__class__): + return self.__dict__ == other.__dict__ + return False + + def __ne__(self, other: Any) -> bool: + """Compare objects by comparing all attributes. + + :param object other: The object to compare + :returns: True if objects are not equal + :rtype: bool + """ + return not self.__eq__(other) + + def __str__(self) -> str: + return str(self.__dict__) + + @classmethod + def enable_additional_properties_sending(cls) -> None: + cls._attribute_map["additional_properties"] = {"key": "", "type": "{object}"} + + @classmethod + def is_xml_model(cls) -> bool: + try: + cls._xml_map # type: ignore + except AttributeError: + return False + return True + + @classmethod + def _create_xml_node(cls): + """Create XML node. + + :returns: The XML node + :rtype: xml.etree.ElementTree.Element + """ + try: + xml_map = cls._xml_map # type: ignore + except AttributeError: + xml_map = {} + + return _create_xml_node(xml_map.get("name", cls.__name__), xml_map.get("prefix", None), xml_map.get("ns", None)) + + def serialize(self, keep_readonly: bool = False, **kwargs: Any) -> JSON: + """Return the JSON that would be sent to server from this model. + + This is an alias to `as_dict(full_restapi_key_transformer, keep_readonly=False)`. + + If you want XML serialization, you can pass the kwargs is_xml=True. + + :param bool keep_readonly: If you want to serialize the readonly attributes + :returns: A dict JSON compatible object + :rtype: dict + """ + serializer = Serializer(self._infer_class_models()) + return serializer._serialize( # type: ignore # pylint: disable=protected-access + self, keep_readonly=keep_readonly, **kwargs + ) + + def as_dict( + self, + keep_readonly: bool = True, + key_transformer: Callable[[str, Dict[str, Any], Any], Any] = attribute_transformer, + **kwargs: Any + ) -> JSON: + """Return a dict that can be serialized using json.dump. + + Advanced usage might optionally use a callback as parameter: + + .. code::python + + def my_key_transformer(key, attr_desc, value): + return key + + Key is the attribute name used in Python. Attr_desc + is a dict of metadata. Currently contains 'type' with the + msrest type and 'key' with the RestAPI encoded key. + Value is the current value in this object. + + The string returned will be used to serialize the key. + If the return type is a list, this is considered hierarchical + result dict. + + See the three examples in this file: + + - attribute_transformer + - full_restapi_key_transformer + - last_restapi_key_transformer + + If you want XML serialization, you can pass the kwargs is_xml=True. + + :param bool keep_readonly: If you want to serialize the readonly attributes + :param function key_transformer: A key transformer function. + :returns: A dict JSON compatible object + :rtype: dict + """ + serializer = Serializer(self._infer_class_models()) + return serializer._serialize( # type: ignore # pylint: disable=protected-access + self, key_transformer=key_transformer, keep_readonly=keep_readonly, **kwargs + ) + + @classmethod + def _infer_class_models(cls): + try: + str_models = cls.__module__.rsplit(".", 1)[0] + models = sys.modules[str_models] + client_models = {k: v for k, v in models.__dict__.items() if isinstance(v, type)} + if cls.__name__ not in client_models: + raise ValueError("Not Autorest generated code") + except Exception: # pylint: disable=broad-exception-caught + # Assume it's not Autorest generated (tests?). Add ourselves as dependencies. + client_models = {cls.__name__: cls} + return client_models + + @classmethod + def deserialize(cls, data: Any, content_type: Optional[str] = None) -> Self: + """Parse a str using the RestAPI syntax and return a model. + + :param str data: A str using RestAPI structure. JSON by default. + :param str content_type: JSON by default, set application/xml if XML. + :returns: An instance of this model + :raises DeserializationError: if something went wrong + :rtype: Self + """ + deserializer = Deserializer(cls._infer_class_models()) + return deserializer(cls.__name__, data, content_type=content_type) # type: ignore + + @classmethod + def from_dict( + cls, + data: Any, + key_extractors: Optional[Callable[[str, Dict[str, Any], Any], Any]] = None, + content_type: Optional[str] = None, + ) -> Self: + """Parse a dict using given key extractor return a model. + + By default consider key + extractors (rest_key_case_insensitive_extractor, attribute_key_case_insensitive_extractor + and last_rest_key_case_insensitive_extractor) + + :param dict data: A dict using RestAPI structure + :param function key_extractors: A key extractor function. + :param str content_type: JSON by default, set application/xml if XML. + :returns: An instance of this model + :raises DeserializationError: if something went wrong + :rtype: Self + """ + deserializer = Deserializer(cls._infer_class_models()) + deserializer.key_extractors = ( # type: ignore + [ # type: ignore + attribute_key_case_insensitive_extractor, + rest_key_case_insensitive_extractor, + last_rest_key_case_insensitive_extractor, + ] + if key_extractors is None + else key_extractors + ) + return deserializer(cls.__name__, data, content_type=content_type) # type: ignore + + @classmethod + def _flatten_subtype(cls, key, objects): + if "_subtype_map" not in cls.__dict__: + return {} + result = dict(cls._subtype_map[key]) + for valuetype in cls._subtype_map[key].values(): + result.update(objects[valuetype]._flatten_subtype(key, objects)) # pylint: disable=protected-access + return result + + @classmethod + def _classify(cls, response, objects): + """Check the class _subtype_map for any child classes. + We want to ignore any inherited _subtype_maps. + + :param dict response: The initial data + :param dict objects: The class objects + :returns: The class to be used + :rtype: class + """ + for subtype_key in cls.__dict__.get("_subtype_map", {}).keys(): + subtype_value = None + + if not isinstance(response, ET.Element): + rest_api_response_key = cls._get_rest_key_parts(subtype_key)[-1] + subtype_value = response.get(rest_api_response_key, None) or response.get(subtype_key, None) + else: + subtype_value = xml_key_extractor(subtype_key, cls._attribute_map[subtype_key], response) + if subtype_value: + # Try to match base class. Can be class name only + # (bug to fix in Autorest to support x-ms-discriminator-name) + if cls.__name__ == subtype_value: + return cls + flatten_mapping_type = cls._flatten_subtype(subtype_key, objects) + try: + return objects[flatten_mapping_type[subtype_value]] # type: ignore + except KeyError: + _LOGGER.warning( + "Subtype value %s has no mapping, use base class %s.", + subtype_value, + cls.__name__, + ) + break + else: + _LOGGER.warning("Discriminator %s is absent or null, use base class %s.", subtype_key, cls.__name__) + break + return cls + + @classmethod + def _get_rest_key_parts(cls, attr_key): + """Get the RestAPI key of this attr, split it and decode part + :param str attr_key: Attribute key must be in attribute_map. + :returns: A list of RestAPI part + :rtype: list + """ + rest_split_key = _FLATTEN.split(cls._attribute_map[attr_key]["key"]) + return [_decode_attribute_map_key(key_part) for key_part in rest_split_key] + + +def _decode_attribute_map_key(key): + """This decode a key in an _attribute_map to the actual key we want to look at + inside the received data. + + :param str key: A key string from the generated code + :returns: The decoded key + :rtype: str + """ + return key.replace("\\.", ".") + + +class Serializer: # pylint: disable=too-many-public-methods + """Request object model serializer.""" + + basic_types = {str: "str", int: "int", bool: "bool", float: "float"} + + _xml_basic_types_serializers = {"bool": lambda x: str(x).lower()} + days = {0: "Mon", 1: "Tue", 2: "Wed", 3: "Thu", 4: "Fri", 5: "Sat", 6: "Sun"} + months = { + 1: "Jan", + 2: "Feb", + 3: "Mar", + 4: "Apr", + 5: "May", + 6: "Jun", + 7: "Jul", + 8: "Aug", + 9: "Sep", + 10: "Oct", + 11: "Nov", + 12: "Dec", + } + validation = { + "min_length": lambda x, y: len(x) < y, + "max_length": lambda x, y: len(x) > y, + "minimum": lambda x, y: x < y, + "maximum": lambda x, y: x > y, + "minimum_ex": lambda x, y: x <= y, + "maximum_ex": lambda x, y: x >= y, + "min_items": lambda x, y: len(x) < y, + "max_items": lambda x, y: len(x) > y, + "pattern": lambda x, y: not re.match(y, x, re.UNICODE), + "unique": lambda x, y: len(x) != len(set(x)), + "multiple": lambda x, y: x % y != 0, + } + + def __init__(self, classes: Optional[Mapping[str, type]] = None) -> None: + self.serialize_type = { + "iso-8601": Serializer.serialize_iso, + "rfc-1123": Serializer.serialize_rfc, + "unix-time": Serializer.serialize_unix, + "duration": Serializer.serialize_duration, + "date": Serializer.serialize_date, + "time": Serializer.serialize_time, + "decimal": Serializer.serialize_decimal, + "long": Serializer.serialize_long, + "bytearray": Serializer.serialize_bytearray, + "base64": Serializer.serialize_base64, + "object": self.serialize_object, + "[]": self.serialize_iter, + "{}": self.serialize_dict, + } + self.dependencies: Dict[str, type] = dict(classes) if classes else {} + self.key_transformer = full_restapi_key_transformer + self.client_side_validation = True + + def _serialize( # pylint: disable=too-many-nested-blocks, too-many-branches, too-many-statements, too-many-locals + self, target_obj, data_type=None, **kwargs + ): + """Serialize data into a string according to type. + + :param object target_obj: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str, dict + :raises SerializationError: if serialization fails. + :returns: The serialized data. + """ + key_transformer = kwargs.get("key_transformer", self.key_transformer) + keep_readonly = kwargs.get("keep_readonly", False) + if target_obj is None: + return None + + attr_name = None + class_name = target_obj.__class__.__name__ + + if data_type: + return self.serialize_data(target_obj, data_type, **kwargs) + + if not hasattr(target_obj, "_attribute_map"): + data_type = type(target_obj).__name__ + if data_type in self.basic_types.values(): + return self.serialize_data(target_obj, data_type, **kwargs) + + # Force "is_xml" kwargs if we detect a XML model + try: + is_xml_model_serialization = kwargs["is_xml"] + except KeyError: + is_xml_model_serialization = kwargs.setdefault("is_xml", target_obj.is_xml_model()) + + serialized = {} + if is_xml_model_serialization: + serialized = target_obj._create_xml_node() # pylint: disable=protected-access + try: + attributes = target_obj._attribute_map # pylint: disable=protected-access + for attr, attr_desc in attributes.items(): + attr_name = attr + if not keep_readonly and target_obj._validation.get( # pylint: disable=protected-access + attr_name, {} + ).get("readonly", False): + continue + + if attr_name == "additional_properties" and attr_desc["key"] == "": + if target_obj.additional_properties is not None: + serialized.update(target_obj.additional_properties) + continue + try: + + orig_attr = getattr(target_obj, attr) + if is_xml_model_serialization: + pass # Don't provide "transformer" for XML for now. Keep "orig_attr" + else: # JSON + keys, orig_attr = key_transformer(attr, attr_desc.copy(), orig_attr) + keys = keys if isinstance(keys, list) else [keys] + + kwargs["serialization_ctxt"] = attr_desc + new_attr = self.serialize_data(orig_attr, attr_desc["type"], **kwargs) + + if is_xml_model_serialization: + xml_desc = attr_desc.get("xml", {}) + xml_name = xml_desc.get("name", attr_desc["key"]) + xml_prefix = xml_desc.get("prefix", None) + xml_ns = xml_desc.get("ns", None) + if xml_desc.get("attr", False): + if xml_ns: + ET.register_namespace(xml_prefix, xml_ns) + xml_name = "{{{}}}{}".format(xml_ns, xml_name) + serialized.set(xml_name, new_attr) # type: ignore + continue + if xml_desc.get("text", False): + serialized.text = new_attr # type: ignore + continue + if isinstance(new_attr, list): + serialized.extend(new_attr) # type: ignore + elif isinstance(new_attr, ET.Element): + # If the down XML has no XML/Name, + # we MUST replace the tag with the local tag. But keeping the namespaces. + if "name" not in getattr(orig_attr, "_xml_map", {}): + splitted_tag = new_attr.tag.split("}") + if len(splitted_tag) == 2: # Namespace + new_attr.tag = "}".join([splitted_tag[0], xml_name]) + else: + new_attr.tag = xml_name + serialized.append(new_attr) # type: ignore + else: # That's a basic type + # Integrate namespace if necessary + local_node = _create_xml_node(xml_name, xml_prefix, xml_ns) + local_node.text = str(new_attr) + serialized.append(local_node) # type: ignore + else: # JSON + for k in reversed(keys): # type: ignore + new_attr = {k: new_attr} + + _new_attr = new_attr + _serialized = serialized + for k in keys: # type: ignore + if k not in _serialized: + _serialized.update(_new_attr) # type: ignore + _new_attr = _new_attr[k] # type: ignore + _serialized = _serialized[k] + except ValueError as err: + if isinstance(err, SerializationError): + raise + + except (AttributeError, KeyError, TypeError) as err: + msg = "Attribute {} in object {} cannot be serialized.\n{}".format(attr_name, class_name, str(target_obj)) + raise SerializationError(msg) from err + return serialized + + def body(self, data, data_type, **kwargs): + """Serialize data intended for a request body. + + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: dict + :raises SerializationError: if serialization fails. + :raises ValueError: if data is None + :returns: The serialized request body + """ + + # Just in case this is a dict + internal_data_type_str = data_type.strip("[]{}") + internal_data_type = self.dependencies.get(internal_data_type_str, None) + try: + is_xml_model_serialization = kwargs["is_xml"] + except KeyError: + if internal_data_type and issubclass(internal_data_type, Model): + is_xml_model_serialization = kwargs.setdefault("is_xml", internal_data_type.is_xml_model()) + else: + is_xml_model_serialization = False + if internal_data_type and not isinstance(internal_data_type, Enum): + try: + deserializer = Deserializer(self.dependencies) + # Since it's on serialization, it's almost sure that format is not JSON REST + # We're not able to deal with additional properties for now. + deserializer.additional_properties_detection = False + if is_xml_model_serialization: + deserializer.key_extractors = [ # type: ignore + attribute_key_case_insensitive_extractor, + ] + else: + deserializer.key_extractors = [ + rest_key_case_insensitive_extractor, + attribute_key_case_insensitive_extractor, + last_rest_key_case_insensitive_extractor, + ] + data = deserializer._deserialize(data_type, data) # pylint: disable=protected-access + except DeserializationError as err: + raise SerializationError("Unable to build a model: " + str(err)) from err + + return self._serialize(data, data_type, **kwargs) + + def url(self, name, data, data_type, **kwargs): + """Serialize data intended for a URL path. + + :param str name: The name of the URL path parameter. + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str + :returns: The serialized URL path + :raises TypeError: if serialization fails. + :raises ValueError: if data is None + """ + try: + output = self.serialize_data(data, data_type, **kwargs) + if data_type == "bool": + output = json.dumps(output) + + if kwargs.get("skip_quote") is True: + output = str(output) + output = output.replace("{", quote("{")).replace("}", quote("}")) + else: + output = quote(str(output), safe="") + except SerializationError as exc: + raise TypeError("{} must be type {}.".format(name, data_type)) from exc + return output + + def query(self, name, data, data_type, **kwargs): + """Serialize data intended for a URL query. + + :param str name: The name of the query parameter. + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str, list + :raises TypeError: if serialization fails. + :raises ValueError: if data is None + :returns: The serialized query parameter + """ + try: + # Treat the list aside, since we don't want to encode the div separator + if data_type.startswith("["): + internal_data_type = data_type[1:-1] + do_quote = not kwargs.get("skip_quote", False) + return self.serialize_iter(data, internal_data_type, do_quote=do_quote, **kwargs) + + # Not a list, regular serialization + output = self.serialize_data(data, data_type, **kwargs) + if data_type == "bool": + output = json.dumps(output) + if kwargs.get("skip_quote") is True: + output = str(output) + else: + output = quote(str(output), safe="") + except SerializationError as exc: + raise TypeError("{} must be type {}.".format(name, data_type)) from exc + return str(output) + + def header(self, name, data, data_type, **kwargs): + """Serialize data intended for a request header. + + :param str name: The name of the header. + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str + :raises TypeError: if serialization fails. + :raises ValueError: if data is None + :returns: The serialized header + """ + try: + if data_type in ["[str]"]: + data = ["" if d is None else d for d in data] + + output = self.serialize_data(data, data_type, **kwargs) + if data_type == "bool": + output = json.dumps(output) + except SerializationError as exc: + raise TypeError("{} must be type {}.".format(name, data_type)) from exc + return str(output) + + def serialize_data(self, data, data_type, **kwargs): + """Serialize generic data according to supplied data type. + + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :raises AttributeError: if required data is None. + :raises ValueError: if data is None + :raises SerializationError: if serialization fails. + :returns: The serialized data. + :rtype: str, int, float, bool, dict, list + """ + if data is None: + raise ValueError("No value for given attribute") + + try: + if data is CoreNull: + return None + if data_type in self.basic_types.values(): + return self.serialize_basic(data, data_type, **kwargs) + + if data_type in self.serialize_type: + return self.serialize_type[data_type](data, **kwargs) + + # If dependencies is empty, try with current data class + # It has to be a subclass of Enum anyway + enum_type = self.dependencies.get(data_type, data.__class__) + if issubclass(enum_type, Enum): + return Serializer.serialize_enum(data, enum_obj=enum_type) + + iter_type = data_type[0] + data_type[-1] + if iter_type in self.serialize_type: + return self.serialize_type[iter_type](data, data_type[1:-1], **kwargs) + + except (ValueError, TypeError) as err: + msg = "Unable to serialize value: {!r} as type: {!r}." + raise SerializationError(msg.format(data, data_type)) from err + return self._serialize(data, **kwargs) + + @classmethod + def _get_custom_serializers(cls, data_type, **kwargs): # pylint: disable=inconsistent-return-statements + custom_serializer = kwargs.get("basic_types_serializers", {}).get(data_type) + if custom_serializer: + return custom_serializer + if kwargs.get("is_xml", False): + return cls._xml_basic_types_serializers.get(data_type) + + @classmethod + def serialize_basic(cls, data, data_type, **kwargs): + """Serialize basic builting data type. + Serializes objects to str, int, float or bool. + + Possible kwargs: + - basic_types_serializers dict[str, callable] : If set, use the callable as serializer + - is_xml bool : If set, use xml_basic_types_serializers + + :param obj data: Object to be serialized. + :param str data_type: Type of object in the iterable. + :rtype: str, int, float, bool + :return: serialized object + """ + custom_serializer = cls._get_custom_serializers(data_type, **kwargs) + if custom_serializer: + return custom_serializer(data) + if data_type == "str": + return cls.serialize_unicode(data) + return eval(data_type)(data) # nosec # pylint: disable=eval-used + + @classmethod + def serialize_unicode(cls, data): + """Special handling for serializing unicode strings in Py2. + Encode to UTF-8 if unicode, otherwise handle as a str. + + :param str data: Object to be serialized. + :rtype: str + :return: serialized object + """ + try: # If I received an enum, return its value + return data.value + except AttributeError: + pass + + try: + if isinstance(data, unicode): # type: ignore + # Don't change it, JSON and XML ElementTree are totally able + # to serialize correctly u'' strings + return data + except NameError: + return str(data) + return str(data) + + def serialize_iter(self, data, iter_type, div=None, **kwargs): + """Serialize iterable. + + Supported kwargs: + - serialization_ctxt dict : The current entry of _attribute_map, or same format. + serialization_ctxt['type'] should be same as data_type. + - is_xml bool : If set, serialize as XML + + :param list data: Object to be serialized. + :param str iter_type: Type of object in the iterable. + :param str div: If set, this str will be used to combine the elements + in the iterable into a combined string. Default is 'None'. + Defaults to False. + :rtype: list, str + :return: serialized iterable + """ + if isinstance(data, str): + raise SerializationError("Refuse str type as a valid iter type.") + + serialization_ctxt = kwargs.get("serialization_ctxt", {}) + is_xml = kwargs.get("is_xml", False) + + serialized = [] + for d in data: + try: + serialized.append(self.serialize_data(d, iter_type, **kwargs)) + except ValueError as err: + if isinstance(err, SerializationError): + raise + serialized.append(None) + + if kwargs.get("do_quote", False): + serialized = ["" if s is None else quote(str(s), safe="") for s in serialized] + + if div: + serialized = ["" if s is None else str(s) for s in serialized] + serialized = div.join(serialized) + + if "xml" in serialization_ctxt or is_xml: + # XML serialization is more complicated + xml_desc = serialization_ctxt.get("xml", {}) + xml_name = xml_desc.get("name") + if not xml_name: + xml_name = serialization_ctxt["key"] + + # Create a wrap node if necessary (use the fact that Element and list have "append") + is_wrapped = xml_desc.get("wrapped", False) + node_name = xml_desc.get("itemsName", xml_name) + if is_wrapped: + final_result = _create_xml_node(xml_name, xml_desc.get("prefix", None), xml_desc.get("ns", None)) + else: + final_result = [] + # All list elements to "local_node" + for el in serialized: + if isinstance(el, ET.Element): + el_node = el + else: + el_node = _create_xml_node(node_name, xml_desc.get("prefix", None), xml_desc.get("ns", None)) + if el is not None: # Otherwise it writes "None" :-p + el_node.text = str(el) + final_result.append(el_node) + return final_result + return serialized + + def serialize_dict(self, attr, dict_type, **kwargs): + """Serialize a dictionary of objects. + + :param dict attr: Object to be serialized. + :param str dict_type: Type of object in the dictionary. + :rtype: dict + :return: serialized dictionary + """ + serialization_ctxt = kwargs.get("serialization_ctxt", {}) + serialized = {} + for key, value in attr.items(): + try: + serialized[self.serialize_unicode(key)] = self.serialize_data(value, dict_type, **kwargs) + except ValueError as err: + if isinstance(err, SerializationError): + raise + serialized[self.serialize_unicode(key)] = None + + if "xml" in serialization_ctxt: + # XML serialization is more complicated + xml_desc = serialization_ctxt["xml"] + xml_name = xml_desc["name"] + + final_result = _create_xml_node(xml_name, xml_desc.get("prefix", None), xml_desc.get("ns", None)) + for key, value in serialized.items(): + ET.SubElement(final_result, key).text = value + return final_result + + return serialized + + def serialize_object(self, attr, **kwargs): # pylint: disable=too-many-return-statements + """Serialize a generic object. + This will be handled as a dictionary. If object passed in is not + a basic type (str, int, float, dict, list) it will simply be + cast to str. + + :param dict attr: Object to be serialized. + :rtype: dict or str + :return: serialized object + """ + if attr is None: + return None + if isinstance(attr, ET.Element): + return attr + obj_type = type(attr) + if obj_type in self.basic_types: + return self.serialize_basic(attr, self.basic_types[obj_type], **kwargs) + if obj_type is _long_type: + return self.serialize_long(attr) + if obj_type is str: + return self.serialize_unicode(attr) + if obj_type is datetime.datetime: + return self.serialize_iso(attr) + if obj_type is datetime.date: + return self.serialize_date(attr) + if obj_type is datetime.time: + return self.serialize_time(attr) + if obj_type is datetime.timedelta: + return self.serialize_duration(attr) + if obj_type is decimal.Decimal: + return self.serialize_decimal(attr) + + # If it's a model or I know this dependency, serialize as a Model + if obj_type in self.dependencies.values() or isinstance(attr, Model): + return self._serialize(attr) + + if obj_type == dict: + serialized = {} + for key, value in attr.items(): + try: + serialized[self.serialize_unicode(key)] = self.serialize_object(value, **kwargs) + except ValueError: + serialized[self.serialize_unicode(key)] = None + return serialized + + if obj_type == list: + serialized = [] + for obj in attr: + try: + serialized.append(self.serialize_object(obj, **kwargs)) + except ValueError: + pass + return serialized + return str(attr) + + @staticmethod + def serialize_enum(attr, enum_obj=None): + try: + result = attr.value + except AttributeError: + result = attr + try: + enum_obj(result) # type: ignore + return result + except ValueError as exc: + for enum_value in enum_obj: # type: ignore + if enum_value.value.lower() == str(attr).lower(): + return enum_value.value + error = "{!r} is not valid value for enum {!r}" + raise SerializationError(error.format(attr, enum_obj)) from exc + + @staticmethod + def serialize_bytearray(attr, **kwargs): # pylint: disable=unused-argument + """Serialize bytearray into base-64 string. + + :param str attr: Object to be serialized. + :rtype: str + :return: serialized base64 + """ + return b64encode(attr).decode() + + @staticmethod + def serialize_base64(attr, **kwargs): # pylint: disable=unused-argument + """Serialize str into base-64 string. + + :param str attr: Object to be serialized. + :rtype: str + :return: serialized base64 + """ + encoded = b64encode(attr).decode("ascii") + return encoded.strip("=").replace("+", "-").replace("/", "_") + + @staticmethod + def serialize_decimal(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Decimal object to float. + + :param decimal attr: Object to be serialized. + :rtype: float + :return: serialized decimal + """ + return float(attr) + + @staticmethod + def serialize_long(attr, **kwargs): # pylint: disable=unused-argument + """Serialize long (Py2) or int (Py3). + + :param int attr: Object to be serialized. + :rtype: int/long + :return: serialized long + """ + return _long_type(attr) + + @staticmethod + def serialize_date(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Date object into ISO-8601 formatted string. + + :param Date attr: Object to be serialized. + :rtype: str + :return: serialized date + """ + if isinstance(attr, str): + attr = isodate.parse_date(attr) + t = "{:04}-{:02}-{:02}".format(attr.year, attr.month, attr.day) + return t + + @staticmethod + def serialize_time(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Time object into ISO-8601 formatted string. + + :param datetime.time attr: Object to be serialized. + :rtype: str + :return: serialized time + """ + if isinstance(attr, str): + attr = isodate.parse_time(attr) + t = "{:02}:{:02}:{:02}".format(attr.hour, attr.minute, attr.second) + if attr.microsecond: + t += ".{:02}".format(attr.microsecond) + return t + + @staticmethod + def serialize_duration(attr, **kwargs): # pylint: disable=unused-argument + """Serialize TimeDelta object into ISO-8601 formatted string. + + :param TimeDelta attr: Object to be serialized. + :rtype: str + :return: serialized duration + """ + if isinstance(attr, str): + attr = isodate.parse_duration(attr) + return isodate.duration_isoformat(attr) + + @staticmethod + def serialize_rfc(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Datetime object into RFC-1123 formatted string. + + :param Datetime attr: Object to be serialized. + :rtype: str + :raises TypeError: if format invalid. + :return: serialized rfc + """ + try: + if not attr.tzinfo: + _LOGGER.warning("Datetime with no tzinfo will be considered UTC.") + utc = attr.utctimetuple() + except AttributeError as exc: + raise TypeError("RFC1123 object must be valid Datetime object.") from exc + + return "{}, {:02} {} {:04} {:02}:{:02}:{:02} GMT".format( + Serializer.days[utc.tm_wday], + utc.tm_mday, + Serializer.months[utc.tm_mon], + utc.tm_year, + utc.tm_hour, + utc.tm_min, + utc.tm_sec, + ) + + @staticmethod + def serialize_iso(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Datetime object into ISO-8601 formatted string. + + :param Datetime attr: Object to be serialized. + :rtype: str + :raises SerializationError: if format invalid. + :return: serialized iso + """ + if isinstance(attr, str): + attr = isodate.parse_datetime(attr) + try: + if not attr.tzinfo: + _LOGGER.warning("Datetime with no tzinfo will be considered UTC.") + utc = attr.utctimetuple() + if utc.tm_year > 9999 or utc.tm_year < 1: + raise OverflowError("Hit max or min date") + + microseconds = str(attr.microsecond).rjust(6, "0").rstrip("0").ljust(3, "0") + if microseconds: + microseconds = "." + microseconds + date = "{:04}-{:02}-{:02}T{:02}:{:02}:{:02}".format( + utc.tm_year, utc.tm_mon, utc.tm_mday, utc.tm_hour, utc.tm_min, utc.tm_sec + ) + return date + microseconds + "Z" + except (ValueError, OverflowError) as err: + msg = "Unable to serialize datetime object." + raise SerializationError(msg) from err + except AttributeError as err: + msg = "ISO-8601 object must be valid Datetime object." + raise TypeError(msg) from err + + @staticmethod + def serialize_unix(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Datetime object into IntTime format. + This is represented as seconds. + + :param Datetime attr: Object to be serialized. + :rtype: int + :raises SerializationError: if format invalid + :return: serialied unix + """ + if isinstance(attr, int): + return attr + try: + if not attr.tzinfo: + _LOGGER.warning("Datetime with no tzinfo will be considered UTC.") + return int(calendar.timegm(attr.utctimetuple())) + except AttributeError as exc: + raise TypeError("Unix time object must be valid Datetime object.") from exc + + +def rest_key_extractor(attr, attr_desc, data): # pylint: disable=unused-argument + key = attr_desc["key"] + working_data = data + + while "." in key: + # Need the cast, as for some reasons "split" is typed as list[str | Any] + dict_keys = cast(List[str], _FLATTEN.split(key)) + if len(dict_keys) == 1: + key = _decode_attribute_map_key(dict_keys[0]) + break + working_key = _decode_attribute_map_key(dict_keys[0]) + working_data = working_data.get(working_key, data) + if working_data is None: + # If at any point while following flatten JSON path see None, it means + # that all properties under are None as well + return None + key = ".".join(dict_keys[1:]) + + return working_data.get(key) + + +def rest_key_case_insensitive_extractor( # pylint: disable=unused-argument, inconsistent-return-statements + attr, attr_desc, data +): + key = attr_desc["key"] + working_data = data + + while "." in key: + dict_keys = _FLATTEN.split(key) + if len(dict_keys) == 1: + key = _decode_attribute_map_key(dict_keys[0]) + break + working_key = _decode_attribute_map_key(dict_keys[0]) + working_data = attribute_key_case_insensitive_extractor(working_key, None, working_data) + if working_data is None: + # If at any point while following flatten JSON path see None, it means + # that all properties under are None as well + return None + key = ".".join(dict_keys[1:]) + + if working_data: + return attribute_key_case_insensitive_extractor(key, None, working_data) + + +def last_rest_key_extractor(attr, attr_desc, data): # pylint: disable=unused-argument + """Extract the attribute in "data" based on the last part of the JSON path key. + + :param str attr: The attribute to extract + :param dict attr_desc: The attribute description + :param dict data: The data to extract from + :rtype: object + :returns: The extracted attribute + """ + key = attr_desc["key"] + dict_keys = _FLATTEN.split(key) + return attribute_key_extractor(dict_keys[-1], None, data) + + +def last_rest_key_case_insensitive_extractor(attr, attr_desc, data): # pylint: disable=unused-argument + """Extract the attribute in "data" based on the last part of the JSON path key. + + This is the case insensitive version of "last_rest_key_extractor" + :param str attr: The attribute to extract + :param dict attr_desc: The attribute description + :param dict data: The data to extract from + :rtype: object + :returns: The extracted attribute + """ + key = attr_desc["key"] + dict_keys = _FLATTEN.split(key) + return attribute_key_case_insensitive_extractor(dict_keys[-1], None, data) + + +def attribute_key_extractor(attr, _, data): + return data.get(attr) + + +def attribute_key_case_insensitive_extractor(attr, _, data): + found_key = None + lower_attr = attr.lower() + for key in data: + if lower_attr == key.lower(): + found_key = key + break + + return data.get(found_key) + + +def _extract_name_from_internal_type(internal_type): + """Given an internal type XML description, extract correct XML name with namespace. + + :param dict internal_type: An model type + :rtype: tuple + :returns: A tuple XML name + namespace dict + """ + internal_type_xml_map = getattr(internal_type, "_xml_map", {}) + xml_name = internal_type_xml_map.get("name", internal_type.__name__) + xml_ns = internal_type_xml_map.get("ns", None) + if xml_ns: + xml_name = "{{{}}}{}".format(xml_ns, xml_name) + return xml_name + + +def xml_key_extractor(attr, attr_desc, data): # pylint: disable=unused-argument,too-many-return-statements + if isinstance(data, dict): + return None + + # Test if this model is XML ready first + if not isinstance(data, ET.Element): + return None + + xml_desc = attr_desc.get("xml", {}) + xml_name = xml_desc.get("name", attr_desc["key"]) + + # Look for a children + is_iter_type = attr_desc["type"].startswith("[") + is_wrapped = xml_desc.get("wrapped", False) + internal_type = attr_desc.get("internalType", None) + internal_type_xml_map = getattr(internal_type, "_xml_map", {}) + + # Integrate namespace if necessary + xml_ns = xml_desc.get("ns", internal_type_xml_map.get("ns", None)) + if xml_ns: + xml_name = "{{{}}}{}".format(xml_ns, xml_name) + + # If it's an attribute, that's simple + if xml_desc.get("attr", False): + return data.get(xml_name) + + # If it's x-ms-text, that's simple too + if xml_desc.get("text", False): + return data.text + + # Scenario where I take the local name: + # - Wrapped node + # - Internal type is an enum (considered basic types) + # - Internal type has no XML/Name node + if is_wrapped or (internal_type and (issubclass(internal_type, Enum) or "name" not in internal_type_xml_map)): + children = data.findall(xml_name) + # If internal type has a local name and it's not a list, I use that name + elif not is_iter_type and internal_type and "name" in internal_type_xml_map: + xml_name = _extract_name_from_internal_type(internal_type) + children = data.findall(xml_name) + # That's an array + else: + if internal_type: # Complex type, ignore itemsName and use the complex type name + items_name = _extract_name_from_internal_type(internal_type) + else: + items_name = xml_desc.get("itemsName", xml_name) + children = data.findall(items_name) + + if len(children) == 0: + if is_iter_type: + if is_wrapped: + return None # is_wrapped no node, we want None + return [] # not wrapped, assume empty list + return None # Assume it's not there, maybe an optional node. + + # If is_iter_type and not wrapped, return all found children + if is_iter_type: + if not is_wrapped: + return children + # Iter and wrapped, should have found one node only (the wrap one) + if len(children) != 1: + raise DeserializationError( + "Tried to deserialize an array not wrapped, and found several nodes '{}'. Maybe you should declare this array as wrapped?".format( + xml_name + ) + ) + return list(children[0]) # Might be empty list and that's ok. + + # Here it's not a itertype, we should have found one element only or empty + if len(children) > 1: + raise DeserializationError("Find several XML '{}' where it was not expected".format(xml_name)) + return children[0] + + +class Deserializer: + """Response object model deserializer. + + :param dict classes: Class type dictionary for deserializing complex types. + :ivar list key_extractors: Ordered list of extractors to be used by this deserializer. + """ + + basic_types = {str: "str", int: "int", bool: "bool", float: "float"} + + valid_date = re.compile(r"\d{4}[-]\d{2}[-]\d{2}T\d{2}:\d{2}:\d{2}\.?\d*Z?[-+]?[\d{2}]?:?[\d{2}]?") + + def __init__(self, classes: Optional[Mapping[str, type]] = None) -> None: + self.deserialize_type = { + "iso-8601": Deserializer.deserialize_iso, + "rfc-1123": Deserializer.deserialize_rfc, + "unix-time": Deserializer.deserialize_unix, + "duration": Deserializer.deserialize_duration, + "date": Deserializer.deserialize_date, + "time": Deserializer.deserialize_time, + "decimal": Deserializer.deserialize_decimal, + "long": Deserializer.deserialize_long, + "bytearray": Deserializer.deserialize_bytearray, + "base64": Deserializer.deserialize_base64, + "object": self.deserialize_object, + "[]": self.deserialize_iter, + "{}": self.deserialize_dict, + } + self.deserialize_expected_types = { + "duration": (isodate.Duration, datetime.timedelta), + "iso-8601": (datetime.datetime), + } + self.dependencies: Dict[str, type] = dict(classes) if classes else {} + self.key_extractors = [rest_key_extractor, xml_key_extractor] + # Additional properties only works if the "rest_key_extractor" is used to + # extract the keys. Making it to work whatever the key extractor is too much + # complicated, with no real scenario for now. + # So adding a flag to disable additional properties detection. This flag should be + # used if your expect the deserialization to NOT come from a JSON REST syntax. + # Otherwise, result are unexpected + self.additional_properties_detection = True + + def __call__(self, target_obj, response_data, content_type=None): + """Call the deserializer to process a REST response. + + :param str target_obj: Target data type to deserialize to. + :param requests.Response response_data: REST response object. + :param str content_type: Swagger "produces" if available. + :raises DeserializationError: if deserialization fails. + :return: Deserialized object. + :rtype: object + """ + data = self._unpack_content(response_data, content_type) + return self._deserialize(target_obj, data) + + def _deserialize(self, target_obj, data): # pylint: disable=inconsistent-return-statements + """Call the deserializer on a model. + + Data needs to be already deserialized as JSON or XML ElementTree + + :param str target_obj: Target data type to deserialize to. + :param object data: Object to deserialize. + :raises DeserializationError: if deserialization fails. + :return: Deserialized object. + :rtype: object + """ + # This is already a model, go recursive just in case + if hasattr(data, "_attribute_map"): + constants = [name for name, config in getattr(data, "_validation", {}).items() if config.get("constant")] + try: + for attr, mapconfig in data._attribute_map.items(): # pylint: disable=protected-access + if attr in constants: + continue + value = getattr(data, attr) + if value is None: + continue + local_type = mapconfig["type"] + internal_data_type = local_type.strip("[]{}") + if internal_data_type not in self.dependencies or isinstance(internal_data_type, Enum): + continue + setattr(data, attr, self._deserialize(local_type, value)) + return data + except AttributeError: + return + + response, class_name = self._classify_target(target_obj, data) + + if isinstance(response, str): + return self.deserialize_data(data, response) + if isinstance(response, type) and issubclass(response, Enum): + return self.deserialize_enum(data, response) + + if data is None or data is CoreNull: + return data + try: + attributes = response._attribute_map # type: ignore # pylint: disable=protected-access + d_attrs = {} + for attr, attr_desc in attributes.items(): + # Check empty string. If it's not empty, someone has a real "additionalProperties"... + if attr == "additional_properties" and attr_desc["key"] == "": + continue + raw_value = None + # Enhance attr_desc with some dynamic data + attr_desc = attr_desc.copy() # Do a copy, do not change the real one + internal_data_type = attr_desc["type"].strip("[]{}") + if internal_data_type in self.dependencies: + attr_desc["internalType"] = self.dependencies[internal_data_type] + + for key_extractor in self.key_extractors: + found_value = key_extractor(attr, attr_desc, data) + if found_value is not None: + if raw_value is not None and raw_value != found_value: + msg = ( + "Ignoring extracted value '%s' from %s for key '%s'" + " (duplicate extraction, follow extractors order)" + ) + _LOGGER.warning(msg, found_value, key_extractor, attr) + continue + raw_value = found_value + + value = self.deserialize_data(raw_value, attr_desc["type"]) + d_attrs[attr] = value + except (AttributeError, TypeError, KeyError) as err: + msg = "Unable to deserialize to object: " + class_name # type: ignore + raise DeserializationError(msg) from err + additional_properties = self._build_additional_properties(attributes, data) + return self._instantiate_model(response, d_attrs, additional_properties) + + def _build_additional_properties(self, attribute_map, data): + if not self.additional_properties_detection: + return None + if "additional_properties" in attribute_map and attribute_map.get("additional_properties", {}).get("key") != "": + # Check empty string. If it's not empty, someone has a real "additionalProperties" + return None + if isinstance(data, ET.Element): + data = {el.tag: el.text for el in data} + + known_keys = { + _decode_attribute_map_key(_FLATTEN.split(desc["key"])[0]) + for desc in attribute_map.values() + if desc["key"] != "" + } + present_keys = set(data.keys()) + missing_keys = present_keys - known_keys + return {key: data[key] for key in missing_keys} + + def _classify_target(self, target, data): + """Check to see whether the deserialization target object can + be classified into a subclass. + Once classification has been determined, initialize object. + + :param str target: The target object type to deserialize to. + :param str/dict data: The response data to deserialize. + :return: The classified target object and its class name. + :rtype: tuple + """ + if target is None: + return None, None + + if isinstance(target, str): + try: + target = self.dependencies[target] + except KeyError: + return target, target + + try: + target = target._classify(data, self.dependencies) # type: ignore # pylint: disable=protected-access + except AttributeError: + pass # Target is not a Model, no classify + return target, target.__class__.__name__ # type: ignore + + def failsafe_deserialize(self, target_obj, data, content_type=None): + """Ignores any errors encountered in deserialization, + and falls back to not deserializing the object. Recommended + for use in error deserialization, as we want to return the + HttpResponseError to users, and not have them deal with + a deserialization error. + + :param str target_obj: The target object type to deserialize to. + :param str/dict data: The response data to deserialize. + :param str content_type: Swagger "produces" if available. + :return: Deserialized object. + :rtype: object + """ + try: + return self(target_obj, data, content_type=content_type) + except: # pylint: disable=bare-except + _LOGGER.debug( + "Ran into a deserialization error. Ignoring since this is failsafe deserialization", exc_info=True + ) + return None + + @staticmethod + def _unpack_content(raw_data, content_type=None): + """Extract the correct structure for deserialization. + + If raw_data is a PipelineResponse, try to extract the result of RawDeserializer. + if we can't, raise. Your Pipeline should have a RawDeserializer. + + If not a pipeline response and raw_data is bytes or string, use content-type + to decode it. If no content-type, try JSON. + + If raw_data is something else, bypass all logic and return it directly. + + :param obj raw_data: Data to be processed. + :param str content_type: How to parse if raw_data is a string/bytes. + :raises JSONDecodeError: If JSON is requested and parsing is impossible. + :raises UnicodeDecodeError: If bytes is not UTF8 + :rtype: object + :return: Unpacked content. + """ + # Assume this is enough to detect a Pipeline Response without importing it + context = getattr(raw_data, "context", {}) + if context: + if RawDeserializer.CONTEXT_NAME in context: + return context[RawDeserializer.CONTEXT_NAME] + raise ValueError("This pipeline didn't have the RawDeserializer policy; can't deserialize") + + # Assume this is enough to recognize universal_http.ClientResponse without importing it + if hasattr(raw_data, "body"): + return RawDeserializer.deserialize_from_http_generics(raw_data.text(), raw_data.headers) + + # Assume this enough to recognize requests.Response without importing it. + if hasattr(raw_data, "_content_consumed"): + return RawDeserializer.deserialize_from_http_generics(raw_data.text, raw_data.headers) + + if isinstance(raw_data, (str, bytes)) or hasattr(raw_data, "read"): + return RawDeserializer.deserialize_from_text(raw_data, content_type) # type: ignore + return raw_data + + def _instantiate_model(self, response, attrs, additional_properties=None): + """Instantiate a response model passing in deserialized args. + + :param Response response: The response model class. + :param dict attrs: The deserialized response attributes. + :param dict additional_properties: Additional properties to be set. + :rtype: Response + :return: The instantiated response model. + """ + if callable(response): + subtype = getattr(response, "_subtype_map", {}) + try: + readonly = [ + k + for k, v in response._validation.items() # pylint: disable=protected-access # type: ignore + if v.get("readonly") + ] + const = [ + k + for k, v in response._validation.items() # pylint: disable=protected-access # type: ignore + if v.get("constant") + ] + kwargs = {k: v for k, v in attrs.items() if k not in subtype and k not in readonly + const} + response_obj = response(**kwargs) + for attr in readonly: + setattr(response_obj, attr, attrs.get(attr)) + if additional_properties: + response_obj.additional_properties = additional_properties # type: ignore + return response_obj + except TypeError as err: + msg = "Unable to deserialize {} into model {}. ".format(kwargs, response) # type: ignore + raise DeserializationError(msg + str(err)) from err + else: + try: + for attr, value in attrs.items(): + setattr(response, attr, value) + return response + except Exception as exp: + msg = "Unable to populate response model. " + msg += "Type: {}, Error: {}".format(type(response), exp) + raise DeserializationError(msg) from exp + + def deserialize_data(self, data, data_type): # pylint: disable=too-many-return-statements + """Process data for deserialization according to data type. + + :param str data: The response string to be deserialized. + :param str data_type: The type to deserialize to. + :raises DeserializationError: if deserialization fails. + :return: Deserialized object. + :rtype: object + """ + if data is None: + return data + + try: + if not data_type: + return data + if data_type in self.basic_types.values(): + return self.deserialize_basic(data, data_type) + if data_type in self.deserialize_type: + if isinstance(data, self.deserialize_expected_types.get(data_type, tuple())): + return data + + is_a_text_parsing_type = lambda x: x not in [ # pylint: disable=unnecessary-lambda-assignment + "object", + "[]", + r"{}", + ] + if isinstance(data, ET.Element) and is_a_text_parsing_type(data_type) and not data.text: + return None + data_val = self.deserialize_type[data_type](data) + return data_val + + iter_type = data_type[0] + data_type[-1] + if iter_type in self.deserialize_type: + return self.deserialize_type[iter_type](data, data_type[1:-1]) + + obj_type = self.dependencies[data_type] + if issubclass(obj_type, Enum): + if isinstance(data, ET.Element): + data = data.text + return self.deserialize_enum(data, obj_type) + + except (ValueError, TypeError, AttributeError) as err: + msg = "Unable to deserialize response data." + msg += " Data: {}, {}".format(data, data_type) + raise DeserializationError(msg) from err + return self._deserialize(obj_type, data) + + def deserialize_iter(self, attr, iter_type): + """Deserialize an iterable. + + :param list attr: Iterable to be deserialized. + :param str iter_type: The type of object in the iterable. + :return: Deserialized iterable. + :rtype: list + """ + if attr is None: + return None + if isinstance(attr, ET.Element): # If I receive an element here, get the children + attr = list(attr) + if not isinstance(attr, (list, set)): + raise DeserializationError("Cannot deserialize as [{}] an object of type {}".format(iter_type, type(attr))) + return [self.deserialize_data(a, iter_type) for a in attr] + + def deserialize_dict(self, attr, dict_type): + """Deserialize a dictionary. + + :param dict/list attr: Dictionary to be deserialized. Also accepts + a list of key, value pairs. + :param str dict_type: The object type of the items in the dictionary. + :return: Deserialized dictionary. + :rtype: dict + """ + if isinstance(attr, list): + return {x["key"]: self.deserialize_data(x["value"], dict_type) for x in attr} + + if isinstance(attr, ET.Element): + # Transform value into {"Key": "value"} + attr = {el.tag: el.text for el in attr} + return {k: self.deserialize_data(v, dict_type) for k, v in attr.items()} + + def deserialize_object(self, attr, **kwargs): # pylint: disable=too-many-return-statements + """Deserialize a generic object. + This will be handled as a dictionary. + + :param dict attr: Dictionary to be deserialized. + :return: Deserialized object. + :rtype: dict + :raises TypeError: if non-builtin datatype encountered. + """ + if attr is None: + return None + if isinstance(attr, ET.Element): + # Do no recurse on XML, just return the tree as-is + return attr + if isinstance(attr, str): + return self.deserialize_basic(attr, "str") + obj_type = type(attr) + if obj_type in self.basic_types: + return self.deserialize_basic(attr, self.basic_types[obj_type]) + if obj_type is _long_type: + return self.deserialize_long(attr) + + if obj_type == dict: + deserialized = {} + for key, value in attr.items(): + try: + deserialized[key] = self.deserialize_object(value, **kwargs) + except ValueError: + deserialized[key] = None + return deserialized + + if obj_type == list: + deserialized = [] + for obj in attr: + try: + deserialized.append(self.deserialize_object(obj, **kwargs)) + except ValueError: + pass + return deserialized + + error = "Cannot deserialize generic object with type: " + raise TypeError(error + str(obj_type)) + + def deserialize_basic(self, attr, data_type): # pylint: disable=too-many-return-statements + """Deserialize basic builtin data type from string. + Will attempt to convert to str, int, float and bool. + This function will also accept '1', '0', 'true' and 'false' as + valid bool values. + + :param str attr: response string to be deserialized. + :param str data_type: deserialization data type. + :return: Deserialized basic type. + :rtype: str, int, float or bool + :raises TypeError: if string format is not valid. + """ + # If we're here, data is supposed to be a basic type. + # If it's still an XML node, take the text + if isinstance(attr, ET.Element): + attr = attr.text + if not attr: + if data_type == "str": + # None or '', node is empty string. + return "" + # None or '', node with a strong type is None. + # Don't try to model "empty bool" or "empty int" + return None + + if data_type == "bool": + if attr in [True, False, 1, 0]: + return bool(attr) + if isinstance(attr, str): + if attr.lower() in ["true", "1"]: + return True + if attr.lower() in ["false", "0"]: + return False + raise TypeError("Invalid boolean value: {}".format(attr)) + + if data_type == "str": + return self.deserialize_unicode(attr) + return eval(data_type)(attr) # nosec # pylint: disable=eval-used + + @staticmethod + def deserialize_unicode(data): + """Preserve unicode objects in Python 2, otherwise return data + as a string. + + :param str data: response string to be deserialized. + :return: Deserialized string. + :rtype: str or unicode + """ + # We might be here because we have an enum modeled as string, + # and we try to deserialize a partial dict with enum inside + if isinstance(data, Enum): + return data + + # Consider this is real string + try: + if isinstance(data, unicode): # type: ignore + return data + except NameError: + return str(data) + return str(data) + + @staticmethod + def deserialize_enum(data, enum_obj): + """Deserialize string into enum object. + + If the string is not a valid enum value it will be returned as-is + and a warning will be logged. + + :param str data: Response string to be deserialized. If this value is + None or invalid it will be returned as-is. + :param Enum enum_obj: Enum object to deserialize to. + :return: Deserialized enum object. + :rtype: Enum + """ + if isinstance(data, enum_obj) or data is None: + return data + if isinstance(data, Enum): + data = data.value + if isinstance(data, int): + # Workaround. We might consider remove it in the future. + try: + return list(enum_obj.__members__.values())[data] + except IndexError as exc: + error = "{!r} is not a valid index for enum {!r}" + raise DeserializationError(error.format(data, enum_obj)) from exc + try: + return enum_obj(str(data)) + except ValueError: + for enum_value in enum_obj: + if enum_value.value.lower() == str(data).lower(): + return enum_value + # We don't fail anymore for unknown value, we deserialize as a string + _LOGGER.warning("Deserializer is not able to find %s as valid enum in %s", data, enum_obj) + return Deserializer.deserialize_unicode(data) + + @staticmethod + def deserialize_bytearray(attr): + """Deserialize string into bytearray. + + :param str attr: response string to be deserialized. + :return: Deserialized bytearray + :rtype: bytearray + :raises TypeError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + return bytearray(b64decode(attr)) # type: ignore + + @staticmethod + def deserialize_base64(attr): + """Deserialize base64 encoded string into string. + + :param str attr: response string to be deserialized. + :return: Deserialized base64 string + :rtype: bytearray + :raises TypeError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + padding = "=" * (3 - (len(attr) + 3) % 4) # type: ignore + attr = attr + padding # type: ignore + encoded = attr.replace("-", "+").replace("_", "/") + return b64decode(encoded) + + @staticmethod + def deserialize_decimal(attr): + """Deserialize string into Decimal object. + + :param str attr: response string to be deserialized. + :return: Deserialized decimal + :raises DeserializationError: if string format invalid. + :rtype: decimal + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + return decimal.Decimal(str(attr)) # type: ignore + except decimal.DecimalException as err: + msg = "Invalid decimal {}".format(attr) + raise DeserializationError(msg) from err + + @staticmethod + def deserialize_long(attr): + """Deserialize string into long (Py2) or int (Py3). + + :param str attr: response string to be deserialized. + :return: Deserialized int + :rtype: long or int + :raises ValueError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + return _long_type(attr) # type: ignore + + @staticmethod + def deserialize_duration(attr): + """Deserialize ISO-8601 formatted string into TimeDelta object. + + :param str attr: response string to be deserialized. + :return: Deserialized duration + :rtype: TimeDelta + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + duration = isodate.parse_duration(attr) + except (ValueError, OverflowError, AttributeError) as err: + msg = "Cannot deserialize duration object." + raise DeserializationError(msg) from err + return duration + + @staticmethod + def deserialize_date(attr): + """Deserialize ISO-8601 formatted string into Date object. + + :param str attr: response string to be deserialized. + :return: Deserialized date + :rtype: Date + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + if re.search(r"[^\W\d_]", attr, re.I + re.U): # type: ignore + raise DeserializationError("Date must have only digits and -. Received: %s" % attr) + # This must NOT use defaultmonth/defaultday. Using None ensure this raises an exception. + return isodate.parse_date(attr, defaultmonth=0, defaultday=0) + + @staticmethod + def deserialize_time(attr): + """Deserialize ISO-8601 formatted string into time object. + + :param str attr: response string to be deserialized. + :return: Deserialized time + :rtype: datetime.time + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + if re.search(r"[^\W\d_]", attr, re.I + re.U): # type: ignore + raise DeserializationError("Date must have only digits and -. Received: %s" % attr) + return isodate.parse_time(attr) + + @staticmethod + def deserialize_rfc(attr): + """Deserialize RFC-1123 formatted string into Datetime object. + + :param str attr: response string to be deserialized. + :return: Deserialized RFC datetime + :rtype: Datetime + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + parsed_date = email.utils.parsedate_tz(attr) # type: ignore + date_obj = datetime.datetime( + *parsed_date[:6], tzinfo=datetime.timezone(datetime.timedelta(minutes=(parsed_date[9] or 0) / 60)) + ) + if not date_obj.tzinfo: + date_obj = date_obj.astimezone(tz=TZ_UTC) + except ValueError as err: + msg = "Cannot deserialize to rfc datetime object." + raise DeserializationError(msg) from err + return date_obj + + @staticmethod + def deserialize_iso(attr): + """Deserialize ISO-8601 formatted string into Datetime object. + + :param str attr: response string to be deserialized. + :return: Deserialized ISO datetime + :rtype: Datetime + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + attr = attr.upper() # type: ignore + match = Deserializer.valid_date.match(attr) + if not match: + raise ValueError("Invalid datetime string: " + attr) + + check_decimal = attr.split(".") + if len(check_decimal) > 1: + decimal_str = "" + for digit in check_decimal[1]: + if digit.isdigit(): + decimal_str += digit + else: + break + if len(decimal_str) > 6: + attr = attr.replace(decimal_str, decimal_str[0:6]) + + date_obj = isodate.parse_datetime(attr) + test_utc = date_obj.utctimetuple() + if test_utc.tm_year > 9999 or test_utc.tm_year < 1: + raise OverflowError("Hit max or min date") + except (ValueError, OverflowError, AttributeError) as err: + msg = "Cannot deserialize datetime object." + raise DeserializationError(msg) from err + return date_obj + + @staticmethod + def deserialize_unix(attr): + """Serialize Datetime object into IntTime format. + This is represented as seconds. + + :param int attr: Object to be serialized. + :return: Deserialized datetime + :rtype: Datetime + :raises DeserializationError: if format invalid + """ + if isinstance(attr, ET.Element): + attr = int(attr.text) # type: ignore + try: + attr = int(attr) + date_obj = datetime.datetime.fromtimestamp(attr, TZ_UTC) + except ValueError as err: + msg = "Cannot deserialize to unix datetime object." + raise DeserializationError(msg) from err + return date_obj diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/MergePatchJsonVersionTolerant/mergepatchjsonversiontolerant/_utils/utils.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/MergePatchJsonVersionTolerant/mergepatchjsonversiontolerant/_utils/utils.py new file mode 100644 index 00000000000..39b612f39a9 --- /dev/null +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/MergePatchJsonVersionTolerant/mergepatchjsonversiontolerant/_utils/utils.py @@ -0,0 +1,25 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from abc import ABC +from typing import Generic, TYPE_CHECKING, TypeVar + +if TYPE_CHECKING: + from .serialization import Deserializer, Serializer + + +TClient = TypeVar("TClient") +TConfig = TypeVar("TConfig") + + +class ClientMixinABC(ABC, Generic[TClient, TConfig]): + """DO NOT use this class. It is for internal typing use only.""" + + _client: TClient + _config: TConfig + _serialize: "Serializer" + _deserialize: "Deserializer" diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/MergePatchJsonVersionTolerant/mergepatchjsonversiontolerant/_vendor.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/MergePatchJsonVersionTolerant/mergepatchjsonversiontolerant/_vendor.py deleted file mode 100644 index 8295b4aa6c6..00000000000 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/MergePatchJsonVersionTolerant/mergepatchjsonversiontolerant/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) AutoRest Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import MergePatchJsonClientConfiguration - -if TYPE_CHECKING: - from azure.core import PipelineClient - - from ._serialization import Deserializer, Serializer - - -class MergePatchJsonClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "PipelineClient" - _config: MergePatchJsonClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/MergePatchJsonVersionTolerant/mergepatchjsonversiontolerant/aio/_client.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/MergePatchJsonVersionTolerant/mergepatchjsonversiontolerant/aio/_client.py index 713c2d94510..535a9ca380f 100644 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/MergePatchJsonVersionTolerant/mergepatchjsonversiontolerant/aio/_client.py +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/MergePatchJsonVersionTolerant/mergepatchjsonversiontolerant/aio/_client.py @@ -14,7 +14,7 @@ from azure.core.pipeline import policies from azure.core.rest import AsyncHttpResponse, HttpRequest -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import MergePatchJsonClientConfiguration from ._operations import MergePatchJsonClientOperationsMixin diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/MergePatchJsonVersionTolerant/mergepatchjsonversiontolerant/aio/_operations/_operations.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/MergePatchJsonVersionTolerant/mergepatchjsonversiontolerant/aio/_operations/_operations.py index 46a0f6158da..bdcd8a5eb8b 100644 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/MergePatchJsonVersionTolerant/mergepatchjsonversiontolerant/aio/_operations/_operations.py +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/MergePatchJsonVersionTolerant/mergepatchjsonversiontolerant/aio/_operations/_operations.py @@ -9,6 +9,7 @@ from collections.abc import MutableMapping from typing import Any, Callable, Dict, Optional, TypeVar +from azure.core import AsyncPipelineClient from azure.core.exceptions import ( ClientAuthenticationError, HttpResponseError, @@ -23,14 +24,15 @@ from azure.core.utils import case_insensitive_dict from ..._operations._operations import build_merge_patch_json_patch_single_request -from .._vendor import MergePatchJsonClientMixinABC +from ..._utils.utils import ClientMixinABC +from .._configuration import MergePatchJsonClientConfiguration JSON = MutableMapping[str, Any] T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, AsyncHttpResponse], T, Dict[str, Any]], Any]] -class MergePatchJsonClientOperationsMixin(MergePatchJsonClientMixinABC): +class MergePatchJsonClientOperationsMixin(ClientMixinABC[AsyncPipelineClient, MergePatchJsonClientConfiguration]): @distributed_trace_async async def patch_single(self, body: JSON, **kwargs: Any) -> None: diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/MergePatchJsonVersionTolerant/mergepatchjsonversiontolerant/aio/_vendor.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/MergePatchJsonVersionTolerant/mergepatchjsonversiontolerant/aio/_vendor.py deleted file mode 100644 index ef83da259a4..00000000000 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/MergePatchJsonVersionTolerant/mergepatchjsonversiontolerant/aio/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) AutoRest Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import MergePatchJsonClientConfiguration - -if TYPE_CHECKING: - from azure.core import AsyncPipelineClient - - from .._serialization import Deserializer, Serializer - - -class MergePatchJsonClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "AsyncPipelineClient" - _config: MergePatchJsonClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ModelFlatteningVersionTolerant/modelflatteningversiontolerant/_client.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ModelFlatteningVersionTolerant/modelflatteningversiontolerant/_client.py index 9f288126f80..1ba4d7f684e 100644 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ModelFlatteningVersionTolerant/modelflatteningversiontolerant/_client.py +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ModelFlatteningVersionTolerant/modelflatteningversiontolerant/_client.py @@ -16,7 +16,7 @@ from ._configuration import AutoRestResourceFlatteningTestServiceConfiguration from ._operations import AutoRestResourceFlatteningTestServiceOperationsMixin -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer class AutoRestResourceFlatteningTestService( diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ModelFlatteningVersionTolerant/modelflatteningversiontolerant/_operations/_operations.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ModelFlatteningVersionTolerant/modelflatteningversiontolerant/_operations/_operations.py index 95af714d1b7..127de4032b2 100644 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ModelFlatteningVersionTolerant/modelflatteningversiontolerant/_operations/_operations.py +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ModelFlatteningVersionTolerant/modelflatteningversiontolerant/_operations/_operations.py @@ -10,6 +10,7 @@ from io import IOBase from typing import Any, Callable, Dict, IO, List, Optional, TypeVar, Union, cast, overload +from azure.core import PipelineClient from azure.core.exceptions import ( ClientAuthenticationError, HttpResponseError, @@ -23,8 +24,9 @@ from azure.core.tracing.decorator import distributed_trace from azure.core.utils import case_insensitive_dict -from .._serialization import Serializer -from .._vendor import AutoRestResourceFlatteningTestServiceMixinABC +from .._configuration import AutoRestResourceFlatteningTestServiceConfiguration +from .._utils.serialization import Serializer +from .._utils.utils import ClientMixinABC JSON = MutableMapping[str, Any] T = TypeVar("T") @@ -237,7 +239,7 @@ def build_auto_rest_resource_flattening_test_service_put_simple_product_with_gro class AutoRestResourceFlatteningTestServiceOperationsMixin( # pylint: disable=name-too-long - AutoRestResourceFlatteningTestServiceMixinABC + ClientMixinABC[PipelineClient, AutoRestResourceFlatteningTestServiceConfiguration] ): @overload diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ModelFlatteningVersionTolerant/modelflatteningversiontolerant/_utils/__init__.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ModelFlatteningVersionTolerant/modelflatteningversiontolerant/_utils/__init__.py new file mode 100644 index 00000000000..0af9b28f660 --- /dev/null +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ModelFlatteningVersionTolerant/modelflatteningversiontolerant/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ModelFlatteningVersionTolerant/modelflatteningversiontolerant/_utils/serialization.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ModelFlatteningVersionTolerant/modelflatteningversiontolerant/_utils/serialization.py new file mode 100644 index 00000000000..f5187701d7b --- /dev/null +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ModelFlatteningVersionTolerant/modelflatteningversiontolerant/_utils/serialization.py @@ -0,0 +1,2032 @@ +# pylint: disable=line-too-long,useless-suppression,too-many-lines +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +# pyright: reportUnnecessaryTypeIgnoreComment=false + +from base64 import b64decode, b64encode +import calendar +import datetime +import decimal +import email +from enum import Enum +import json +import logging +import re +import sys +import codecs +from typing import ( + Dict, + Any, + cast, + Optional, + Union, + AnyStr, + IO, + Mapping, + Callable, + MutableMapping, + List, +) + +try: + from urllib import quote # type: ignore +except ImportError: + from urllib.parse import quote +import xml.etree.ElementTree as ET + +import isodate # type: ignore +from typing_extensions import Self + +from azure.core.exceptions import DeserializationError, SerializationError +from azure.core.serialization import NULL as CoreNull + +_BOM = codecs.BOM_UTF8.decode(encoding="utf-8") + +JSON = MutableMapping[str, Any] + + +class RawDeserializer: + + # Accept "text" because we're open minded people... + JSON_REGEXP = re.compile(r"^(application|text)/([a-z+.]+\+)?json$") + + # Name used in context + CONTEXT_NAME = "deserialized_data" + + @classmethod + def deserialize_from_text(cls, data: Optional[Union[AnyStr, IO]], content_type: Optional[str] = None) -> Any: + """Decode data according to content-type. + + Accept a stream of data as well, but will be load at once in memory for now. + + If no content-type, will return the string version (not bytes, not stream) + + :param data: Input, could be bytes or stream (will be decoded with UTF8) or text + :type data: str or bytes or IO + :param str content_type: The content type. + :return: The deserialized data. + :rtype: object + """ + if hasattr(data, "read"): + # Assume a stream + data = cast(IO, data).read() + + if isinstance(data, bytes): + data_as_str = data.decode(encoding="utf-8-sig") + else: + # Explain to mypy the correct type. + data_as_str = cast(str, data) + + # Remove Byte Order Mark if present in string + data_as_str = data_as_str.lstrip(_BOM) + + if content_type is None: + return data + + if cls.JSON_REGEXP.match(content_type): + try: + return json.loads(data_as_str) + except ValueError as err: + raise DeserializationError("JSON is invalid: {}".format(err), err) from err + elif "xml" in (content_type or []): + try: + + try: + if isinstance(data, unicode): # type: ignore + # If I'm Python 2.7 and unicode XML will scream if I try a "fromstring" on unicode string + data_as_str = data_as_str.encode(encoding="utf-8") # type: ignore + except NameError: + pass + + return ET.fromstring(data_as_str) # nosec + except ET.ParseError as err: + # It might be because the server has an issue, and returned JSON with + # content-type XML.... + # So let's try a JSON load, and if it's still broken + # let's flow the initial exception + def _json_attemp(data): + try: + return True, json.loads(data) + except ValueError: + return False, None # Don't care about this one + + success, json_result = _json_attemp(data) + if success: + return json_result + # If i'm here, it's not JSON, it's not XML, let's scream + # and raise the last context in this block (the XML exception) + # The function hack is because Py2.7 messes up with exception + # context otherwise. + _LOGGER.critical("Wasn't XML not JSON, failing") + raise DeserializationError("XML is invalid") from err + elif content_type.startswith("text/"): + return data_as_str + raise DeserializationError("Cannot deserialize content-type: {}".format(content_type)) + + @classmethod + def deserialize_from_http_generics(cls, body_bytes: Optional[Union[AnyStr, IO]], headers: Mapping) -> Any: + """Deserialize from HTTP response. + + Use bytes and headers to NOT use any requests/aiohttp or whatever + specific implementation. + Headers will tested for "content-type" + + :param bytes body_bytes: The body of the response. + :param dict headers: The headers of the response. + :returns: The deserialized data. + :rtype: object + """ + # Try to use content-type from headers if available + content_type = None + if "content-type" in headers: + content_type = headers["content-type"].split(";")[0].strip().lower() + # Ouch, this server did not declare what it sent... + # Let's guess it's JSON... + # Also, since Autorest was considering that an empty body was a valid JSON, + # need that test as well.... + else: + content_type = "application/json" + + if body_bytes: + return cls.deserialize_from_text(body_bytes, content_type) + return None + + +_LOGGER = logging.getLogger(__name__) + +try: + _long_type = long # type: ignore +except NameError: + _long_type = int + +TZ_UTC = datetime.timezone.utc + +_FLATTEN = re.compile(r"(? None: + self.additional_properties: Optional[Dict[str, Any]] = {} + for k in kwargs: # pylint: disable=consider-using-dict-items + if k not in self._attribute_map: + _LOGGER.warning("%s is not a known attribute of class %s and will be ignored", k, self.__class__) + elif k in self._validation and self._validation[k].get("readonly", False): + _LOGGER.warning("Readonly attribute %s will be ignored in class %s", k, self.__class__) + else: + setattr(self, k, kwargs[k]) + + def __eq__(self, other: Any) -> bool: + """Compare objects by comparing all attributes. + + :param object other: The object to compare + :returns: True if objects are equal + :rtype: bool + """ + if isinstance(other, self.__class__): + return self.__dict__ == other.__dict__ + return False + + def __ne__(self, other: Any) -> bool: + """Compare objects by comparing all attributes. + + :param object other: The object to compare + :returns: True if objects are not equal + :rtype: bool + """ + return not self.__eq__(other) + + def __str__(self) -> str: + return str(self.__dict__) + + @classmethod + def enable_additional_properties_sending(cls) -> None: + cls._attribute_map["additional_properties"] = {"key": "", "type": "{object}"} + + @classmethod + def is_xml_model(cls) -> bool: + try: + cls._xml_map # type: ignore + except AttributeError: + return False + return True + + @classmethod + def _create_xml_node(cls): + """Create XML node. + + :returns: The XML node + :rtype: xml.etree.ElementTree.Element + """ + try: + xml_map = cls._xml_map # type: ignore + except AttributeError: + xml_map = {} + + return _create_xml_node(xml_map.get("name", cls.__name__), xml_map.get("prefix", None), xml_map.get("ns", None)) + + def serialize(self, keep_readonly: bool = False, **kwargs: Any) -> JSON: + """Return the JSON that would be sent to server from this model. + + This is an alias to `as_dict(full_restapi_key_transformer, keep_readonly=False)`. + + If you want XML serialization, you can pass the kwargs is_xml=True. + + :param bool keep_readonly: If you want to serialize the readonly attributes + :returns: A dict JSON compatible object + :rtype: dict + """ + serializer = Serializer(self._infer_class_models()) + return serializer._serialize( # type: ignore # pylint: disable=protected-access + self, keep_readonly=keep_readonly, **kwargs + ) + + def as_dict( + self, + keep_readonly: bool = True, + key_transformer: Callable[[str, Dict[str, Any], Any], Any] = attribute_transformer, + **kwargs: Any + ) -> JSON: + """Return a dict that can be serialized using json.dump. + + Advanced usage might optionally use a callback as parameter: + + .. code::python + + def my_key_transformer(key, attr_desc, value): + return key + + Key is the attribute name used in Python. Attr_desc + is a dict of metadata. Currently contains 'type' with the + msrest type and 'key' with the RestAPI encoded key. + Value is the current value in this object. + + The string returned will be used to serialize the key. + If the return type is a list, this is considered hierarchical + result dict. + + See the three examples in this file: + + - attribute_transformer + - full_restapi_key_transformer + - last_restapi_key_transformer + + If you want XML serialization, you can pass the kwargs is_xml=True. + + :param bool keep_readonly: If you want to serialize the readonly attributes + :param function key_transformer: A key transformer function. + :returns: A dict JSON compatible object + :rtype: dict + """ + serializer = Serializer(self._infer_class_models()) + return serializer._serialize( # type: ignore # pylint: disable=protected-access + self, key_transformer=key_transformer, keep_readonly=keep_readonly, **kwargs + ) + + @classmethod + def _infer_class_models(cls): + try: + str_models = cls.__module__.rsplit(".", 1)[0] + models = sys.modules[str_models] + client_models = {k: v for k, v in models.__dict__.items() if isinstance(v, type)} + if cls.__name__ not in client_models: + raise ValueError("Not Autorest generated code") + except Exception: # pylint: disable=broad-exception-caught + # Assume it's not Autorest generated (tests?). Add ourselves as dependencies. + client_models = {cls.__name__: cls} + return client_models + + @classmethod + def deserialize(cls, data: Any, content_type: Optional[str] = None) -> Self: + """Parse a str using the RestAPI syntax and return a model. + + :param str data: A str using RestAPI structure. JSON by default. + :param str content_type: JSON by default, set application/xml if XML. + :returns: An instance of this model + :raises DeserializationError: if something went wrong + :rtype: Self + """ + deserializer = Deserializer(cls._infer_class_models()) + return deserializer(cls.__name__, data, content_type=content_type) # type: ignore + + @classmethod + def from_dict( + cls, + data: Any, + key_extractors: Optional[Callable[[str, Dict[str, Any], Any], Any]] = None, + content_type: Optional[str] = None, + ) -> Self: + """Parse a dict using given key extractor return a model. + + By default consider key + extractors (rest_key_case_insensitive_extractor, attribute_key_case_insensitive_extractor + and last_rest_key_case_insensitive_extractor) + + :param dict data: A dict using RestAPI structure + :param function key_extractors: A key extractor function. + :param str content_type: JSON by default, set application/xml if XML. + :returns: An instance of this model + :raises DeserializationError: if something went wrong + :rtype: Self + """ + deserializer = Deserializer(cls._infer_class_models()) + deserializer.key_extractors = ( # type: ignore + [ # type: ignore + attribute_key_case_insensitive_extractor, + rest_key_case_insensitive_extractor, + last_rest_key_case_insensitive_extractor, + ] + if key_extractors is None + else key_extractors + ) + return deserializer(cls.__name__, data, content_type=content_type) # type: ignore + + @classmethod + def _flatten_subtype(cls, key, objects): + if "_subtype_map" not in cls.__dict__: + return {} + result = dict(cls._subtype_map[key]) + for valuetype in cls._subtype_map[key].values(): + result.update(objects[valuetype]._flatten_subtype(key, objects)) # pylint: disable=protected-access + return result + + @classmethod + def _classify(cls, response, objects): + """Check the class _subtype_map for any child classes. + We want to ignore any inherited _subtype_maps. + + :param dict response: The initial data + :param dict objects: The class objects + :returns: The class to be used + :rtype: class + """ + for subtype_key in cls.__dict__.get("_subtype_map", {}).keys(): + subtype_value = None + + if not isinstance(response, ET.Element): + rest_api_response_key = cls._get_rest_key_parts(subtype_key)[-1] + subtype_value = response.get(rest_api_response_key, None) or response.get(subtype_key, None) + else: + subtype_value = xml_key_extractor(subtype_key, cls._attribute_map[subtype_key], response) + if subtype_value: + # Try to match base class. Can be class name only + # (bug to fix in Autorest to support x-ms-discriminator-name) + if cls.__name__ == subtype_value: + return cls + flatten_mapping_type = cls._flatten_subtype(subtype_key, objects) + try: + return objects[flatten_mapping_type[subtype_value]] # type: ignore + except KeyError: + _LOGGER.warning( + "Subtype value %s has no mapping, use base class %s.", + subtype_value, + cls.__name__, + ) + break + else: + _LOGGER.warning("Discriminator %s is absent or null, use base class %s.", subtype_key, cls.__name__) + break + return cls + + @classmethod + def _get_rest_key_parts(cls, attr_key): + """Get the RestAPI key of this attr, split it and decode part + :param str attr_key: Attribute key must be in attribute_map. + :returns: A list of RestAPI part + :rtype: list + """ + rest_split_key = _FLATTEN.split(cls._attribute_map[attr_key]["key"]) + return [_decode_attribute_map_key(key_part) for key_part in rest_split_key] + + +def _decode_attribute_map_key(key): + """This decode a key in an _attribute_map to the actual key we want to look at + inside the received data. + + :param str key: A key string from the generated code + :returns: The decoded key + :rtype: str + """ + return key.replace("\\.", ".") + + +class Serializer: # pylint: disable=too-many-public-methods + """Request object model serializer.""" + + basic_types = {str: "str", int: "int", bool: "bool", float: "float"} + + _xml_basic_types_serializers = {"bool": lambda x: str(x).lower()} + days = {0: "Mon", 1: "Tue", 2: "Wed", 3: "Thu", 4: "Fri", 5: "Sat", 6: "Sun"} + months = { + 1: "Jan", + 2: "Feb", + 3: "Mar", + 4: "Apr", + 5: "May", + 6: "Jun", + 7: "Jul", + 8: "Aug", + 9: "Sep", + 10: "Oct", + 11: "Nov", + 12: "Dec", + } + validation = { + "min_length": lambda x, y: len(x) < y, + "max_length": lambda x, y: len(x) > y, + "minimum": lambda x, y: x < y, + "maximum": lambda x, y: x > y, + "minimum_ex": lambda x, y: x <= y, + "maximum_ex": lambda x, y: x >= y, + "min_items": lambda x, y: len(x) < y, + "max_items": lambda x, y: len(x) > y, + "pattern": lambda x, y: not re.match(y, x, re.UNICODE), + "unique": lambda x, y: len(x) != len(set(x)), + "multiple": lambda x, y: x % y != 0, + } + + def __init__(self, classes: Optional[Mapping[str, type]] = None) -> None: + self.serialize_type = { + "iso-8601": Serializer.serialize_iso, + "rfc-1123": Serializer.serialize_rfc, + "unix-time": Serializer.serialize_unix, + "duration": Serializer.serialize_duration, + "date": Serializer.serialize_date, + "time": Serializer.serialize_time, + "decimal": Serializer.serialize_decimal, + "long": Serializer.serialize_long, + "bytearray": Serializer.serialize_bytearray, + "base64": Serializer.serialize_base64, + "object": self.serialize_object, + "[]": self.serialize_iter, + "{}": self.serialize_dict, + } + self.dependencies: Dict[str, type] = dict(classes) if classes else {} + self.key_transformer = full_restapi_key_transformer + self.client_side_validation = True + + def _serialize( # pylint: disable=too-many-nested-blocks, too-many-branches, too-many-statements, too-many-locals + self, target_obj, data_type=None, **kwargs + ): + """Serialize data into a string according to type. + + :param object target_obj: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str, dict + :raises SerializationError: if serialization fails. + :returns: The serialized data. + """ + key_transformer = kwargs.get("key_transformer", self.key_transformer) + keep_readonly = kwargs.get("keep_readonly", False) + if target_obj is None: + return None + + attr_name = None + class_name = target_obj.__class__.__name__ + + if data_type: + return self.serialize_data(target_obj, data_type, **kwargs) + + if not hasattr(target_obj, "_attribute_map"): + data_type = type(target_obj).__name__ + if data_type in self.basic_types.values(): + return self.serialize_data(target_obj, data_type, **kwargs) + + # Force "is_xml" kwargs if we detect a XML model + try: + is_xml_model_serialization = kwargs["is_xml"] + except KeyError: + is_xml_model_serialization = kwargs.setdefault("is_xml", target_obj.is_xml_model()) + + serialized = {} + if is_xml_model_serialization: + serialized = target_obj._create_xml_node() # pylint: disable=protected-access + try: + attributes = target_obj._attribute_map # pylint: disable=protected-access + for attr, attr_desc in attributes.items(): + attr_name = attr + if not keep_readonly and target_obj._validation.get( # pylint: disable=protected-access + attr_name, {} + ).get("readonly", False): + continue + + if attr_name == "additional_properties" and attr_desc["key"] == "": + if target_obj.additional_properties is not None: + serialized.update(target_obj.additional_properties) + continue + try: + + orig_attr = getattr(target_obj, attr) + if is_xml_model_serialization: + pass # Don't provide "transformer" for XML for now. Keep "orig_attr" + else: # JSON + keys, orig_attr = key_transformer(attr, attr_desc.copy(), orig_attr) + keys = keys if isinstance(keys, list) else [keys] + + kwargs["serialization_ctxt"] = attr_desc + new_attr = self.serialize_data(orig_attr, attr_desc["type"], **kwargs) + + if is_xml_model_serialization: + xml_desc = attr_desc.get("xml", {}) + xml_name = xml_desc.get("name", attr_desc["key"]) + xml_prefix = xml_desc.get("prefix", None) + xml_ns = xml_desc.get("ns", None) + if xml_desc.get("attr", False): + if xml_ns: + ET.register_namespace(xml_prefix, xml_ns) + xml_name = "{{{}}}{}".format(xml_ns, xml_name) + serialized.set(xml_name, new_attr) # type: ignore + continue + if xml_desc.get("text", False): + serialized.text = new_attr # type: ignore + continue + if isinstance(new_attr, list): + serialized.extend(new_attr) # type: ignore + elif isinstance(new_attr, ET.Element): + # If the down XML has no XML/Name, + # we MUST replace the tag with the local tag. But keeping the namespaces. + if "name" not in getattr(orig_attr, "_xml_map", {}): + splitted_tag = new_attr.tag.split("}") + if len(splitted_tag) == 2: # Namespace + new_attr.tag = "}".join([splitted_tag[0], xml_name]) + else: + new_attr.tag = xml_name + serialized.append(new_attr) # type: ignore + else: # That's a basic type + # Integrate namespace if necessary + local_node = _create_xml_node(xml_name, xml_prefix, xml_ns) + local_node.text = str(new_attr) + serialized.append(local_node) # type: ignore + else: # JSON + for k in reversed(keys): # type: ignore + new_attr = {k: new_attr} + + _new_attr = new_attr + _serialized = serialized + for k in keys: # type: ignore + if k not in _serialized: + _serialized.update(_new_attr) # type: ignore + _new_attr = _new_attr[k] # type: ignore + _serialized = _serialized[k] + except ValueError as err: + if isinstance(err, SerializationError): + raise + + except (AttributeError, KeyError, TypeError) as err: + msg = "Attribute {} in object {} cannot be serialized.\n{}".format(attr_name, class_name, str(target_obj)) + raise SerializationError(msg) from err + return serialized + + def body(self, data, data_type, **kwargs): + """Serialize data intended for a request body. + + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: dict + :raises SerializationError: if serialization fails. + :raises ValueError: if data is None + :returns: The serialized request body + """ + + # Just in case this is a dict + internal_data_type_str = data_type.strip("[]{}") + internal_data_type = self.dependencies.get(internal_data_type_str, None) + try: + is_xml_model_serialization = kwargs["is_xml"] + except KeyError: + if internal_data_type and issubclass(internal_data_type, Model): + is_xml_model_serialization = kwargs.setdefault("is_xml", internal_data_type.is_xml_model()) + else: + is_xml_model_serialization = False + if internal_data_type and not isinstance(internal_data_type, Enum): + try: + deserializer = Deserializer(self.dependencies) + # Since it's on serialization, it's almost sure that format is not JSON REST + # We're not able to deal with additional properties for now. + deserializer.additional_properties_detection = False + if is_xml_model_serialization: + deserializer.key_extractors = [ # type: ignore + attribute_key_case_insensitive_extractor, + ] + else: + deserializer.key_extractors = [ + rest_key_case_insensitive_extractor, + attribute_key_case_insensitive_extractor, + last_rest_key_case_insensitive_extractor, + ] + data = deserializer._deserialize(data_type, data) # pylint: disable=protected-access + except DeserializationError as err: + raise SerializationError("Unable to build a model: " + str(err)) from err + + return self._serialize(data, data_type, **kwargs) + + def url(self, name, data, data_type, **kwargs): + """Serialize data intended for a URL path. + + :param str name: The name of the URL path parameter. + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str + :returns: The serialized URL path + :raises TypeError: if serialization fails. + :raises ValueError: if data is None + """ + try: + output = self.serialize_data(data, data_type, **kwargs) + if data_type == "bool": + output = json.dumps(output) + + if kwargs.get("skip_quote") is True: + output = str(output) + output = output.replace("{", quote("{")).replace("}", quote("}")) + else: + output = quote(str(output), safe="") + except SerializationError as exc: + raise TypeError("{} must be type {}.".format(name, data_type)) from exc + return output + + def query(self, name, data, data_type, **kwargs): + """Serialize data intended for a URL query. + + :param str name: The name of the query parameter. + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str, list + :raises TypeError: if serialization fails. + :raises ValueError: if data is None + :returns: The serialized query parameter + """ + try: + # Treat the list aside, since we don't want to encode the div separator + if data_type.startswith("["): + internal_data_type = data_type[1:-1] + do_quote = not kwargs.get("skip_quote", False) + return self.serialize_iter(data, internal_data_type, do_quote=do_quote, **kwargs) + + # Not a list, regular serialization + output = self.serialize_data(data, data_type, **kwargs) + if data_type == "bool": + output = json.dumps(output) + if kwargs.get("skip_quote") is True: + output = str(output) + else: + output = quote(str(output), safe="") + except SerializationError as exc: + raise TypeError("{} must be type {}.".format(name, data_type)) from exc + return str(output) + + def header(self, name, data, data_type, **kwargs): + """Serialize data intended for a request header. + + :param str name: The name of the header. + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str + :raises TypeError: if serialization fails. + :raises ValueError: if data is None + :returns: The serialized header + """ + try: + if data_type in ["[str]"]: + data = ["" if d is None else d for d in data] + + output = self.serialize_data(data, data_type, **kwargs) + if data_type == "bool": + output = json.dumps(output) + except SerializationError as exc: + raise TypeError("{} must be type {}.".format(name, data_type)) from exc + return str(output) + + def serialize_data(self, data, data_type, **kwargs): + """Serialize generic data according to supplied data type. + + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :raises AttributeError: if required data is None. + :raises ValueError: if data is None + :raises SerializationError: if serialization fails. + :returns: The serialized data. + :rtype: str, int, float, bool, dict, list + """ + if data is None: + raise ValueError("No value for given attribute") + + try: + if data is CoreNull: + return None + if data_type in self.basic_types.values(): + return self.serialize_basic(data, data_type, **kwargs) + + if data_type in self.serialize_type: + return self.serialize_type[data_type](data, **kwargs) + + # If dependencies is empty, try with current data class + # It has to be a subclass of Enum anyway + enum_type = self.dependencies.get(data_type, data.__class__) + if issubclass(enum_type, Enum): + return Serializer.serialize_enum(data, enum_obj=enum_type) + + iter_type = data_type[0] + data_type[-1] + if iter_type in self.serialize_type: + return self.serialize_type[iter_type](data, data_type[1:-1], **kwargs) + + except (ValueError, TypeError) as err: + msg = "Unable to serialize value: {!r} as type: {!r}." + raise SerializationError(msg.format(data, data_type)) from err + return self._serialize(data, **kwargs) + + @classmethod + def _get_custom_serializers(cls, data_type, **kwargs): # pylint: disable=inconsistent-return-statements + custom_serializer = kwargs.get("basic_types_serializers", {}).get(data_type) + if custom_serializer: + return custom_serializer + if kwargs.get("is_xml", False): + return cls._xml_basic_types_serializers.get(data_type) + + @classmethod + def serialize_basic(cls, data, data_type, **kwargs): + """Serialize basic builting data type. + Serializes objects to str, int, float or bool. + + Possible kwargs: + - basic_types_serializers dict[str, callable] : If set, use the callable as serializer + - is_xml bool : If set, use xml_basic_types_serializers + + :param obj data: Object to be serialized. + :param str data_type: Type of object in the iterable. + :rtype: str, int, float, bool + :return: serialized object + """ + custom_serializer = cls._get_custom_serializers(data_type, **kwargs) + if custom_serializer: + return custom_serializer(data) + if data_type == "str": + return cls.serialize_unicode(data) + return eval(data_type)(data) # nosec # pylint: disable=eval-used + + @classmethod + def serialize_unicode(cls, data): + """Special handling for serializing unicode strings in Py2. + Encode to UTF-8 if unicode, otherwise handle as a str. + + :param str data: Object to be serialized. + :rtype: str + :return: serialized object + """ + try: # If I received an enum, return its value + return data.value + except AttributeError: + pass + + try: + if isinstance(data, unicode): # type: ignore + # Don't change it, JSON and XML ElementTree are totally able + # to serialize correctly u'' strings + return data + except NameError: + return str(data) + return str(data) + + def serialize_iter(self, data, iter_type, div=None, **kwargs): + """Serialize iterable. + + Supported kwargs: + - serialization_ctxt dict : The current entry of _attribute_map, or same format. + serialization_ctxt['type'] should be same as data_type. + - is_xml bool : If set, serialize as XML + + :param list data: Object to be serialized. + :param str iter_type: Type of object in the iterable. + :param str div: If set, this str will be used to combine the elements + in the iterable into a combined string. Default is 'None'. + Defaults to False. + :rtype: list, str + :return: serialized iterable + """ + if isinstance(data, str): + raise SerializationError("Refuse str type as a valid iter type.") + + serialization_ctxt = kwargs.get("serialization_ctxt", {}) + is_xml = kwargs.get("is_xml", False) + + serialized = [] + for d in data: + try: + serialized.append(self.serialize_data(d, iter_type, **kwargs)) + except ValueError as err: + if isinstance(err, SerializationError): + raise + serialized.append(None) + + if kwargs.get("do_quote", False): + serialized = ["" if s is None else quote(str(s), safe="") for s in serialized] + + if div: + serialized = ["" if s is None else str(s) for s in serialized] + serialized = div.join(serialized) + + if "xml" in serialization_ctxt or is_xml: + # XML serialization is more complicated + xml_desc = serialization_ctxt.get("xml", {}) + xml_name = xml_desc.get("name") + if not xml_name: + xml_name = serialization_ctxt["key"] + + # Create a wrap node if necessary (use the fact that Element and list have "append") + is_wrapped = xml_desc.get("wrapped", False) + node_name = xml_desc.get("itemsName", xml_name) + if is_wrapped: + final_result = _create_xml_node(xml_name, xml_desc.get("prefix", None), xml_desc.get("ns", None)) + else: + final_result = [] + # All list elements to "local_node" + for el in serialized: + if isinstance(el, ET.Element): + el_node = el + else: + el_node = _create_xml_node(node_name, xml_desc.get("prefix", None), xml_desc.get("ns", None)) + if el is not None: # Otherwise it writes "None" :-p + el_node.text = str(el) + final_result.append(el_node) + return final_result + return serialized + + def serialize_dict(self, attr, dict_type, **kwargs): + """Serialize a dictionary of objects. + + :param dict attr: Object to be serialized. + :param str dict_type: Type of object in the dictionary. + :rtype: dict + :return: serialized dictionary + """ + serialization_ctxt = kwargs.get("serialization_ctxt", {}) + serialized = {} + for key, value in attr.items(): + try: + serialized[self.serialize_unicode(key)] = self.serialize_data(value, dict_type, **kwargs) + except ValueError as err: + if isinstance(err, SerializationError): + raise + serialized[self.serialize_unicode(key)] = None + + if "xml" in serialization_ctxt: + # XML serialization is more complicated + xml_desc = serialization_ctxt["xml"] + xml_name = xml_desc["name"] + + final_result = _create_xml_node(xml_name, xml_desc.get("prefix", None), xml_desc.get("ns", None)) + for key, value in serialized.items(): + ET.SubElement(final_result, key).text = value + return final_result + + return serialized + + def serialize_object(self, attr, **kwargs): # pylint: disable=too-many-return-statements + """Serialize a generic object. + This will be handled as a dictionary. If object passed in is not + a basic type (str, int, float, dict, list) it will simply be + cast to str. + + :param dict attr: Object to be serialized. + :rtype: dict or str + :return: serialized object + """ + if attr is None: + return None + if isinstance(attr, ET.Element): + return attr + obj_type = type(attr) + if obj_type in self.basic_types: + return self.serialize_basic(attr, self.basic_types[obj_type], **kwargs) + if obj_type is _long_type: + return self.serialize_long(attr) + if obj_type is str: + return self.serialize_unicode(attr) + if obj_type is datetime.datetime: + return self.serialize_iso(attr) + if obj_type is datetime.date: + return self.serialize_date(attr) + if obj_type is datetime.time: + return self.serialize_time(attr) + if obj_type is datetime.timedelta: + return self.serialize_duration(attr) + if obj_type is decimal.Decimal: + return self.serialize_decimal(attr) + + # If it's a model or I know this dependency, serialize as a Model + if obj_type in self.dependencies.values() or isinstance(attr, Model): + return self._serialize(attr) + + if obj_type == dict: + serialized = {} + for key, value in attr.items(): + try: + serialized[self.serialize_unicode(key)] = self.serialize_object(value, **kwargs) + except ValueError: + serialized[self.serialize_unicode(key)] = None + return serialized + + if obj_type == list: + serialized = [] + for obj in attr: + try: + serialized.append(self.serialize_object(obj, **kwargs)) + except ValueError: + pass + return serialized + return str(attr) + + @staticmethod + def serialize_enum(attr, enum_obj=None): + try: + result = attr.value + except AttributeError: + result = attr + try: + enum_obj(result) # type: ignore + return result + except ValueError as exc: + for enum_value in enum_obj: # type: ignore + if enum_value.value.lower() == str(attr).lower(): + return enum_value.value + error = "{!r} is not valid value for enum {!r}" + raise SerializationError(error.format(attr, enum_obj)) from exc + + @staticmethod + def serialize_bytearray(attr, **kwargs): # pylint: disable=unused-argument + """Serialize bytearray into base-64 string. + + :param str attr: Object to be serialized. + :rtype: str + :return: serialized base64 + """ + return b64encode(attr).decode() + + @staticmethod + def serialize_base64(attr, **kwargs): # pylint: disable=unused-argument + """Serialize str into base-64 string. + + :param str attr: Object to be serialized. + :rtype: str + :return: serialized base64 + """ + encoded = b64encode(attr).decode("ascii") + return encoded.strip("=").replace("+", "-").replace("/", "_") + + @staticmethod + def serialize_decimal(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Decimal object to float. + + :param decimal attr: Object to be serialized. + :rtype: float + :return: serialized decimal + """ + return float(attr) + + @staticmethod + def serialize_long(attr, **kwargs): # pylint: disable=unused-argument + """Serialize long (Py2) or int (Py3). + + :param int attr: Object to be serialized. + :rtype: int/long + :return: serialized long + """ + return _long_type(attr) + + @staticmethod + def serialize_date(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Date object into ISO-8601 formatted string. + + :param Date attr: Object to be serialized. + :rtype: str + :return: serialized date + """ + if isinstance(attr, str): + attr = isodate.parse_date(attr) + t = "{:04}-{:02}-{:02}".format(attr.year, attr.month, attr.day) + return t + + @staticmethod + def serialize_time(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Time object into ISO-8601 formatted string. + + :param datetime.time attr: Object to be serialized. + :rtype: str + :return: serialized time + """ + if isinstance(attr, str): + attr = isodate.parse_time(attr) + t = "{:02}:{:02}:{:02}".format(attr.hour, attr.minute, attr.second) + if attr.microsecond: + t += ".{:02}".format(attr.microsecond) + return t + + @staticmethod + def serialize_duration(attr, **kwargs): # pylint: disable=unused-argument + """Serialize TimeDelta object into ISO-8601 formatted string. + + :param TimeDelta attr: Object to be serialized. + :rtype: str + :return: serialized duration + """ + if isinstance(attr, str): + attr = isodate.parse_duration(attr) + return isodate.duration_isoformat(attr) + + @staticmethod + def serialize_rfc(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Datetime object into RFC-1123 formatted string. + + :param Datetime attr: Object to be serialized. + :rtype: str + :raises TypeError: if format invalid. + :return: serialized rfc + """ + try: + if not attr.tzinfo: + _LOGGER.warning("Datetime with no tzinfo will be considered UTC.") + utc = attr.utctimetuple() + except AttributeError as exc: + raise TypeError("RFC1123 object must be valid Datetime object.") from exc + + return "{}, {:02} {} {:04} {:02}:{:02}:{:02} GMT".format( + Serializer.days[utc.tm_wday], + utc.tm_mday, + Serializer.months[utc.tm_mon], + utc.tm_year, + utc.tm_hour, + utc.tm_min, + utc.tm_sec, + ) + + @staticmethod + def serialize_iso(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Datetime object into ISO-8601 formatted string. + + :param Datetime attr: Object to be serialized. + :rtype: str + :raises SerializationError: if format invalid. + :return: serialized iso + """ + if isinstance(attr, str): + attr = isodate.parse_datetime(attr) + try: + if not attr.tzinfo: + _LOGGER.warning("Datetime with no tzinfo will be considered UTC.") + utc = attr.utctimetuple() + if utc.tm_year > 9999 or utc.tm_year < 1: + raise OverflowError("Hit max or min date") + + microseconds = str(attr.microsecond).rjust(6, "0").rstrip("0").ljust(3, "0") + if microseconds: + microseconds = "." + microseconds + date = "{:04}-{:02}-{:02}T{:02}:{:02}:{:02}".format( + utc.tm_year, utc.tm_mon, utc.tm_mday, utc.tm_hour, utc.tm_min, utc.tm_sec + ) + return date + microseconds + "Z" + except (ValueError, OverflowError) as err: + msg = "Unable to serialize datetime object." + raise SerializationError(msg) from err + except AttributeError as err: + msg = "ISO-8601 object must be valid Datetime object." + raise TypeError(msg) from err + + @staticmethod + def serialize_unix(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Datetime object into IntTime format. + This is represented as seconds. + + :param Datetime attr: Object to be serialized. + :rtype: int + :raises SerializationError: if format invalid + :return: serialied unix + """ + if isinstance(attr, int): + return attr + try: + if not attr.tzinfo: + _LOGGER.warning("Datetime with no tzinfo will be considered UTC.") + return int(calendar.timegm(attr.utctimetuple())) + except AttributeError as exc: + raise TypeError("Unix time object must be valid Datetime object.") from exc + + +def rest_key_extractor(attr, attr_desc, data): # pylint: disable=unused-argument + key = attr_desc["key"] + working_data = data + + while "." in key: + # Need the cast, as for some reasons "split" is typed as list[str | Any] + dict_keys = cast(List[str], _FLATTEN.split(key)) + if len(dict_keys) == 1: + key = _decode_attribute_map_key(dict_keys[0]) + break + working_key = _decode_attribute_map_key(dict_keys[0]) + working_data = working_data.get(working_key, data) + if working_data is None: + # If at any point while following flatten JSON path see None, it means + # that all properties under are None as well + return None + key = ".".join(dict_keys[1:]) + + return working_data.get(key) + + +def rest_key_case_insensitive_extractor( # pylint: disable=unused-argument, inconsistent-return-statements + attr, attr_desc, data +): + key = attr_desc["key"] + working_data = data + + while "." in key: + dict_keys = _FLATTEN.split(key) + if len(dict_keys) == 1: + key = _decode_attribute_map_key(dict_keys[0]) + break + working_key = _decode_attribute_map_key(dict_keys[0]) + working_data = attribute_key_case_insensitive_extractor(working_key, None, working_data) + if working_data is None: + # If at any point while following flatten JSON path see None, it means + # that all properties under are None as well + return None + key = ".".join(dict_keys[1:]) + + if working_data: + return attribute_key_case_insensitive_extractor(key, None, working_data) + + +def last_rest_key_extractor(attr, attr_desc, data): # pylint: disable=unused-argument + """Extract the attribute in "data" based on the last part of the JSON path key. + + :param str attr: The attribute to extract + :param dict attr_desc: The attribute description + :param dict data: The data to extract from + :rtype: object + :returns: The extracted attribute + """ + key = attr_desc["key"] + dict_keys = _FLATTEN.split(key) + return attribute_key_extractor(dict_keys[-1], None, data) + + +def last_rest_key_case_insensitive_extractor(attr, attr_desc, data): # pylint: disable=unused-argument + """Extract the attribute in "data" based on the last part of the JSON path key. + + This is the case insensitive version of "last_rest_key_extractor" + :param str attr: The attribute to extract + :param dict attr_desc: The attribute description + :param dict data: The data to extract from + :rtype: object + :returns: The extracted attribute + """ + key = attr_desc["key"] + dict_keys = _FLATTEN.split(key) + return attribute_key_case_insensitive_extractor(dict_keys[-1], None, data) + + +def attribute_key_extractor(attr, _, data): + return data.get(attr) + + +def attribute_key_case_insensitive_extractor(attr, _, data): + found_key = None + lower_attr = attr.lower() + for key in data: + if lower_attr == key.lower(): + found_key = key + break + + return data.get(found_key) + + +def _extract_name_from_internal_type(internal_type): + """Given an internal type XML description, extract correct XML name with namespace. + + :param dict internal_type: An model type + :rtype: tuple + :returns: A tuple XML name + namespace dict + """ + internal_type_xml_map = getattr(internal_type, "_xml_map", {}) + xml_name = internal_type_xml_map.get("name", internal_type.__name__) + xml_ns = internal_type_xml_map.get("ns", None) + if xml_ns: + xml_name = "{{{}}}{}".format(xml_ns, xml_name) + return xml_name + + +def xml_key_extractor(attr, attr_desc, data): # pylint: disable=unused-argument,too-many-return-statements + if isinstance(data, dict): + return None + + # Test if this model is XML ready first + if not isinstance(data, ET.Element): + return None + + xml_desc = attr_desc.get("xml", {}) + xml_name = xml_desc.get("name", attr_desc["key"]) + + # Look for a children + is_iter_type = attr_desc["type"].startswith("[") + is_wrapped = xml_desc.get("wrapped", False) + internal_type = attr_desc.get("internalType", None) + internal_type_xml_map = getattr(internal_type, "_xml_map", {}) + + # Integrate namespace if necessary + xml_ns = xml_desc.get("ns", internal_type_xml_map.get("ns", None)) + if xml_ns: + xml_name = "{{{}}}{}".format(xml_ns, xml_name) + + # If it's an attribute, that's simple + if xml_desc.get("attr", False): + return data.get(xml_name) + + # If it's x-ms-text, that's simple too + if xml_desc.get("text", False): + return data.text + + # Scenario where I take the local name: + # - Wrapped node + # - Internal type is an enum (considered basic types) + # - Internal type has no XML/Name node + if is_wrapped or (internal_type and (issubclass(internal_type, Enum) or "name" not in internal_type_xml_map)): + children = data.findall(xml_name) + # If internal type has a local name and it's not a list, I use that name + elif not is_iter_type and internal_type and "name" in internal_type_xml_map: + xml_name = _extract_name_from_internal_type(internal_type) + children = data.findall(xml_name) + # That's an array + else: + if internal_type: # Complex type, ignore itemsName and use the complex type name + items_name = _extract_name_from_internal_type(internal_type) + else: + items_name = xml_desc.get("itemsName", xml_name) + children = data.findall(items_name) + + if len(children) == 0: + if is_iter_type: + if is_wrapped: + return None # is_wrapped no node, we want None + return [] # not wrapped, assume empty list + return None # Assume it's not there, maybe an optional node. + + # If is_iter_type and not wrapped, return all found children + if is_iter_type: + if not is_wrapped: + return children + # Iter and wrapped, should have found one node only (the wrap one) + if len(children) != 1: + raise DeserializationError( + "Tried to deserialize an array not wrapped, and found several nodes '{}'. Maybe you should declare this array as wrapped?".format( + xml_name + ) + ) + return list(children[0]) # Might be empty list and that's ok. + + # Here it's not a itertype, we should have found one element only or empty + if len(children) > 1: + raise DeserializationError("Find several XML '{}' where it was not expected".format(xml_name)) + return children[0] + + +class Deserializer: + """Response object model deserializer. + + :param dict classes: Class type dictionary for deserializing complex types. + :ivar list key_extractors: Ordered list of extractors to be used by this deserializer. + """ + + basic_types = {str: "str", int: "int", bool: "bool", float: "float"} + + valid_date = re.compile(r"\d{4}[-]\d{2}[-]\d{2}T\d{2}:\d{2}:\d{2}\.?\d*Z?[-+]?[\d{2}]?:?[\d{2}]?") + + def __init__(self, classes: Optional[Mapping[str, type]] = None) -> None: + self.deserialize_type = { + "iso-8601": Deserializer.deserialize_iso, + "rfc-1123": Deserializer.deserialize_rfc, + "unix-time": Deserializer.deserialize_unix, + "duration": Deserializer.deserialize_duration, + "date": Deserializer.deserialize_date, + "time": Deserializer.deserialize_time, + "decimal": Deserializer.deserialize_decimal, + "long": Deserializer.deserialize_long, + "bytearray": Deserializer.deserialize_bytearray, + "base64": Deserializer.deserialize_base64, + "object": self.deserialize_object, + "[]": self.deserialize_iter, + "{}": self.deserialize_dict, + } + self.deserialize_expected_types = { + "duration": (isodate.Duration, datetime.timedelta), + "iso-8601": (datetime.datetime), + } + self.dependencies: Dict[str, type] = dict(classes) if classes else {} + self.key_extractors = [rest_key_extractor, xml_key_extractor] + # Additional properties only works if the "rest_key_extractor" is used to + # extract the keys. Making it to work whatever the key extractor is too much + # complicated, with no real scenario for now. + # So adding a flag to disable additional properties detection. This flag should be + # used if your expect the deserialization to NOT come from a JSON REST syntax. + # Otherwise, result are unexpected + self.additional_properties_detection = True + + def __call__(self, target_obj, response_data, content_type=None): + """Call the deserializer to process a REST response. + + :param str target_obj: Target data type to deserialize to. + :param requests.Response response_data: REST response object. + :param str content_type: Swagger "produces" if available. + :raises DeserializationError: if deserialization fails. + :return: Deserialized object. + :rtype: object + """ + data = self._unpack_content(response_data, content_type) + return self._deserialize(target_obj, data) + + def _deserialize(self, target_obj, data): # pylint: disable=inconsistent-return-statements + """Call the deserializer on a model. + + Data needs to be already deserialized as JSON or XML ElementTree + + :param str target_obj: Target data type to deserialize to. + :param object data: Object to deserialize. + :raises DeserializationError: if deserialization fails. + :return: Deserialized object. + :rtype: object + """ + # This is already a model, go recursive just in case + if hasattr(data, "_attribute_map"): + constants = [name for name, config in getattr(data, "_validation", {}).items() if config.get("constant")] + try: + for attr, mapconfig in data._attribute_map.items(): # pylint: disable=protected-access + if attr in constants: + continue + value = getattr(data, attr) + if value is None: + continue + local_type = mapconfig["type"] + internal_data_type = local_type.strip("[]{}") + if internal_data_type not in self.dependencies or isinstance(internal_data_type, Enum): + continue + setattr(data, attr, self._deserialize(local_type, value)) + return data + except AttributeError: + return + + response, class_name = self._classify_target(target_obj, data) + + if isinstance(response, str): + return self.deserialize_data(data, response) + if isinstance(response, type) and issubclass(response, Enum): + return self.deserialize_enum(data, response) + + if data is None or data is CoreNull: + return data + try: + attributes = response._attribute_map # type: ignore # pylint: disable=protected-access + d_attrs = {} + for attr, attr_desc in attributes.items(): + # Check empty string. If it's not empty, someone has a real "additionalProperties"... + if attr == "additional_properties" and attr_desc["key"] == "": + continue + raw_value = None + # Enhance attr_desc with some dynamic data + attr_desc = attr_desc.copy() # Do a copy, do not change the real one + internal_data_type = attr_desc["type"].strip("[]{}") + if internal_data_type in self.dependencies: + attr_desc["internalType"] = self.dependencies[internal_data_type] + + for key_extractor in self.key_extractors: + found_value = key_extractor(attr, attr_desc, data) + if found_value is not None: + if raw_value is not None and raw_value != found_value: + msg = ( + "Ignoring extracted value '%s' from %s for key '%s'" + " (duplicate extraction, follow extractors order)" + ) + _LOGGER.warning(msg, found_value, key_extractor, attr) + continue + raw_value = found_value + + value = self.deserialize_data(raw_value, attr_desc["type"]) + d_attrs[attr] = value + except (AttributeError, TypeError, KeyError) as err: + msg = "Unable to deserialize to object: " + class_name # type: ignore + raise DeserializationError(msg) from err + additional_properties = self._build_additional_properties(attributes, data) + return self._instantiate_model(response, d_attrs, additional_properties) + + def _build_additional_properties(self, attribute_map, data): + if not self.additional_properties_detection: + return None + if "additional_properties" in attribute_map and attribute_map.get("additional_properties", {}).get("key") != "": + # Check empty string. If it's not empty, someone has a real "additionalProperties" + return None + if isinstance(data, ET.Element): + data = {el.tag: el.text for el in data} + + known_keys = { + _decode_attribute_map_key(_FLATTEN.split(desc["key"])[0]) + for desc in attribute_map.values() + if desc["key"] != "" + } + present_keys = set(data.keys()) + missing_keys = present_keys - known_keys + return {key: data[key] for key in missing_keys} + + def _classify_target(self, target, data): + """Check to see whether the deserialization target object can + be classified into a subclass. + Once classification has been determined, initialize object. + + :param str target: The target object type to deserialize to. + :param str/dict data: The response data to deserialize. + :return: The classified target object and its class name. + :rtype: tuple + """ + if target is None: + return None, None + + if isinstance(target, str): + try: + target = self.dependencies[target] + except KeyError: + return target, target + + try: + target = target._classify(data, self.dependencies) # type: ignore # pylint: disable=protected-access + except AttributeError: + pass # Target is not a Model, no classify + return target, target.__class__.__name__ # type: ignore + + def failsafe_deserialize(self, target_obj, data, content_type=None): + """Ignores any errors encountered in deserialization, + and falls back to not deserializing the object. Recommended + for use in error deserialization, as we want to return the + HttpResponseError to users, and not have them deal with + a deserialization error. + + :param str target_obj: The target object type to deserialize to. + :param str/dict data: The response data to deserialize. + :param str content_type: Swagger "produces" if available. + :return: Deserialized object. + :rtype: object + """ + try: + return self(target_obj, data, content_type=content_type) + except: # pylint: disable=bare-except + _LOGGER.debug( + "Ran into a deserialization error. Ignoring since this is failsafe deserialization", exc_info=True + ) + return None + + @staticmethod + def _unpack_content(raw_data, content_type=None): + """Extract the correct structure for deserialization. + + If raw_data is a PipelineResponse, try to extract the result of RawDeserializer. + if we can't, raise. Your Pipeline should have a RawDeserializer. + + If not a pipeline response and raw_data is bytes or string, use content-type + to decode it. If no content-type, try JSON. + + If raw_data is something else, bypass all logic and return it directly. + + :param obj raw_data: Data to be processed. + :param str content_type: How to parse if raw_data is a string/bytes. + :raises JSONDecodeError: If JSON is requested and parsing is impossible. + :raises UnicodeDecodeError: If bytes is not UTF8 + :rtype: object + :return: Unpacked content. + """ + # Assume this is enough to detect a Pipeline Response without importing it + context = getattr(raw_data, "context", {}) + if context: + if RawDeserializer.CONTEXT_NAME in context: + return context[RawDeserializer.CONTEXT_NAME] + raise ValueError("This pipeline didn't have the RawDeserializer policy; can't deserialize") + + # Assume this is enough to recognize universal_http.ClientResponse without importing it + if hasattr(raw_data, "body"): + return RawDeserializer.deserialize_from_http_generics(raw_data.text(), raw_data.headers) + + # Assume this enough to recognize requests.Response without importing it. + if hasattr(raw_data, "_content_consumed"): + return RawDeserializer.deserialize_from_http_generics(raw_data.text, raw_data.headers) + + if isinstance(raw_data, (str, bytes)) or hasattr(raw_data, "read"): + return RawDeserializer.deserialize_from_text(raw_data, content_type) # type: ignore + return raw_data + + def _instantiate_model(self, response, attrs, additional_properties=None): + """Instantiate a response model passing in deserialized args. + + :param Response response: The response model class. + :param dict attrs: The deserialized response attributes. + :param dict additional_properties: Additional properties to be set. + :rtype: Response + :return: The instantiated response model. + """ + if callable(response): + subtype = getattr(response, "_subtype_map", {}) + try: + readonly = [ + k + for k, v in response._validation.items() # pylint: disable=protected-access # type: ignore + if v.get("readonly") + ] + const = [ + k + for k, v in response._validation.items() # pylint: disable=protected-access # type: ignore + if v.get("constant") + ] + kwargs = {k: v for k, v in attrs.items() if k not in subtype and k not in readonly + const} + response_obj = response(**kwargs) + for attr in readonly: + setattr(response_obj, attr, attrs.get(attr)) + if additional_properties: + response_obj.additional_properties = additional_properties # type: ignore + return response_obj + except TypeError as err: + msg = "Unable to deserialize {} into model {}. ".format(kwargs, response) # type: ignore + raise DeserializationError(msg + str(err)) from err + else: + try: + for attr, value in attrs.items(): + setattr(response, attr, value) + return response + except Exception as exp: + msg = "Unable to populate response model. " + msg += "Type: {}, Error: {}".format(type(response), exp) + raise DeserializationError(msg) from exp + + def deserialize_data(self, data, data_type): # pylint: disable=too-many-return-statements + """Process data for deserialization according to data type. + + :param str data: The response string to be deserialized. + :param str data_type: The type to deserialize to. + :raises DeserializationError: if deserialization fails. + :return: Deserialized object. + :rtype: object + """ + if data is None: + return data + + try: + if not data_type: + return data + if data_type in self.basic_types.values(): + return self.deserialize_basic(data, data_type) + if data_type in self.deserialize_type: + if isinstance(data, self.deserialize_expected_types.get(data_type, tuple())): + return data + + is_a_text_parsing_type = lambda x: x not in [ # pylint: disable=unnecessary-lambda-assignment + "object", + "[]", + r"{}", + ] + if isinstance(data, ET.Element) and is_a_text_parsing_type(data_type) and not data.text: + return None + data_val = self.deserialize_type[data_type](data) + return data_val + + iter_type = data_type[0] + data_type[-1] + if iter_type in self.deserialize_type: + return self.deserialize_type[iter_type](data, data_type[1:-1]) + + obj_type = self.dependencies[data_type] + if issubclass(obj_type, Enum): + if isinstance(data, ET.Element): + data = data.text + return self.deserialize_enum(data, obj_type) + + except (ValueError, TypeError, AttributeError) as err: + msg = "Unable to deserialize response data." + msg += " Data: {}, {}".format(data, data_type) + raise DeserializationError(msg) from err + return self._deserialize(obj_type, data) + + def deserialize_iter(self, attr, iter_type): + """Deserialize an iterable. + + :param list attr: Iterable to be deserialized. + :param str iter_type: The type of object in the iterable. + :return: Deserialized iterable. + :rtype: list + """ + if attr is None: + return None + if isinstance(attr, ET.Element): # If I receive an element here, get the children + attr = list(attr) + if not isinstance(attr, (list, set)): + raise DeserializationError("Cannot deserialize as [{}] an object of type {}".format(iter_type, type(attr))) + return [self.deserialize_data(a, iter_type) for a in attr] + + def deserialize_dict(self, attr, dict_type): + """Deserialize a dictionary. + + :param dict/list attr: Dictionary to be deserialized. Also accepts + a list of key, value pairs. + :param str dict_type: The object type of the items in the dictionary. + :return: Deserialized dictionary. + :rtype: dict + """ + if isinstance(attr, list): + return {x["key"]: self.deserialize_data(x["value"], dict_type) for x in attr} + + if isinstance(attr, ET.Element): + # Transform value into {"Key": "value"} + attr = {el.tag: el.text for el in attr} + return {k: self.deserialize_data(v, dict_type) for k, v in attr.items()} + + def deserialize_object(self, attr, **kwargs): # pylint: disable=too-many-return-statements + """Deserialize a generic object. + This will be handled as a dictionary. + + :param dict attr: Dictionary to be deserialized. + :return: Deserialized object. + :rtype: dict + :raises TypeError: if non-builtin datatype encountered. + """ + if attr is None: + return None + if isinstance(attr, ET.Element): + # Do no recurse on XML, just return the tree as-is + return attr + if isinstance(attr, str): + return self.deserialize_basic(attr, "str") + obj_type = type(attr) + if obj_type in self.basic_types: + return self.deserialize_basic(attr, self.basic_types[obj_type]) + if obj_type is _long_type: + return self.deserialize_long(attr) + + if obj_type == dict: + deserialized = {} + for key, value in attr.items(): + try: + deserialized[key] = self.deserialize_object(value, **kwargs) + except ValueError: + deserialized[key] = None + return deserialized + + if obj_type == list: + deserialized = [] + for obj in attr: + try: + deserialized.append(self.deserialize_object(obj, **kwargs)) + except ValueError: + pass + return deserialized + + error = "Cannot deserialize generic object with type: " + raise TypeError(error + str(obj_type)) + + def deserialize_basic(self, attr, data_type): # pylint: disable=too-many-return-statements + """Deserialize basic builtin data type from string. + Will attempt to convert to str, int, float and bool. + This function will also accept '1', '0', 'true' and 'false' as + valid bool values. + + :param str attr: response string to be deserialized. + :param str data_type: deserialization data type. + :return: Deserialized basic type. + :rtype: str, int, float or bool + :raises TypeError: if string format is not valid. + """ + # If we're here, data is supposed to be a basic type. + # If it's still an XML node, take the text + if isinstance(attr, ET.Element): + attr = attr.text + if not attr: + if data_type == "str": + # None or '', node is empty string. + return "" + # None or '', node with a strong type is None. + # Don't try to model "empty bool" or "empty int" + return None + + if data_type == "bool": + if attr in [True, False, 1, 0]: + return bool(attr) + if isinstance(attr, str): + if attr.lower() in ["true", "1"]: + return True + if attr.lower() in ["false", "0"]: + return False + raise TypeError("Invalid boolean value: {}".format(attr)) + + if data_type == "str": + return self.deserialize_unicode(attr) + return eval(data_type)(attr) # nosec # pylint: disable=eval-used + + @staticmethod + def deserialize_unicode(data): + """Preserve unicode objects in Python 2, otherwise return data + as a string. + + :param str data: response string to be deserialized. + :return: Deserialized string. + :rtype: str or unicode + """ + # We might be here because we have an enum modeled as string, + # and we try to deserialize a partial dict with enum inside + if isinstance(data, Enum): + return data + + # Consider this is real string + try: + if isinstance(data, unicode): # type: ignore + return data + except NameError: + return str(data) + return str(data) + + @staticmethod + def deserialize_enum(data, enum_obj): + """Deserialize string into enum object. + + If the string is not a valid enum value it will be returned as-is + and a warning will be logged. + + :param str data: Response string to be deserialized. If this value is + None or invalid it will be returned as-is. + :param Enum enum_obj: Enum object to deserialize to. + :return: Deserialized enum object. + :rtype: Enum + """ + if isinstance(data, enum_obj) or data is None: + return data + if isinstance(data, Enum): + data = data.value + if isinstance(data, int): + # Workaround. We might consider remove it in the future. + try: + return list(enum_obj.__members__.values())[data] + except IndexError as exc: + error = "{!r} is not a valid index for enum {!r}" + raise DeserializationError(error.format(data, enum_obj)) from exc + try: + return enum_obj(str(data)) + except ValueError: + for enum_value in enum_obj: + if enum_value.value.lower() == str(data).lower(): + return enum_value + # We don't fail anymore for unknown value, we deserialize as a string + _LOGGER.warning("Deserializer is not able to find %s as valid enum in %s", data, enum_obj) + return Deserializer.deserialize_unicode(data) + + @staticmethod + def deserialize_bytearray(attr): + """Deserialize string into bytearray. + + :param str attr: response string to be deserialized. + :return: Deserialized bytearray + :rtype: bytearray + :raises TypeError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + return bytearray(b64decode(attr)) # type: ignore + + @staticmethod + def deserialize_base64(attr): + """Deserialize base64 encoded string into string. + + :param str attr: response string to be deserialized. + :return: Deserialized base64 string + :rtype: bytearray + :raises TypeError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + padding = "=" * (3 - (len(attr) + 3) % 4) # type: ignore + attr = attr + padding # type: ignore + encoded = attr.replace("-", "+").replace("_", "/") + return b64decode(encoded) + + @staticmethod + def deserialize_decimal(attr): + """Deserialize string into Decimal object. + + :param str attr: response string to be deserialized. + :return: Deserialized decimal + :raises DeserializationError: if string format invalid. + :rtype: decimal + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + return decimal.Decimal(str(attr)) # type: ignore + except decimal.DecimalException as err: + msg = "Invalid decimal {}".format(attr) + raise DeserializationError(msg) from err + + @staticmethod + def deserialize_long(attr): + """Deserialize string into long (Py2) or int (Py3). + + :param str attr: response string to be deserialized. + :return: Deserialized int + :rtype: long or int + :raises ValueError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + return _long_type(attr) # type: ignore + + @staticmethod + def deserialize_duration(attr): + """Deserialize ISO-8601 formatted string into TimeDelta object. + + :param str attr: response string to be deserialized. + :return: Deserialized duration + :rtype: TimeDelta + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + duration = isodate.parse_duration(attr) + except (ValueError, OverflowError, AttributeError) as err: + msg = "Cannot deserialize duration object." + raise DeserializationError(msg) from err + return duration + + @staticmethod + def deserialize_date(attr): + """Deserialize ISO-8601 formatted string into Date object. + + :param str attr: response string to be deserialized. + :return: Deserialized date + :rtype: Date + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + if re.search(r"[^\W\d_]", attr, re.I + re.U): # type: ignore + raise DeserializationError("Date must have only digits and -. Received: %s" % attr) + # This must NOT use defaultmonth/defaultday. Using None ensure this raises an exception. + return isodate.parse_date(attr, defaultmonth=0, defaultday=0) + + @staticmethod + def deserialize_time(attr): + """Deserialize ISO-8601 formatted string into time object. + + :param str attr: response string to be deserialized. + :return: Deserialized time + :rtype: datetime.time + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + if re.search(r"[^\W\d_]", attr, re.I + re.U): # type: ignore + raise DeserializationError("Date must have only digits and -. Received: %s" % attr) + return isodate.parse_time(attr) + + @staticmethod + def deserialize_rfc(attr): + """Deserialize RFC-1123 formatted string into Datetime object. + + :param str attr: response string to be deserialized. + :return: Deserialized RFC datetime + :rtype: Datetime + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + parsed_date = email.utils.parsedate_tz(attr) # type: ignore + date_obj = datetime.datetime( + *parsed_date[:6], tzinfo=datetime.timezone(datetime.timedelta(minutes=(parsed_date[9] or 0) / 60)) + ) + if not date_obj.tzinfo: + date_obj = date_obj.astimezone(tz=TZ_UTC) + except ValueError as err: + msg = "Cannot deserialize to rfc datetime object." + raise DeserializationError(msg) from err + return date_obj + + @staticmethod + def deserialize_iso(attr): + """Deserialize ISO-8601 formatted string into Datetime object. + + :param str attr: response string to be deserialized. + :return: Deserialized ISO datetime + :rtype: Datetime + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + attr = attr.upper() # type: ignore + match = Deserializer.valid_date.match(attr) + if not match: + raise ValueError("Invalid datetime string: " + attr) + + check_decimal = attr.split(".") + if len(check_decimal) > 1: + decimal_str = "" + for digit in check_decimal[1]: + if digit.isdigit(): + decimal_str += digit + else: + break + if len(decimal_str) > 6: + attr = attr.replace(decimal_str, decimal_str[0:6]) + + date_obj = isodate.parse_datetime(attr) + test_utc = date_obj.utctimetuple() + if test_utc.tm_year > 9999 or test_utc.tm_year < 1: + raise OverflowError("Hit max or min date") + except (ValueError, OverflowError, AttributeError) as err: + msg = "Cannot deserialize datetime object." + raise DeserializationError(msg) from err + return date_obj + + @staticmethod + def deserialize_unix(attr): + """Serialize Datetime object into IntTime format. + This is represented as seconds. + + :param int attr: Object to be serialized. + :return: Deserialized datetime + :rtype: Datetime + :raises DeserializationError: if format invalid + """ + if isinstance(attr, ET.Element): + attr = int(attr.text) # type: ignore + try: + attr = int(attr) + date_obj = datetime.datetime.fromtimestamp(attr, TZ_UTC) + except ValueError as err: + msg = "Cannot deserialize to unix datetime object." + raise DeserializationError(msg) from err + return date_obj diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ModelFlatteningVersionTolerant/modelflatteningversiontolerant/_utils/utils.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ModelFlatteningVersionTolerant/modelflatteningversiontolerant/_utils/utils.py new file mode 100644 index 00000000000..39b612f39a9 --- /dev/null +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ModelFlatteningVersionTolerant/modelflatteningversiontolerant/_utils/utils.py @@ -0,0 +1,25 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from abc import ABC +from typing import Generic, TYPE_CHECKING, TypeVar + +if TYPE_CHECKING: + from .serialization import Deserializer, Serializer + + +TClient = TypeVar("TClient") +TConfig = TypeVar("TConfig") + + +class ClientMixinABC(ABC, Generic[TClient, TConfig]): + """DO NOT use this class. It is for internal typing use only.""" + + _client: TClient + _config: TConfig + _serialize: "Serializer" + _deserialize: "Deserializer" diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ModelFlatteningVersionTolerant/modelflatteningversiontolerant/_vendor.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ModelFlatteningVersionTolerant/modelflatteningversiontolerant/_vendor.py deleted file mode 100644 index fb5eb8adf2b..00000000000 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ModelFlatteningVersionTolerant/modelflatteningversiontolerant/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) AutoRest Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import AutoRestResourceFlatteningTestServiceConfiguration - -if TYPE_CHECKING: - from azure.core import PipelineClient - - from ._serialization import Deserializer, Serializer - - -class AutoRestResourceFlatteningTestServiceMixinABC(ABC): # pylint: disable=name-too-long - """DO NOT use this class. It is for internal typing use only.""" - - _client: "PipelineClient" - _config: AutoRestResourceFlatteningTestServiceConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ModelFlatteningVersionTolerant/modelflatteningversiontolerant/aio/_client.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ModelFlatteningVersionTolerant/modelflatteningversiontolerant/aio/_client.py index a3442cd5ebe..cac25fcefc0 100644 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ModelFlatteningVersionTolerant/modelflatteningversiontolerant/aio/_client.py +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ModelFlatteningVersionTolerant/modelflatteningversiontolerant/aio/_client.py @@ -14,7 +14,7 @@ from azure.core.pipeline import policies from azure.core.rest import AsyncHttpResponse, HttpRequest -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import AutoRestResourceFlatteningTestServiceConfiguration from ._operations import AutoRestResourceFlatteningTestServiceOperationsMixin diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ModelFlatteningVersionTolerant/modelflatteningversiontolerant/aio/_operations/_operations.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ModelFlatteningVersionTolerant/modelflatteningversiontolerant/aio/_operations/_operations.py index ec4cf616a14..f2f1cafa589 100644 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ModelFlatteningVersionTolerant/modelflatteningversiontolerant/aio/_operations/_operations.py +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ModelFlatteningVersionTolerant/modelflatteningversiontolerant/aio/_operations/_operations.py @@ -10,6 +10,7 @@ from io import IOBase from typing import Any, Callable, Dict, IO, List, Optional, TypeVar, Union, cast, overload +from azure.core import AsyncPipelineClient from azure.core.exceptions import ( ClientAuthenticationError, HttpResponseError, @@ -36,7 +37,8 @@ build_auto_rest_resource_flattening_test_service_put_simple_product_with_grouping_request, build_auto_rest_resource_flattening_test_service_put_wrapped_array_request, ) -from .._vendor import AutoRestResourceFlatteningTestServiceMixinABC +from ..._utils.utils import ClientMixinABC +from .._configuration import AutoRestResourceFlatteningTestServiceConfiguration JSON = MutableMapping[str, Any] T = TypeVar("T") @@ -44,7 +46,7 @@ class AutoRestResourceFlatteningTestServiceOperationsMixin( # pylint: disable=name-too-long - AutoRestResourceFlatteningTestServiceMixinABC + ClientMixinABC[AsyncPipelineClient, AutoRestResourceFlatteningTestServiceConfiguration] ): @overload diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ModelFlatteningVersionTolerant/modelflatteningversiontolerant/aio/_vendor.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ModelFlatteningVersionTolerant/modelflatteningversiontolerant/aio/_vendor.py deleted file mode 100644 index bb2abe11703..00000000000 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ModelFlatteningVersionTolerant/modelflatteningversiontolerant/aio/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) AutoRest Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import AutoRestResourceFlatteningTestServiceConfiguration - -if TYPE_CHECKING: - from azure.core import AsyncPipelineClient - - from .._serialization import Deserializer, Serializer - - -class AutoRestResourceFlatteningTestServiceMixinABC(ABC): # pylint: disable=name-too-long - """DO NOT use this class. It is for internal typing use only.""" - - _client: "AsyncPipelineClient" - _config: AutoRestResourceFlatteningTestServiceConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/MultipleInheritanceVersionTolerant/multipleinheritanceversiontolerant/_client.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/MultipleInheritanceVersionTolerant/multipleinheritanceversiontolerant/_client.py index 385649690be..cd031e32cc9 100644 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/MultipleInheritanceVersionTolerant/multipleinheritanceversiontolerant/_client.py +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/MultipleInheritanceVersionTolerant/multipleinheritanceversiontolerant/_client.py @@ -16,7 +16,7 @@ from ._configuration import MultipleInheritanceServiceClientConfiguration from ._operations import MultipleInheritanceServiceClientOperationsMixin -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer class MultipleInheritanceServiceClient( diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/MultipleInheritanceVersionTolerant/multipleinheritanceversiontolerant/_operations/_operations.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/MultipleInheritanceVersionTolerant/multipleinheritanceversiontolerant/_operations/_operations.py index 387345090cf..14dfce62ac6 100644 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/MultipleInheritanceVersionTolerant/multipleinheritanceversiontolerant/_operations/_operations.py +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/MultipleInheritanceVersionTolerant/multipleinheritanceversiontolerant/_operations/_operations.py @@ -10,6 +10,7 @@ from io import IOBase from typing import Any, Callable, Dict, IO, Optional, TypeVar, Union, cast, overload +from azure.core import PipelineClient from azure.core.exceptions import ( ClientAuthenticationError, HttpResponseError, @@ -23,8 +24,9 @@ from azure.core.tracing.decorator import distributed_trace from azure.core.utils import case_insensitive_dict -from .._serialization import Serializer -from .._vendor import MultipleInheritanceServiceClientMixinABC +from .._configuration import MultipleInheritanceServiceClientConfiguration +from .._utils.serialization import Serializer +from .._utils.utils import ClientMixinABC JSON = MutableMapping[str, Any] T = TypeVar("T") @@ -198,7 +200,7 @@ def build_multiple_inheritance_service_put_kitten_request( # pylint: disable=na class MultipleInheritanceServiceClientOperationsMixin( # pylint: disable=name-too-long - MultipleInheritanceServiceClientMixinABC + ClientMixinABC[PipelineClient, MultipleInheritanceServiceClientConfiguration] ): @distributed_trace diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/MultipleInheritanceVersionTolerant/multipleinheritanceversiontolerant/_utils/__init__.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/MultipleInheritanceVersionTolerant/multipleinheritanceversiontolerant/_utils/__init__.py new file mode 100644 index 00000000000..0af9b28f660 --- /dev/null +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/MultipleInheritanceVersionTolerant/multipleinheritanceversiontolerant/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/MultipleInheritanceVersionTolerant/multipleinheritanceversiontolerant/_utils/serialization.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/MultipleInheritanceVersionTolerant/multipleinheritanceversiontolerant/_utils/serialization.py new file mode 100644 index 00000000000..f5187701d7b --- /dev/null +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/MultipleInheritanceVersionTolerant/multipleinheritanceversiontolerant/_utils/serialization.py @@ -0,0 +1,2032 @@ +# pylint: disable=line-too-long,useless-suppression,too-many-lines +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +# pyright: reportUnnecessaryTypeIgnoreComment=false + +from base64 import b64decode, b64encode +import calendar +import datetime +import decimal +import email +from enum import Enum +import json +import logging +import re +import sys +import codecs +from typing import ( + Dict, + Any, + cast, + Optional, + Union, + AnyStr, + IO, + Mapping, + Callable, + MutableMapping, + List, +) + +try: + from urllib import quote # type: ignore +except ImportError: + from urllib.parse import quote +import xml.etree.ElementTree as ET + +import isodate # type: ignore +from typing_extensions import Self + +from azure.core.exceptions import DeserializationError, SerializationError +from azure.core.serialization import NULL as CoreNull + +_BOM = codecs.BOM_UTF8.decode(encoding="utf-8") + +JSON = MutableMapping[str, Any] + + +class RawDeserializer: + + # Accept "text" because we're open minded people... + JSON_REGEXP = re.compile(r"^(application|text)/([a-z+.]+\+)?json$") + + # Name used in context + CONTEXT_NAME = "deserialized_data" + + @classmethod + def deserialize_from_text(cls, data: Optional[Union[AnyStr, IO]], content_type: Optional[str] = None) -> Any: + """Decode data according to content-type. + + Accept a stream of data as well, but will be load at once in memory for now. + + If no content-type, will return the string version (not bytes, not stream) + + :param data: Input, could be bytes or stream (will be decoded with UTF8) or text + :type data: str or bytes or IO + :param str content_type: The content type. + :return: The deserialized data. + :rtype: object + """ + if hasattr(data, "read"): + # Assume a stream + data = cast(IO, data).read() + + if isinstance(data, bytes): + data_as_str = data.decode(encoding="utf-8-sig") + else: + # Explain to mypy the correct type. + data_as_str = cast(str, data) + + # Remove Byte Order Mark if present in string + data_as_str = data_as_str.lstrip(_BOM) + + if content_type is None: + return data + + if cls.JSON_REGEXP.match(content_type): + try: + return json.loads(data_as_str) + except ValueError as err: + raise DeserializationError("JSON is invalid: {}".format(err), err) from err + elif "xml" in (content_type or []): + try: + + try: + if isinstance(data, unicode): # type: ignore + # If I'm Python 2.7 and unicode XML will scream if I try a "fromstring" on unicode string + data_as_str = data_as_str.encode(encoding="utf-8") # type: ignore + except NameError: + pass + + return ET.fromstring(data_as_str) # nosec + except ET.ParseError as err: + # It might be because the server has an issue, and returned JSON with + # content-type XML.... + # So let's try a JSON load, and if it's still broken + # let's flow the initial exception + def _json_attemp(data): + try: + return True, json.loads(data) + except ValueError: + return False, None # Don't care about this one + + success, json_result = _json_attemp(data) + if success: + return json_result + # If i'm here, it's not JSON, it's not XML, let's scream + # and raise the last context in this block (the XML exception) + # The function hack is because Py2.7 messes up with exception + # context otherwise. + _LOGGER.critical("Wasn't XML not JSON, failing") + raise DeserializationError("XML is invalid") from err + elif content_type.startswith("text/"): + return data_as_str + raise DeserializationError("Cannot deserialize content-type: {}".format(content_type)) + + @classmethod + def deserialize_from_http_generics(cls, body_bytes: Optional[Union[AnyStr, IO]], headers: Mapping) -> Any: + """Deserialize from HTTP response. + + Use bytes and headers to NOT use any requests/aiohttp or whatever + specific implementation. + Headers will tested for "content-type" + + :param bytes body_bytes: The body of the response. + :param dict headers: The headers of the response. + :returns: The deserialized data. + :rtype: object + """ + # Try to use content-type from headers if available + content_type = None + if "content-type" in headers: + content_type = headers["content-type"].split(";")[0].strip().lower() + # Ouch, this server did not declare what it sent... + # Let's guess it's JSON... + # Also, since Autorest was considering that an empty body was a valid JSON, + # need that test as well.... + else: + content_type = "application/json" + + if body_bytes: + return cls.deserialize_from_text(body_bytes, content_type) + return None + + +_LOGGER = logging.getLogger(__name__) + +try: + _long_type = long # type: ignore +except NameError: + _long_type = int + +TZ_UTC = datetime.timezone.utc + +_FLATTEN = re.compile(r"(? None: + self.additional_properties: Optional[Dict[str, Any]] = {} + for k in kwargs: # pylint: disable=consider-using-dict-items + if k not in self._attribute_map: + _LOGGER.warning("%s is not a known attribute of class %s and will be ignored", k, self.__class__) + elif k in self._validation and self._validation[k].get("readonly", False): + _LOGGER.warning("Readonly attribute %s will be ignored in class %s", k, self.__class__) + else: + setattr(self, k, kwargs[k]) + + def __eq__(self, other: Any) -> bool: + """Compare objects by comparing all attributes. + + :param object other: The object to compare + :returns: True if objects are equal + :rtype: bool + """ + if isinstance(other, self.__class__): + return self.__dict__ == other.__dict__ + return False + + def __ne__(self, other: Any) -> bool: + """Compare objects by comparing all attributes. + + :param object other: The object to compare + :returns: True if objects are not equal + :rtype: bool + """ + return not self.__eq__(other) + + def __str__(self) -> str: + return str(self.__dict__) + + @classmethod + def enable_additional_properties_sending(cls) -> None: + cls._attribute_map["additional_properties"] = {"key": "", "type": "{object}"} + + @classmethod + def is_xml_model(cls) -> bool: + try: + cls._xml_map # type: ignore + except AttributeError: + return False + return True + + @classmethod + def _create_xml_node(cls): + """Create XML node. + + :returns: The XML node + :rtype: xml.etree.ElementTree.Element + """ + try: + xml_map = cls._xml_map # type: ignore + except AttributeError: + xml_map = {} + + return _create_xml_node(xml_map.get("name", cls.__name__), xml_map.get("prefix", None), xml_map.get("ns", None)) + + def serialize(self, keep_readonly: bool = False, **kwargs: Any) -> JSON: + """Return the JSON that would be sent to server from this model. + + This is an alias to `as_dict(full_restapi_key_transformer, keep_readonly=False)`. + + If you want XML serialization, you can pass the kwargs is_xml=True. + + :param bool keep_readonly: If you want to serialize the readonly attributes + :returns: A dict JSON compatible object + :rtype: dict + """ + serializer = Serializer(self._infer_class_models()) + return serializer._serialize( # type: ignore # pylint: disable=protected-access + self, keep_readonly=keep_readonly, **kwargs + ) + + def as_dict( + self, + keep_readonly: bool = True, + key_transformer: Callable[[str, Dict[str, Any], Any], Any] = attribute_transformer, + **kwargs: Any + ) -> JSON: + """Return a dict that can be serialized using json.dump. + + Advanced usage might optionally use a callback as parameter: + + .. code::python + + def my_key_transformer(key, attr_desc, value): + return key + + Key is the attribute name used in Python. Attr_desc + is a dict of metadata. Currently contains 'type' with the + msrest type and 'key' with the RestAPI encoded key. + Value is the current value in this object. + + The string returned will be used to serialize the key. + If the return type is a list, this is considered hierarchical + result dict. + + See the three examples in this file: + + - attribute_transformer + - full_restapi_key_transformer + - last_restapi_key_transformer + + If you want XML serialization, you can pass the kwargs is_xml=True. + + :param bool keep_readonly: If you want to serialize the readonly attributes + :param function key_transformer: A key transformer function. + :returns: A dict JSON compatible object + :rtype: dict + """ + serializer = Serializer(self._infer_class_models()) + return serializer._serialize( # type: ignore # pylint: disable=protected-access + self, key_transformer=key_transformer, keep_readonly=keep_readonly, **kwargs + ) + + @classmethod + def _infer_class_models(cls): + try: + str_models = cls.__module__.rsplit(".", 1)[0] + models = sys.modules[str_models] + client_models = {k: v for k, v in models.__dict__.items() if isinstance(v, type)} + if cls.__name__ not in client_models: + raise ValueError("Not Autorest generated code") + except Exception: # pylint: disable=broad-exception-caught + # Assume it's not Autorest generated (tests?). Add ourselves as dependencies. + client_models = {cls.__name__: cls} + return client_models + + @classmethod + def deserialize(cls, data: Any, content_type: Optional[str] = None) -> Self: + """Parse a str using the RestAPI syntax and return a model. + + :param str data: A str using RestAPI structure. JSON by default. + :param str content_type: JSON by default, set application/xml if XML. + :returns: An instance of this model + :raises DeserializationError: if something went wrong + :rtype: Self + """ + deserializer = Deserializer(cls._infer_class_models()) + return deserializer(cls.__name__, data, content_type=content_type) # type: ignore + + @classmethod + def from_dict( + cls, + data: Any, + key_extractors: Optional[Callable[[str, Dict[str, Any], Any], Any]] = None, + content_type: Optional[str] = None, + ) -> Self: + """Parse a dict using given key extractor return a model. + + By default consider key + extractors (rest_key_case_insensitive_extractor, attribute_key_case_insensitive_extractor + and last_rest_key_case_insensitive_extractor) + + :param dict data: A dict using RestAPI structure + :param function key_extractors: A key extractor function. + :param str content_type: JSON by default, set application/xml if XML. + :returns: An instance of this model + :raises DeserializationError: if something went wrong + :rtype: Self + """ + deserializer = Deserializer(cls._infer_class_models()) + deserializer.key_extractors = ( # type: ignore + [ # type: ignore + attribute_key_case_insensitive_extractor, + rest_key_case_insensitive_extractor, + last_rest_key_case_insensitive_extractor, + ] + if key_extractors is None + else key_extractors + ) + return deserializer(cls.__name__, data, content_type=content_type) # type: ignore + + @classmethod + def _flatten_subtype(cls, key, objects): + if "_subtype_map" not in cls.__dict__: + return {} + result = dict(cls._subtype_map[key]) + for valuetype in cls._subtype_map[key].values(): + result.update(objects[valuetype]._flatten_subtype(key, objects)) # pylint: disable=protected-access + return result + + @classmethod + def _classify(cls, response, objects): + """Check the class _subtype_map for any child classes. + We want to ignore any inherited _subtype_maps. + + :param dict response: The initial data + :param dict objects: The class objects + :returns: The class to be used + :rtype: class + """ + for subtype_key in cls.__dict__.get("_subtype_map", {}).keys(): + subtype_value = None + + if not isinstance(response, ET.Element): + rest_api_response_key = cls._get_rest_key_parts(subtype_key)[-1] + subtype_value = response.get(rest_api_response_key, None) or response.get(subtype_key, None) + else: + subtype_value = xml_key_extractor(subtype_key, cls._attribute_map[subtype_key], response) + if subtype_value: + # Try to match base class. Can be class name only + # (bug to fix in Autorest to support x-ms-discriminator-name) + if cls.__name__ == subtype_value: + return cls + flatten_mapping_type = cls._flatten_subtype(subtype_key, objects) + try: + return objects[flatten_mapping_type[subtype_value]] # type: ignore + except KeyError: + _LOGGER.warning( + "Subtype value %s has no mapping, use base class %s.", + subtype_value, + cls.__name__, + ) + break + else: + _LOGGER.warning("Discriminator %s is absent or null, use base class %s.", subtype_key, cls.__name__) + break + return cls + + @classmethod + def _get_rest_key_parts(cls, attr_key): + """Get the RestAPI key of this attr, split it and decode part + :param str attr_key: Attribute key must be in attribute_map. + :returns: A list of RestAPI part + :rtype: list + """ + rest_split_key = _FLATTEN.split(cls._attribute_map[attr_key]["key"]) + return [_decode_attribute_map_key(key_part) for key_part in rest_split_key] + + +def _decode_attribute_map_key(key): + """This decode a key in an _attribute_map to the actual key we want to look at + inside the received data. + + :param str key: A key string from the generated code + :returns: The decoded key + :rtype: str + """ + return key.replace("\\.", ".") + + +class Serializer: # pylint: disable=too-many-public-methods + """Request object model serializer.""" + + basic_types = {str: "str", int: "int", bool: "bool", float: "float"} + + _xml_basic_types_serializers = {"bool": lambda x: str(x).lower()} + days = {0: "Mon", 1: "Tue", 2: "Wed", 3: "Thu", 4: "Fri", 5: "Sat", 6: "Sun"} + months = { + 1: "Jan", + 2: "Feb", + 3: "Mar", + 4: "Apr", + 5: "May", + 6: "Jun", + 7: "Jul", + 8: "Aug", + 9: "Sep", + 10: "Oct", + 11: "Nov", + 12: "Dec", + } + validation = { + "min_length": lambda x, y: len(x) < y, + "max_length": lambda x, y: len(x) > y, + "minimum": lambda x, y: x < y, + "maximum": lambda x, y: x > y, + "minimum_ex": lambda x, y: x <= y, + "maximum_ex": lambda x, y: x >= y, + "min_items": lambda x, y: len(x) < y, + "max_items": lambda x, y: len(x) > y, + "pattern": lambda x, y: not re.match(y, x, re.UNICODE), + "unique": lambda x, y: len(x) != len(set(x)), + "multiple": lambda x, y: x % y != 0, + } + + def __init__(self, classes: Optional[Mapping[str, type]] = None) -> None: + self.serialize_type = { + "iso-8601": Serializer.serialize_iso, + "rfc-1123": Serializer.serialize_rfc, + "unix-time": Serializer.serialize_unix, + "duration": Serializer.serialize_duration, + "date": Serializer.serialize_date, + "time": Serializer.serialize_time, + "decimal": Serializer.serialize_decimal, + "long": Serializer.serialize_long, + "bytearray": Serializer.serialize_bytearray, + "base64": Serializer.serialize_base64, + "object": self.serialize_object, + "[]": self.serialize_iter, + "{}": self.serialize_dict, + } + self.dependencies: Dict[str, type] = dict(classes) if classes else {} + self.key_transformer = full_restapi_key_transformer + self.client_side_validation = True + + def _serialize( # pylint: disable=too-many-nested-blocks, too-many-branches, too-many-statements, too-many-locals + self, target_obj, data_type=None, **kwargs + ): + """Serialize data into a string according to type. + + :param object target_obj: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str, dict + :raises SerializationError: if serialization fails. + :returns: The serialized data. + """ + key_transformer = kwargs.get("key_transformer", self.key_transformer) + keep_readonly = kwargs.get("keep_readonly", False) + if target_obj is None: + return None + + attr_name = None + class_name = target_obj.__class__.__name__ + + if data_type: + return self.serialize_data(target_obj, data_type, **kwargs) + + if not hasattr(target_obj, "_attribute_map"): + data_type = type(target_obj).__name__ + if data_type in self.basic_types.values(): + return self.serialize_data(target_obj, data_type, **kwargs) + + # Force "is_xml" kwargs if we detect a XML model + try: + is_xml_model_serialization = kwargs["is_xml"] + except KeyError: + is_xml_model_serialization = kwargs.setdefault("is_xml", target_obj.is_xml_model()) + + serialized = {} + if is_xml_model_serialization: + serialized = target_obj._create_xml_node() # pylint: disable=protected-access + try: + attributes = target_obj._attribute_map # pylint: disable=protected-access + for attr, attr_desc in attributes.items(): + attr_name = attr + if not keep_readonly and target_obj._validation.get( # pylint: disable=protected-access + attr_name, {} + ).get("readonly", False): + continue + + if attr_name == "additional_properties" and attr_desc["key"] == "": + if target_obj.additional_properties is not None: + serialized.update(target_obj.additional_properties) + continue + try: + + orig_attr = getattr(target_obj, attr) + if is_xml_model_serialization: + pass # Don't provide "transformer" for XML for now. Keep "orig_attr" + else: # JSON + keys, orig_attr = key_transformer(attr, attr_desc.copy(), orig_attr) + keys = keys if isinstance(keys, list) else [keys] + + kwargs["serialization_ctxt"] = attr_desc + new_attr = self.serialize_data(orig_attr, attr_desc["type"], **kwargs) + + if is_xml_model_serialization: + xml_desc = attr_desc.get("xml", {}) + xml_name = xml_desc.get("name", attr_desc["key"]) + xml_prefix = xml_desc.get("prefix", None) + xml_ns = xml_desc.get("ns", None) + if xml_desc.get("attr", False): + if xml_ns: + ET.register_namespace(xml_prefix, xml_ns) + xml_name = "{{{}}}{}".format(xml_ns, xml_name) + serialized.set(xml_name, new_attr) # type: ignore + continue + if xml_desc.get("text", False): + serialized.text = new_attr # type: ignore + continue + if isinstance(new_attr, list): + serialized.extend(new_attr) # type: ignore + elif isinstance(new_attr, ET.Element): + # If the down XML has no XML/Name, + # we MUST replace the tag with the local tag. But keeping the namespaces. + if "name" not in getattr(orig_attr, "_xml_map", {}): + splitted_tag = new_attr.tag.split("}") + if len(splitted_tag) == 2: # Namespace + new_attr.tag = "}".join([splitted_tag[0], xml_name]) + else: + new_attr.tag = xml_name + serialized.append(new_attr) # type: ignore + else: # That's a basic type + # Integrate namespace if necessary + local_node = _create_xml_node(xml_name, xml_prefix, xml_ns) + local_node.text = str(new_attr) + serialized.append(local_node) # type: ignore + else: # JSON + for k in reversed(keys): # type: ignore + new_attr = {k: new_attr} + + _new_attr = new_attr + _serialized = serialized + for k in keys: # type: ignore + if k not in _serialized: + _serialized.update(_new_attr) # type: ignore + _new_attr = _new_attr[k] # type: ignore + _serialized = _serialized[k] + except ValueError as err: + if isinstance(err, SerializationError): + raise + + except (AttributeError, KeyError, TypeError) as err: + msg = "Attribute {} in object {} cannot be serialized.\n{}".format(attr_name, class_name, str(target_obj)) + raise SerializationError(msg) from err + return serialized + + def body(self, data, data_type, **kwargs): + """Serialize data intended for a request body. + + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: dict + :raises SerializationError: if serialization fails. + :raises ValueError: if data is None + :returns: The serialized request body + """ + + # Just in case this is a dict + internal_data_type_str = data_type.strip("[]{}") + internal_data_type = self.dependencies.get(internal_data_type_str, None) + try: + is_xml_model_serialization = kwargs["is_xml"] + except KeyError: + if internal_data_type and issubclass(internal_data_type, Model): + is_xml_model_serialization = kwargs.setdefault("is_xml", internal_data_type.is_xml_model()) + else: + is_xml_model_serialization = False + if internal_data_type and not isinstance(internal_data_type, Enum): + try: + deserializer = Deserializer(self.dependencies) + # Since it's on serialization, it's almost sure that format is not JSON REST + # We're not able to deal with additional properties for now. + deserializer.additional_properties_detection = False + if is_xml_model_serialization: + deserializer.key_extractors = [ # type: ignore + attribute_key_case_insensitive_extractor, + ] + else: + deserializer.key_extractors = [ + rest_key_case_insensitive_extractor, + attribute_key_case_insensitive_extractor, + last_rest_key_case_insensitive_extractor, + ] + data = deserializer._deserialize(data_type, data) # pylint: disable=protected-access + except DeserializationError as err: + raise SerializationError("Unable to build a model: " + str(err)) from err + + return self._serialize(data, data_type, **kwargs) + + def url(self, name, data, data_type, **kwargs): + """Serialize data intended for a URL path. + + :param str name: The name of the URL path parameter. + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str + :returns: The serialized URL path + :raises TypeError: if serialization fails. + :raises ValueError: if data is None + """ + try: + output = self.serialize_data(data, data_type, **kwargs) + if data_type == "bool": + output = json.dumps(output) + + if kwargs.get("skip_quote") is True: + output = str(output) + output = output.replace("{", quote("{")).replace("}", quote("}")) + else: + output = quote(str(output), safe="") + except SerializationError as exc: + raise TypeError("{} must be type {}.".format(name, data_type)) from exc + return output + + def query(self, name, data, data_type, **kwargs): + """Serialize data intended for a URL query. + + :param str name: The name of the query parameter. + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str, list + :raises TypeError: if serialization fails. + :raises ValueError: if data is None + :returns: The serialized query parameter + """ + try: + # Treat the list aside, since we don't want to encode the div separator + if data_type.startswith("["): + internal_data_type = data_type[1:-1] + do_quote = not kwargs.get("skip_quote", False) + return self.serialize_iter(data, internal_data_type, do_quote=do_quote, **kwargs) + + # Not a list, regular serialization + output = self.serialize_data(data, data_type, **kwargs) + if data_type == "bool": + output = json.dumps(output) + if kwargs.get("skip_quote") is True: + output = str(output) + else: + output = quote(str(output), safe="") + except SerializationError as exc: + raise TypeError("{} must be type {}.".format(name, data_type)) from exc + return str(output) + + def header(self, name, data, data_type, **kwargs): + """Serialize data intended for a request header. + + :param str name: The name of the header. + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str + :raises TypeError: if serialization fails. + :raises ValueError: if data is None + :returns: The serialized header + """ + try: + if data_type in ["[str]"]: + data = ["" if d is None else d for d in data] + + output = self.serialize_data(data, data_type, **kwargs) + if data_type == "bool": + output = json.dumps(output) + except SerializationError as exc: + raise TypeError("{} must be type {}.".format(name, data_type)) from exc + return str(output) + + def serialize_data(self, data, data_type, **kwargs): + """Serialize generic data according to supplied data type. + + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :raises AttributeError: if required data is None. + :raises ValueError: if data is None + :raises SerializationError: if serialization fails. + :returns: The serialized data. + :rtype: str, int, float, bool, dict, list + """ + if data is None: + raise ValueError("No value for given attribute") + + try: + if data is CoreNull: + return None + if data_type in self.basic_types.values(): + return self.serialize_basic(data, data_type, **kwargs) + + if data_type in self.serialize_type: + return self.serialize_type[data_type](data, **kwargs) + + # If dependencies is empty, try with current data class + # It has to be a subclass of Enum anyway + enum_type = self.dependencies.get(data_type, data.__class__) + if issubclass(enum_type, Enum): + return Serializer.serialize_enum(data, enum_obj=enum_type) + + iter_type = data_type[0] + data_type[-1] + if iter_type in self.serialize_type: + return self.serialize_type[iter_type](data, data_type[1:-1], **kwargs) + + except (ValueError, TypeError) as err: + msg = "Unable to serialize value: {!r} as type: {!r}." + raise SerializationError(msg.format(data, data_type)) from err + return self._serialize(data, **kwargs) + + @classmethod + def _get_custom_serializers(cls, data_type, **kwargs): # pylint: disable=inconsistent-return-statements + custom_serializer = kwargs.get("basic_types_serializers", {}).get(data_type) + if custom_serializer: + return custom_serializer + if kwargs.get("is_xml", False): + return cls._xml_basic_types_serializers.get(data_type) + + @classmethod + def serialize_basic(cls, data, data_type, **kwargs): + """Serialize basic builting data type. + Serializes objects to str, int, float or bool. + + Possible kwargs: + - basic_types_serializers dict[str, callable] : If set, use the callable as serializer + - is_xml bool : If set, use xml_basic_types_serializers + + :param obj data: Object to be serialized. + :param str data_type: Type of object in the iterable. + :rtype: str, int, float, bool + :return: serialized object + """ + custom_serializer = cls._get_custom_serializers(data_type, **kwargs) + if custom_serializer: + return custom_serializer(data) + if data_type == "str": + return cls.serialize_unicode(data) + return eval(data_type)(data) # nosec # pylint: disable=eval-used + + @classmethod + def serialize_unicode(cls, data): + """Special handling for serializing unicode strings in Py2. + Encode to UTF-8 if unicode, otherwise handle as a str. + + :param str data: Object to be serialized. + :rtype: str + :return: serialized object + """ + try: # If I received an enum, return its value + return data.value + except AttributeError: + pass + + try: + if isinstance(data, unicode): # type: ignore + # Don't change it, JSON and XML ElementTree are totally able + # to serialize correctly u'' strings + return data + except NameError: + return str(data) + return str(data) + + def serialize_iter(self, data, iter_type, div=None, **kwargs): + """Serialize iterable. + + Supported kwargs: + - serialization_ctxt dict : The current entry of _attribute_map, or same format. + serialization_ctxt['type'] should be same as data_type. + - is_xml bool : If set, serialize as XML + + :param list data: Object to be serialized. + :param str iter_type: Type of object in the iterable. + :param str div: If set, this str will be used to combine the elements + in the iterable into a combined string. Default is 'None'. + Defaults to False. + :rtype: list, str + :return: serialized iterable + """ + if isinstance(data, str): + raise SerializationError("Refuse str type as a valid iter type.") + + serialization_ctxt = kwargs.get("serialization_ctxt", {}) + is_xml = kwargs.get("is_xml", False) + + serialized = [] + for d in data: + try: + serialized.append(self.serialize_data(d, iter_type, **kwargs)) + except ValueError as err: + if isinstance(err, SerializationError): + raise + serialized.append(None) + + if kwargs.get("do_quote", False): + serialized = ["" if s is None else quote(str(s), safe="") for s in serialized] + + if div: + serialized = ["" if s is None else str(s) for s in serialized] + serialized = div.join(serialized) + + if "xml" in serialization_ctxt or is_xml: + # XML serialization is more complicated + xml_desc = serialization_ctxt.get("xml", {}) + xml_name = xml_desc.get("name") + if not xml_name: + xml_name = serialization_ctxt["key"] + + # Create a wrap node if necessary (use the fact that Element and list have "append") + is_wrapped = xml_desc.get("wrapped", False) + node_name = xml_desc.get("itemsName", xml_name) + if is_wrapped: + final_result = _create_xml_node(xml_name, xml_desc.get("prefix", None), xml_desc.get("ns", None)) + else: + final_result = [] + # All list elements to "local_node" + for el in serialized: + if isinstance(el, ET.Element): + el_node = el + else: + el_node = _create_xml_node(node_name, xml_desc.get("prefix", None), xml_desc.get("ns", None)) + if el is not None: # Otherwise it writes "None" :-p + el_node.text = str(el) + final_result.append(el_node) + return final_result + return serialized + + def serialize_dict(self, attr, dict_type, **kwargs): + """Serialize a dictionary of objects. + + :param dict attr: Object to be serialized. + :param str dict_type: Type of object in the dictionary. + :rtype: dict + :return: serialized dictionary + """ + serialization_ctxt = kwargs.get("serialization_ctxt", {}) + serialized = {} + for key, value in attr.items(): + try: + serialized[self.serialize_unicode(key)] = self.serialize_data(value, dict_type, **kwargs) + except ValueError as err: + if isinstance(err, SerializationError): + raise + serialized[self.serialize_unicode(key)] = None + + if "xml" in serialization_ctxt: + # XML serialization is more complicated + xml_desc = serialization_ctxt["xml"] + xml_name = xml_desc["name"] + + final_result = _create_xml_node(xml_name, xml_desc.get("prefix", None), xml_desc.get("ns", None)) + for key, value in serialized.items(): + ET.SubElement(final_result, key).text = value + return final_result + + return serialized + + def serialize_object(self, attr, **kwargs): # pylint: disable=too-many-return-statements + """Serialize a generic object. + This will be handled as a dictionary. If object passed in is not + a basic type (str, int, float, dict, list) it will simply be + cast to str. + + :param dict attr: Object to be serialized. + :rtype: dict or str + :return: serialized object + """ + if attr is None: + return None + if isinstance(attr, ET.Element): + return attr + obj_type = type(attr) + if obj_type in self.basic_types: + return self.serialize_basic(attr, self.basic_types[obj_type], **kwargs) + if obj_type is _long_type: + return self.serialize_long(attr) + if obj_type is str: + return self.serialize_unicode(attr) + if obj_type is datetime.datetime: + return self.serialize_iso(attr) + if obj_type is datetime.date: + return self.serialize_date(attr) + if obj_type is datetime.time: + return self.serialize_time(attr) + if obj_type is datetime.timedelta: + return self.serialize_duration(attr) + if obj_type is decimal.Decimal: + return self.serialize_decimal(attr) + + # If it's a model or I know this dependency, serialize as a Model + if obj_type in self.dependencies.values() or isinstance(attr, Model): + return self._serialize(attr) + + if obj_type == dict: + serialized = {} + for key, value in attr.items(): + try: + serialized[self.serialize_unicode(key)] = self.serialize_object(value, **kwargs) + except ValueError: + serialized[self.serialize_unicode(key)] = None + return serialized + + if obj_type == list: + serialized = [] + for obj in attr: + try: + serialized.append(self.serialize_object(obj, **kwargs)) + except ValueError: + pass + return serialized + return str(attr) + + @staticmethod + def serialize_enum(attr, enum_obj=None): + try: + result = attr.value + except AttributeError: + result = attr + try: + enum_obj(result) # type: ignore + return result + except ValueError as exc: + for enum_value in enum_obj: # type: ignore + if enum_value.value.lower() == str(attr).lower(): + return enum_value.value + error = "{!r} is not valid value for enum {!r}" + raise SerializationError(error.format(attr, enum_obj)) from exc + + @staticmethod + def serialize_bytearray(attr, **kwargs): # pylint: disable=unused-argument + """Serialize bytearray into base-64 string. + + :param str attr: Object to be serialized. + :rtype: str + :return: serialized base64 + """ + return b64encode(attr).decode() + + @staticmethod + def serialize_base64(attr, **kwargs): # pylint: disable=unused-argument + """Serialize str into base-64 string. + + :param str attr: Object to be serialized. + :rtype: str + :return: serialized base64 + """ + encoded = b64encode(attr).decode("ascii") + return encoded.strip("=").replace("+", "-").replace("/", "_") + + @staticmethod + def serialize_decimal(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Decimal object to float. + + :param decimal attr: Object to be serialized. + :rtype: float + :return: serialized decimal + """ + return float(attr) + + @staticmethod + def serialize_long(attr, **kwargs): # pylint: disable=unused-argument + """Serialize long (Py2) or int (Py3). + + :param int attr: Object to be serialized. + :rtype: int/long + :return: serialized long + """ + return _long_type(attr) + + @staticmethod + def serialize_date(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Date object into ISO-8601 formatted string. + + :param Date attr: Object to be serialized. + :rtype: str + :return: serialized date + """ + if isinstance(attr, str): + attr = isodate.parse_date(attr) + t = "{:04}-{:02}-{:02}".format(attr.year, attr.month, attr.day) + return t + + @staticmethod + def serialize_time(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Time object into ISO-8601 formatted string. + + :param datetime.time attr: Object to be serialized. + :rtype: str + :return: serialized time + """ + if isinstance(attr, str): + attr = isodate.parse_time(attr) + t = "{:02}:{:02}:{:02}".format(attr.hour, attr.minute, attr.second) + if attr.microsecond: + t += ".{:02}".format(attr.microsecond) + return t + + @staticmethod + def serialize_duration(attr, **kwargs): # pylint: disable=unused-argument + """Serialize TimeDelta object into ISO-8601 formatted string. + + :param TimeDelta attr: Object to be serialized. + :rtype: str + :return: serialized duration + """ + if isinstance(attr, str): + attr = isodate.parse_duration(attr) + return isodate.duration_isoformat(attr) + + @staticmethod + def serialize_rfc(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Datetime object into RFC-1123 formatted string. + + :param Datetime attr: Object to be serialized. + :rtype: str + :raises TypeError: if format invalid. + :return: serialized rfc + """ + try: + if not attr.tzinfo: + _LOGGER.warning("Datetime with no tzinfo will be considered UTC.") + utc = attr.utctimetuple() + except AttributeError as exc: + raise TypeError("RFC1123 object must be valid Datetime object.") from exc + + return "{}, {:02} {} {:04} {:02}:{:02}:{:02} GMT".format( + Serializer.days[utc.tm_wday], + utc.tm_mday, + Serializer.months[utc.tm_mon], + utc.tm_year, + utc.tm_hour, + utc.tm_min, + utc.tm_sec, + ) + + @staticmethod + def serialize_iso(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Datetime object into ISO-8601 formatted string. + + :param Datetime attr: Object to be serialized. + :rtype: str + :raises SerializationError: if format invalid. + :return: serialized iso + """ + if isinstance(attr, str): + attr = isodate.parse_datetime(attr) + try: + if not attr.tzinfo: + _LOGGER.warning("Datetime with no tzinfo will be considered UTC.") + utc = attr.utctimetuple() + if utc.tm_year > 9999 or utc.tm_year < 1: + raise OverflowError("Hit max or min date") + + microseconds = str(attr.microsecond).rjust(6, "0").rstrip("0").ljust(3, "0") + if microseconds: + microseconds = "." + microseconds + date = "{:04}-{:02}-{:02}T{:02}:{:02}:{:02}".format( + utc.tm_year, utc.tm_mon, utc.tm_mday, utc.tm_hour, utc.tm_min, utc.tm_sec + ) + return date + microseconds + "Z" + except (ValueError, OverflowError) as err: + msg = "Unable to serialize datetime object." + raise SerializationError(msg) from err + except AttributeError as err: + msg = "ISO-8601 object must be valid Datetime object." + raise TypeError(msg) from err + + @staticmethod + def serialize_unix(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Datetime object into IntTime format. + This is represented as seconds. + + :param Datetime attr: Object to be serialized. + :rtype: int + :raises SerializationError: if format invalid + :return: serialied unix + """ + if isinstance(attr, int): + return attr + try: + if not attr.tzinfo: + _LOGGER.warning("Datetime with no tzinfo will be considered UTC.") + return int(calendar.timegm(attr.utctimetuple())) + except AttributeError as exc: + raise TypeError("Unix time object must be valid Datetime object.") from exc + + +def rest_key_extractor(attr, attr_desc, data): # pylint: disable=unused-argument + key = attr_desc["key"] + working_data = data + + while "." in key: + # Need the cast, as for some reasons "split" is typed as list[str | Any] + dict_keys = cast(List[str], _FLATTEN.split(key)) + if len(dict_keys) == 1: + key = _decode_attribute_map_key(dict_keys[0]) + break + working_key = _decode_attribute_map_key(dict_keys[0]) + working_data = working_data.get(working_key, data) + if working_data is None: + # If at any point while following flatten JSON path see None, it means + # that all properties under are None as well + return None + key = ".".join(dict_keys[1:]) + + return working_data.get(key) + + +def rest_key_case_insensitive_extractor( # pylint: disable=unused-argument, inconsistent-return-statements + attr, attr_desc, data +): + key = attr_desc["key"] + working_data = data + + while "." in key: + dict_keys = _FLATTEN.split(key) + if len(dict_keys) == 1: + key = _decode_attribute_map_key(dict_keys[0]) + break + working_key = _decode_attribute_map_key(dict_keys[0]) + working_data = attribute_key_case_insensitive_extractor(working_key, None, working_data) + if working_data is None: + # If at any point while following flatten JSON path see None, it means + # that all properties under are None as well + return None + key = ".".join(dict_keys[1:]) + + if working_data: + return attribute_key_case_insensitive_extractor(key, None, working_data) + + +def last_rest_key_extractor(attr, attr_desc, data): # pylint: disable=unused-argument + """Extract the attribute in "data" based on the last part of the JSON path key. + + :param str attr: The attribute to extract + :param dict attr_desc: The attribute description + :param dict data: The data to extract from + :rtype: object + :returns: The extracted attribute + """ + key = attr_desc["key"] + dict_keys = _FLATTEN.split(key) + return attribute_key_extractor(dict_keys[-1], None, data) + + +def last_rest_key_case_insensitive_extractor(attr, attr_desc, data): # pylint: disable=unused-argument + """Extract the attribute in "data" based on the last part of the JSON path key. + + This is the case insensitive version of "last_rest_key_extractor" + :param str attr: The attribute to extract + :param dict attr_desc: The attribute description + :param dict data: The data to extract from + :rtype: object + :returns: The extracted attribute + """ + key = attr_desc["key"] + dict_keys = _FLATTEN.split(key) + return attribute_key_case_insensitive_extractor(dict_keys[-1], None, data) + + +def attribute_key_extractor(attr, _, data): + return data.get(attr) + + +def attribute_key_case_insensitive_extractor(attr, _, data): + found_key = None + lower_attr = attr.lower() + for key in data: + if lower_attr == key.lower(): + found_key = key + break + + return data.get(found_key) + + +def _extract_name_from_internal_type(internal_type): + """Given an internal type XML description, extract correct XML name with namespace. + + :param dict internal_type: An model type + :rtype: tuple + :returns: A tuple XML name + namespace dict + """ + internal_type_xml_map = getattr(internal_type, "_xml_map", {}) + xml_name = internal_type_xml_map.get("name", internal_type.__name__) + xml_ns = internal_type_xml_map.get("ns", None) + if xml_ns: + xml_name = "{{{}}}{}".format(xml_ns, xml_name) + return xml_name + + +def xml_key_extractor(attr, attr_desc, data): # pylint: disable=unused-argument,too-many-return-statements + if isinstance(data, dict): + return None + + # Test if this model is XML ready first + if not isinstance(data, ET.Element): + return None + + xml_desc = attr_desc.get("xml", {}) + xml_name = xml_desc.get("name", attr_desc["key"]) + + # Look for a children + is_iter_type = attr_desc["type"].startswith("[") + is_wrapped = xml_desc.get("wrapped", False) + internal_type = attr_desc.get("internalType", None) + internal_type_xml_map = getattr(internal_type, "_xml_map", {}) + + # Integrate namespace if necessary + xml_ns = xml_desc.get("ns", internal_type_xml_map.get("ns", None)) + if xml_ns: + xml_name = "{{{}}}{}".format(xml_ns, xml_name) + + # If it's an attribute, that's simple + if xml_desc.get("attr", False): + return data.get(xml_name) + + # If it's x-ms-text, that's simple too + if xml_desc.get("text", False): + return data.text + + # Scenario where I take the local name: + # - Wrapped node + # - Internal type is an enum (considered basic types) + # - Internal type has no XML/Name node + if is_wrapped or (internal_type and (issubclass(internal_type, Enum) or "name" not in internal_type_xml_map)): + children = data.findall(xml_name) + # If internal type has a local name and it's not a list, I use that name + elif not is_iter_type and internal_type and "name" in internal_type_xml_map: + xml_name = _extract_name_from_internal_type(internal_type) + children = data.findall(xml_name) + # That's an array + else: + if internal_type: # Complex type, ignore itemsName and use the complex type name + items_name = _extract_name_from_internal_type(internal_type) + else: + items_name = xml_desc.get("itemsName", xml_name) + children = data.findall(items_name) + + if len(children) == 0: + if is_iter_type: + if is_wrapped: + return None # is_wrapped no node, we want None + return [] # not wrapped, assume empty list + return None # Assume it's not there, maybe an optional node. + + # If is_iter_type and not wrapped, return all found children + if is_iter_type: + if not is_wrapped: + return children + # Iter and wrapped, should have found one node only (the wrap one) + if len(children) != 1: + raise DeserializationError( + "Tried to deserialize an array not wrapped, and found several nodes '{}'. Maybe you should declare this array as wrapped?".format( + xml_name + ) + ) + return list(children[0]) # Might be empty list and that's ok. + + # Here it's not a itertype, we should have found one element only or empty + if len(children) > 1: + raise DeserializationError("Find several XML '{}' where it was not expected".format(xml_name)) + return children[0] + + +class Deserializer: + """Response object model deserializer. + + :param dict classes: Class type dictionary for deserializing complex types. + :ivar list key_extractors: Ordered list of extractors to be used by this deserializer. + """ + + basic_types = {str: "str", int: "int", bool: "bool", float: "float"} + + valid_date = re.compile(r"\d{4}[-]\d{2}[-]\d{2}T\d{2}:\d{2}:\d{2}\.?\d*Z?[-+]?[\d{2}]?:?[\d{2}]?") + + def __init__(self, classes: Optional[Mapping[str, type]] = None) -> None: + self.deserialize_type = { + "iso-8601": Deserializer.deserialize_iso, + "rfc-1123": Deserializer.deserialize_rfc, + "unix-time": Deserializer.deserialize_unix, + "duration": Deserializer.deserialize_duration, + "date": Deserializer.deserialize_date, + "time": Deserializer.deserialize_time, + "decimal": Deserializer.deserialize_decimal, + "long": Deserializer.deserialize_long, + "bytearray": Deserializer.deserialize_bytearray, + "base64": Deserializer.deserialize_base64, + "object": self.deserialize_object, + "[]": self.deserialize_iter, + "{}": self.deserialize_dict, + } + self.deserialize_expected_types = { + "duration": (isodate.Duration, datetime.timedelta), + "iso-8601": (datetime.datetime), + } + self.dependencies: Dict[str, type] = dict(classes) if classes else {} + self.key_extractors = [rest_key_extractor, xml_key_extractor] + # Additional properties only works if the "rest_key_extractor" is used to + # extract the keys. Making it to work whatever the key extractor is too much + # complicated, with no real scenario for now. + # So adding a flag to disable additional properties detection. This flag should be + # used if your expect the deserialization to NOT come from a JSON REST syntax. + # Otherwise, result are unexpected + self.additional_properties_detection = True + + def __call__(self, target_obj, response_data, content_type=None): + """Call the deserializer to process a REST response. + + :param str target_obj: Target data type to deserialize to. + :param requests.Response response_data: REST response object. + :param str content_type: Swagger "produces" if available. + :raises DeserializationError: if deserialization fails. + :return: Deserialized object. + :rtype: object + """ + data = self._unpack_content(response_data, content_type) + return self._deserialize(target_obj, data) + + def _deserialize(self, target_obj, data): # pylint: disable=inconsistent-return-statements + """Call the deserializer on a model. + + Data needs to be already deserialized as JSON or XML ElementTree + + :param str target_obj: Target data type to deserialize to. + :param object data: Object to deserialize. + :raises DeserializationError: if deserialization fails. + :return: Deserialized object. + :rtype: object + """ + # This is already a model, go recursive just in case + if hasattr(data, "_attribute_map"): + constants = [name for name, config in getattr(data, "_validation", {}).items() if config.get("constant")] + try: + for attr, mapconfig in data._attribute_map.items(): # pylint: disable=protected-access + if attr in constants: + continue + value = getattr(data, attr) + if value is None: + continue + local_type = mapconfig["type"] + internal_data_type = local_type.strip("[]{}") + if internal_data_type not in self.dependencies or isinstance(internal_data_type, Enum): + continue + setattr(data, attr, self._deserialize(local_type, value)) + return data + except AttributeError: + return + + response, class_name = self._classify_target(target_obj, data) + + if isinstance(response, str): + return self.deserialize_data(data, response) + if isinstance(response, type) and issubclass(response, Enum): + return self.deserialize_enum(data, response) + + if data is None or data is CoreNull: + return data + try: + attributes = response._attribute_map # type: ignore # pylint: disable=protected-access + d_attrs = {} + for attr, attr_desc in attributes.items(): + # Check empty string. If it's not empty, someone has a real "additionalProperties"... + if attr == "additional_properties" and attr_desc["key"] == "": + continue + raw_value = None + # Enhance attr_desc with some dynamic data + attr_desc = attr_desc.copy() # Do a copy, do not change the real one + internal_data_type = attr_desc["type"].strip("[]{}") + if internal_data_type in self.dependencies: + attr_desc["internalType"] = self.dependencies[internal_data_type] + + for key_extractor in self.key_extractors: + found_value = key_extractor(attr, attr_desc, data) + if found_value is not None: + if raw_value is not None and raw_value != found_value: + msg = ( + "Ignoring extracted value '%s' from %s for key '%s'" + " (duplicate extraction, follow extractors order)" + ) + _LOGGER.warning(msg, found_value, key_extractor, attr) + continue + raw_value = found_value + + value = self.deserialize_data(raw_value, attr_desc["type"]) + d_attrs[attr] = value + except (AttributeError, TypeError, KeyError) as err: + msg = "Unable to deserialize to object: " + class_name # type: ignore + raise DeserializationError(msg) from err + additional_properties = self._build_additional_properties(attributes, data) + return self._instantiate_model(response, d_attrs, additional_properties) + + def _build_additional_properties(self, attribute_map, data): + if not self.additional_properties_detection: + return None + if "additional_properties" in attribute_map and attribute_map.get("additional_properties", {}).get("key") != "": + # Check empty string. If it's not empty, someone has a real "additionalProperties" + return None + if isinstance(data, ET.Element): + data = {el.tag: el.text for el in data} + + known_keys = { + _decode_attribute_map_key(_FLATTEN.split(desc["key"])[0]) + for desc in attribute_map.values() + if desc["key"] != "" + } + present_keys = set(data.keys()) + missing_keys = present_keys - known_keys + return {key: data[key] for key in missing_keys} + + def _classify_target(self, target, data): + """Check to see whether the deserialization target object can + be classified into a subclass. + Once classification has been determined, initialize object. + + :param str target: The target object type to deserialize to. + :param str/dict data: The response data to deserialize. + :return: The classified target object and its class name. + :rtype: tuple + """ + if target is None: + return None, None + + if isinstance(target, str): + try: + target = self.dependencies[target] + except KeyError: + return target, target + + try: + target = target._classify(data, self.dependencies) # type: ignore # pylint: disable=protected-access + except AttributeError: + pass # Target is not a Model, no classify + return target, target.__class__.__name__ # type: ignore + + def failsafe_deserialize(self, target_obj, data, content_type=None): + """Ignores any errors encountered in deserialization, + and falls back to not deserializing the object. Recommended + for use in error deserialization, as we want to return the + HttpResponseError to users, and not have them deal with + a deserialization error. + + :param str target_obj: The target object type to deserialize to. + :param str/dict data: The response data to deserialize. + :param str content_type: Swagger "produces" if available. + :return: Deserialized object. + :rtype: object + """ + try: + return self(target_obj, data, content_type=content_type) + except: # pylint: disable=bare-except + _LOGGER.debug( + "Ran into a deserialization error. Ignoring since this is failsafe deserialization", exc_info=True + ) + return None + + @staticmethod + def _unpack_content(raw_data, content_type=None): + """Extract the correct structure for deserialization. + + If raw_data is a PipelineResponse, try to extract the result of RawDeserializer. + if we can't, raise. Your Pipeline should have a RawDeserializer. + + If not a pipeline response and raw_data is bytes or string, use content-type + to decode it. If no content-type, try JSON. + + If raw_data is something else, bypass all logic and return it directly. + + :param obj raw_data: Data to be processed. + :param str content_type: How to parse if raw_data is a string/bytes. + :raises JSONDecodeError: If JSON is requested and parsing is impossible. + :raises UnicodeDecodeError: If bytes is not UTF8 + :rtype: object + :return: Unpacked content. + """ + # Assume this is enough to detect a Pipeline Response without importing it + context = getattr(raw_data, "context", {}) + if context: + if RawDeserializer.CONTEXT_NAME in context: + return context[RawDeserializer.CONTEXT_NAME] + raise ValueError("This pipeline didn't have the RawDeserializer policy; can't deserialize") + + # Assume this is enough to recognize universal_http.ClientResponse without importing it + if hasattr(raw_data, "body"): + return RawDeserializer.deserialize_from_http_generics(raw_data.text(), raw_data.headers) + + # Assume this enough to recognize requests.Response without importing it. + if hasattr(raw_data, "_content_consumed"): + return RawDeserializer.deserialize_from_http_generics(raw_data.text, raw_data.headers) + + if isinstance(raw_data, (str, bytes)) or hasattr(raw_data, "read"): + return RawDeserializer.deserialize_from_text(raw_data, content_type) # type: ignore + return raw_data + + def _instantiate_model(self, response, attrs, additional_properties=None): + """Instantiate a response model passing in deserialized args. + + :param Response response: The response model class. + :param dict attrs: The deserialized response attributes. + :param dict additional_properties: Additional properties to be set. + :rtype: Response + :return: The instantiated response model. + """ + if callable(response): + subtype = getattr(response, "_subtype_map", {}) + try: + readonly = [ + k + for k, v in response._validation.items() # pylint: disable=protected-access # type: ignore + if v.get("readonly") + ] + const = [ + k + for k, v in response._validation.items() # pylint: disable=protected-access # type: ignore + if v.get("constant") + ] + kwargs = {k: v for k, v in attrs.items() if k not in subtype and k not in readonly + const} + response_obj = response(**kwargs) + for attr in readonly: + setattr(response_obj, attr, attrs.get(attr)) + if additional_properties: + response_obj.additional_properties = additional_properties # type: ignore + return response_obj + except TypeError as err: + msg = "Unable to deserialize {} into model {}. ".format(kwargs, response) # type: ignore + raise DeserializationError(msg + str(err)) from err + else: + try: + for attr, value in attrs.items(): + setattr(response, attr, value) + return response + except Exception as exp: + msg = "Unable to populate response model. " + msg += "Type: {}, Error: {}".format(type(response), exp) + raise DeserializationError(msg) from exp + + def deserialize_data(self, data, data_type): # pylint: disable=too-many-return-statements + """Process data for deserialization according to data type. + + :param str data: The response string to be deserialized. + :param str data_type: The type to deserialize to. + :raises DeserializationError: if deserialization fails. + :return: Deserialized object. + :rtype: object + """ + if data is None: + return data + + try: + if not data_type: + return data + if data_type in self.basic_types.values(): + return self.deserialize_basic(data, data_type) + if data_type in self.deserialize_type: + if isinstance(data, self.deserialize_expected_types.get(data_type, tuple())): + return data + + is_a_text_parsing_type = lambda x: x not in [ # pylint: disable=unnecessary-lambda-assignment + "object", + "[]", + r"{}", + ] + if isinstance(data, ET.Element) and is_a_text_parsing_type(data_type) and not data.text: + return None + data_val = self.deserialize_type[data_type](data) + return data_val + + iter_type = data_type[0] + data_type[-1] + if iter_type in self.deserialize_type: + return self.deserialize_type[iter_type](data, data_type[1:-1]) + + obj_type = self.dependencies[data_type] + if issubclass(obj_type, Enum): + if isinstance(data, ET.Element): + data = data.text + return self.deserialize_enum(data, obj_type) + + except (ValueError, TypeError, AttributeError) as err: + msg = "Unable to deserialize response data." + msg += " Data: {}, {}".format(data, data_type) + raise DeserializationError(msg) from err + return self._deserialize(obj_type, data) + + def deserialize_iter(self, attr, iter_type): + """Deserialize an iterable. + + :param list attr: Iterable to be deserialized. + :param str iter_type: The type of object in the iterable. + :return: Deserialized iterable. + :rtype: list + """ + if attr is None: + return None + if isinstance(attr, ET.Element): # If I receive an element here, get the children + attr = list(attr) + if not isinstance(attr, (list, set)): + raise DeserializationError("Cannot deserialize as [{}] an object of type {}".format(iter_type, type(attr))) + return [self.deserialize_data(a, iter_type) for a in attr] + + def deserialize_dict(self, attr, dict_type): + """Deserialize a dictionary. + + :param dict/list attr: Dictionary to be deserialized. Also accepts + a list of key, value pairs. + :param str dict_type: The object type of the items in the dictionary. + :return: Deserialized dictionary. + :rtype: dict + """ + if isinstance(attr, list): + return {x["key"]: self.deserialize_data(x["value"], dict_type) for x in attr} + + if isinstance(attr, ET.Element): + # Transform value into {"Key": "value"} + attr = {el.tag: el.text for el in attr} + return {k: self.deserialize_data(v, dict_type) for k, v in attr.items()} + + def deserialize_object(self, attr, **kwargs): # pylint: disable=too-many-return-statements + """Deserialize a generic object. + This will be handled as a dictionary. + + :param dict attr: Dictionary to be deserialized. + :return: Deserialized object. + :rtype: dict + :raises TypeError: if non-builtin datatype encountered. + """ + if attr is None: + return None + if isinstance(attr, ET.Element): + # Do no recurse on XML, just return the tree as-is + return attr + if isinstance(attr, str): + return self.deserialize_basic(attr, "str") + obj_type = type(attr) + if obj_type in self.basic_types: + return self.deserialize_basic(attr, self.basic_types[obj_type]) + if obj_type is _long_type: + return self.deserialize_long(attr) + + if obj_type == dict: + deserialized = {} + for key, value in attr.items(): + try: + deserialized[key] = self.deserialize_object(value, **kwargs) + except ValueError: + deserialized[key] = None + return deserialized + + if obj_type == list: + deserialized = [] + for obj in attr: + try: + deserialized.append(self.deserialize_object(obj, **kwargs)) + except ValueError: + pass + return deserialized + + error = "Cannot deserialize generic object with type: " + raise TypeError(error + str(obj_type)) + + def deserialize_basic(self, attr, data_type): # pylint: disable=too-many-return-statements + """Deserialize basic builtin data type from string. + Will attempt to convert to str, int, float and bool. + This function will also accept '1', '0', 'true' and 'false' as + valid bool values. + + :param str attr: response string to be deserialized. + :param str data_type: deserialization data type. + :return: Deserialized basic type. + :rtype: str, int, float or bool + :raises TypeError: if string format is not valid. + """ + # If we're here, data is supposed to be a basic type. + # If it's still an XML node, take the text + if isinstance(attr, ET.Element): + attr = attr.text + if not attr: + if data_type == "str": + # None or '', node is empty string. + return "" + # None or '', node with a strong type is None. + # Don't try to model "empty bool" or "empty int" + return None + + if data_type == "bool": + if attr in [True, False, 1, 0]: + return bool(attr) + if isinstance(attr, str): + if attr.lower() in ["true", "1"]: + return True + if attr.lower() in ["false", "0"]: + return False + raise TypeError("Invalid boolean value: {}".format(attr)) + + if data_type == "str": + return self.deserialize_unicode(attr) + return eval(data_type)(attr) # nosec # pylint: disable=eval-used + + @staticmethod + def deserialize_unicode(data): + """Preserve unicode objects in Python 2, otherwise return data + as a string. + + :param str data: response string to be deserialized. + :return: Deserialized string. + :rtype: str or unicode + """ + # We might be here because we have an enum modeled as string, + # and we try to deserialize a partial dict with enum inside + if isinstance(data, Enum): + return data + + # Consider this is real string + try: + if isinstance(data, unicode): # type: ignore + return data + except NameError: + return str(data) + return str(data) + + @staticmethod + def deserialize_enum(data, enum_obj): + """Deserialize string into enum object. + + If the string is not a valid enum value it will be returned as-is + and a warning will be logged. + + :param str data: Response string to be deserialized. If this value is + None or invalid it will be returned as-is. + :param Enum enum_obj: Enum object to deserialize to. + :return: Deserialized enum object. + :rtype: Enum + """ + if isinstance(data, enum_obj) or data is None: + return data + if isinstance(data, Enum): + data = data.value + if isinstance(data, int): + # Workaround. We might consider remove it in the future. + try: + return list(enum_obj.__members__.values())[data] + except IndexError as exc: + error = "{!r} is not a valid index for enum {!r}" + raise DeserializationError(error.format(data, enum_obj)) from exc + try: + return enum_obj(str(data)) + except ValueError: + for enum_value in enum_obj: + if enum_value.value.lower() == str(data).lower(): + return enum_value + # We don't fail anymore for unknown value, we deserialize as a string + _LOGGER.warning("Deserializer is not able to find %s as valid enum in %s", data, enum_obj) + return Deserializer.deserialize_unicode(data) + + @staticmethod + def deserialize_bytearray(attr): + """Deserialize string into bytearray. + + :param str attr: response string to be deserialized. + :return: Deserialized bytearray + :rtype: bytearray + :raises TypeError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + return bytearray(b64decode(attr)) # type: ignore + + @staticmethod + def deserialize_base64(attr): + """Deserialize base64 encoded string into string. + + :param str attr: response string to be deserialized. + :return: Deserialized base64 string + :rtype: bytearray + :raises TypeError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + padding = "=" * (3 - (len(attr) + 3) % 4) # type: ignore + attr = attr + padding # type: ignore + encoded = attr.replace("-", "+").replace("_", "/") + return b64decode(encoded) + + @staticmethod + def deserialize_decimal(attr): + """Deserialize string into Decimal object. + + :param str attr: response string to be deserialized. + :return: Deserialized decimal + :raises DeserializationError: if string format invalid. + :rtype: decimal + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + return decimal.Decimal(str(attr)) # type: ignore + except decimal.DecimalException as err: + msg = "Invalid decimal {}".format(attr) + raise DeserializationError(msg) from err + + @staticmethod + def deserialize_long(attr): + """Deserialize string into long (Py2) or int (Py3). + + :param str attr: response string to be deserialized. + :return: Deserialized int + :rtype: long or int + :raises ValueError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + return _long_type(attr) # type: ignore + + @staticmethod + def deserialize_duration(attr): + """Deserialize ISO-8601 formatted string into TimeDelta object. + + :param str attr: response string to be deserialized. + :return: Deserialized duration + :rtype: TimeDelta + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + duration = isodate.parse_duration(attr) + except (ValueError, OverflowError, AttributeError) as err: + msg = "Cannot deserialize duration object." + raise DeserializationError(msg) from err + return duration + + @staticmethod + def deserialize_date(attr): + """Deserialize ISO-8601 formatted string into Date object. + + :param str attr: response string to be deserialized. + :return: Deserialized date + :rtype: Date + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + if re.search(r"[^\W\d_]", attr, re.I + re.U): # type: ignore + raise DeserializationError("Date must have only digits and -. Received: %s" % attr) + # This must NOT use defaultmonth/defaultday. Using None ensure this raises an exception. + return isodate.parse_date(attr, defaultmonth=0, defaultday=0) + + @staticmethod + def deserialize_time(attr): + """Deserialize ISO-8601 formatted string into time object. + + :param str attr: response string to be deserialized. + :return: Deserialized time + :rtype: datetime.time + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + if re.search(r"[^\W\d_]", attr, re.I + re.U): # type: ignore + raise DeserializationError("Date must have only digits and -. Received: %s" % attr) + return isodate.parse_time(attr) + + @staticmethod + def deserialize_rfc(attr): + """Deserialize RFC-1123 formatted string into Datetime object. + + :param str attr: response string to be deserialized. + :return: Deserialized RFC datetime + :rtype: Datetime + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + parsed_date = email.utils.parsedate_tz(attr) # type: ignore + date_obj = datetime.datetime( + *parsed_date[:6], tzinfo=datetime.timezone(datetime.timedelta(minutes=(parsed_date[9] or 0) / 60)) + ) + if not date_obj.tzinfo: + date_obj = date_obj.astimezone(tz=TZ_UTC) + except ValueError as err: + msg = "Cannot deserialize to rfc datetime object." + raise DeserializationError(msg) from err + return date_obj + + @staticmethod + def deserialize_iso(attr): + """Deserialize ISO-8601 formatted string into Datetime object. + + :param str attr: response string to be deserialized. + :return: Deserialized ISO datetime + :rtype: Datetime + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + attr = attr.upper() # type: ignore + match = Deserializer.valid_date.match(attr) + if not match: + raise ValueError("Invalid datetime string: " + attr) + + check_decimal = attr.split(".") + if len(check_decimal) > 1: + decimal_str = "" + for digit in check_decimal[1]: + if digit.isdigit(): + decimal_str += digit + else: + break + if len(decimal_str) > 6: + attr = attr.replace(decimal_str, decimal_str[0:6]) + + date_obj = isodate.parse_datetime(attr) + test_utc = date_obj.utctimetuple() + if test_utc.tm_year > 9999 or test_utc.tm_year < 1: + raise OverflowError("Hit max or min date") + except (ValueError, OverflowError, AttributeError) as err: + msg = "Cannot deserialize datetime object." + raise DeserializationError(msg) from err + return date_obj + + @staticmethod + def deserialize_unix(attr): + """Serialize Datetime object into IntTime format. + This is represented as seconds. + + :param int attr: Object to be serialized. + :return: Deserialized datetime + :rtype: Datetime + :raises DeserializationError: if format invalid + """ + if isinstance(attr, ET.Element): + attr = int(attr.text) # type: ignore + try: + attr = int(attr) + date_obj = datetime.datetime.fromtimestamp(attr, TZ_UTC) + except ValueError as err: + msg = "Cannot deserialize to unix datetime object." + raise DeserializationError(msg) from err + return date_obj diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/MultipleInheritanceVersionTolerant/multipleinheritanceversiontolerant/_utils/utils.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/MultipleInheritanceVersionTolerant/multipleinheritanceversiontolerant/_utils/utils.py new file mode 100644 index 00000000000..39b612f39a9 --- /dev/null +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/MultipleInheritanceVersionTolerant/multipleinheritanceversiontolerant/_utils/utils.py @@ -0,0 +1,25 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from abc import ABC +from typing import Generic, TYPE_CHECKING, TypeVar + +if TYPE_CHECKING: + from .serialization import Deserializer, Serializer + + +TClient = TypeVar("TClient") +TConfig = TypeVar("TConfig") + + +class ClientMixinABC(ABC, Generic[TClient, TConfig]): + """DO NOT use this class. It is for internal typing use only.""" + + _client: TClient + _config: TConfig + _serialize: "Serializer" + _deserialize: "Deserializer" diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/MultipleInheritanceVersionTolerant/multipleinheritanceversiontolerant/_vendor.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/MultipleInheritanceVersionTolerant/multipleinheritanceversiontolerant/_vendor.py deleted file mode 100644 index 8a74180edd6..00000000000 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/MultipleInheritanceVersionTolerant/multipleinheritanceversiontolerant/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) AutoRest Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import MultipleInheritanceServiceClientConfiguration - -if TYPE_CHECKING: - from azure.core import PipelineClient - - from ._serialization import Deserializer, Serializer - - -class MultipleInheritanceServiceClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "PipelineClient" - _config: MultipleInheritanceServiceClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/MultipleInheritanceVersionTolerant/multipleinheritanceversiontolerant/aio/_client.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/MultipleInheritanceVersionTolerant/multipleinheritanceversiontolerant/aio/_client.py index e7e56063451..9875e7daada 100644 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/MultipleInheritanceVersionTolerant/multipleinheritanceversiontolerant/aio/_client.py +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/MultipleInheritanceVersionTolerant/multipleinheritanceversiontolerant/aio/_client.py @@ -14,7 +14,7 @@ from azure.core.pipeline import policies from azure.core.rest import AsyncHttpResponse, HttpRequest -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import MultipleInheritanceServiceClientConfiguration from ._operations import MultipleInheritanceServiceClientOperationsMixin diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/MultipleInheritanceVersionTolerant/multipleinheritanceversiontolerant/aio/_operations/_operations.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/MultipleInheritanceVersionTolerant/multipleinheritanceversiontolerant/aio/_operations/_operations.py index b3c86ae95b8..8e380a9f71e 100644 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/MultipleInheritanceVersionTolerant/multipleinheritanceversiontolerant/aio/_operations/_operations.py +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/MultipleInheritanceVersionTolerant/multipleinheritanceversiontolerant/aio/_operations/_operations.py @@ -10,6 +10,7 @@ from io import IOBase from typing import Any, Callable, Dict, IO, Optional, TypeVar, Union, cast, overload +from azure.core import AsyncPipelineClient from azure.core.exceptions import ( ClientAuthenticationError, HttpResponseError, @@ -35,7 +36,8 @@ build_multiple_inheritance_service_put_kitten_request, build_multiple_inheritance_service_put_pet_request, ) -from .._vendor import MultipleInheritanceServiceClientMixinABC +from ..._utils.utils import ClientMixinABC +from .._configuration import MultipleInheritanceServiceClientConfiguration JSON = MutableMapping[str, Any] T = TypeVar("T") @@ -43,7 +45,7 @@ class MultipleInheritanceServiceClientOperationsMixin( # pylint: disable=name-too-long - MultipleInheritanceServiceClientMixinABC + ClientMixinABC[AsyncPipelineClient, MultipleInheritanceServiceClientConfiguration] ): @distributed_trace_async diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/MultipleInheritanceVersionTolerant/multipleinheritanceversiontolerant/aio/_vendor.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/MultipleInheritanceVersionTolerant/multipleinheritanceversiontolerant/aio/_vendor.py deleted file mode 100644 index 457fe8c5636..00000000000 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/MultipleInheritanceVersionTolerant/multipleinheritanceversiontolerant/aio/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) AutoRest Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import MultipleInheritanceServiceClientConfiguration - -if TYPE_CHECKING: - from azure.core import AsyncPipelineClient - - from .._serialization import Deserializer, Serializer - - -class MultipleInheritanceServiceClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "AsyncPipelineClient" - _config: MultipleInheritanceServiceClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/NoNamespaceFlagVersionTolerant/anything_client/_client.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/NoNamespaceFlagVersionTolerant/anything_client/_client.py index 519f7a6d1d4..f85ae753b2c 100644 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/NoNamespaceFlagVersionTolerant/anything_client/_client.py +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/NoNamespaceFlagVersionTolerant/anything_client/_client.py @@ -16,7 +16,7 @@ from ._configuration import AnythingClientConfiguration from ._operations import AnythingClientOperationsMixin -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer class AnythingClient(AnythingClientOperationsMixin): # pylint: disable=client-accepts-api-version-keyword diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/NoNamespaceFlagVersionTolerant/anything_client/_operations/_operations.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/NoNamespaceFlagVersionTolerant/anything_client/_operations/_operations.py index cbc250e3733..19fd01b4b5f 100644 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/NoNamespaceFlagVersionTolerant/anything_client/_operations/_operations.py +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/NoNamespaceFlagVersionTolerant/anything_client/_operations/_operations.py @@ -8,6 +8,7 @@ from collections.abc import MutableMapping from typing import Any, Callable, Dict, Optional, TypeVar, cast +from azure.core import PipelineClient from azure.core.exceptions import ( ClientAuthenticationError, HttpResponseError, @@ -21,8 +22,9 @@ from azure.core.tracing.decorator import distributed_trace from azure.core.utils import case_insensitive_dict -from .._serialization import Serializer -from .._vendor import AnythingClientMixinABC +from .._configuration import AnythingClientConfiguration +from .._utils.serialization import Serializer +from .._utils.utils import ClientMixinABC T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] @@ -115,7 +117,7 @@ def build_anything_put_array_request(*, json: Any, **kwargs: Any) -> HttpRequest return HttpRequest(method="PUT", url=_url, headers=_headers, json=json, **kwargs) -class AnythingClientOperationsMixin(AnythingClientMixinABC): +class AnythingClientOperationsMixin(ClientMixinABC[PipelineClient, AnythingClientConfiguration]): @distributed_trace def get_object(self, **kwargs: Any) -> Any: diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/NoNamespaceFlagVersionTolerant/anything_client/_utils/__init__.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/NoNamespaceFlagVersionTolerant/anything_client/_utils/__init__.py new file mode 100644 index 00000000000..0af9b28f660 --- /dev/null +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/NoNamespaceFlagVersionTolerant/anything_client/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/NoNamespaceFlagVersionTolerant/anything_client/_utils/serialization.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/NoNamespaceFlagVersionTolerant/anything_client/_utils/serialization.py new file mode 100644 index 00000000000..f5187701d7b --- /dev/null +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/NoNamespaceFlagVersionTolerant/anything_client/_utils/serialization.py @@ -0,0 +1,2032 @@ +# pylint: disable=line-too-long,useless-suppression,too-many-lines +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +# pyright: reportUnnecessaryTypeIgnoreComment=false + +from base64 import b64decode, b64encode +import calendar +import datetime +import decimal +import email +from enum import Enum +import json +import logging +import re +import sys +import codecs +from typing import ( + Dict, + Any, + cast, + Optional, + Union, + AnyStr, + IO, + Mapping, + Callable, + MutableMapping, + List, +) + +try: + from urllib import quote # type: ignore +except ImportError: + from urllib.parse import quote +import xml.etree.ElementTree as ET + +import isodate # type: ignore +from typing_extensions import Self + +from azure.core.exceptions import DeserializationError, SerializationError +from azure.core.serialization import NULL as CoreNull + +_BOM = codecs.BOM_UTF8.decode(encoding="utf-8") + +JSON = MutableMapping[str, Any] + + +class RawDeserializer: + + # Accept "text" because we're open minded people... + JSON_REGEXP = re.compile(r"^(application|text)/([a-z+.]+\+)?json$") + + # Name used in context + CONTEXT_NAME = "deserialized_data" + + @classmethod + def deserialize_from_text(cls, data: Optional[Union[AnyStr, IO]], content_type: Optional[str] = None) -> Any: + """Decode data according to content-type. + + Accept a stream of data as well, but will be load at once in memory for now. + + If no content-type, will return the string version (not bytes, not stream) + + :param data: Input, could be bytes or stream (will be decoded with UTF8) or text + :type data: str or bytes or IO + :param str content_type: The content type. + :return: The deserialized data. + :rtype: object + """ + if hasattr(data, "read"): + # Assume a stream + data = cast(IO, data).read() + + if isinstance(data, bytes): + data_as_str = data.decode(encoding="utf-8-sig") + else: + # Explain to mypy the correct type. + data_as_str = cast(str, data) + + # Remove Byte Order Mark if present in string + data_as_str = data_as_str.lstrip(_BOM) + + if content_type is None: + return data + + if cls.JSON_REGEXP.match(content_type): + try: + return json.loads(data_as_str) + except ValueError as err: + raise DeserializationError("JSON is invalid: {}".format(err), err) from err + elif "xml" in (content_type or []): + try: + + try: + if isinstance(data, unicode): # type: ignore + # If I'm Python 2.7 and unicode XML will scream if I try a "fromstring" on unicode string + data_as_str = data_as_str.encode(encoding="utf-8") # type: ignore + except NameError: + pass + + return ET.fromstring(data_as_str) # nosec + except ET.ParseError as err: + # It might be because the server has an issue, and returned JSON with + # content-type XML.... + # So let's try a JSON load, and if it's still broken + # let's flow the initial exception + def _json_attemp(data): + try: + return True, json.loads(data) + except ValueError: + return False, None # Don't care about this one + + success, json_result = _json_attemp(data) + if success: + return json_result + # If i'm here, it's not JSON, it's not XML, let's scream + # and raise the last context in this block (the XML exception) + # The function hack is because Py2.7 messes up with exception + # context otherwise. + _LOGGER.critical("Wasn't XML not JSON, failing") + raise DeserializationError("XML is invalid") from err + elif content_type.startswith("text/"): + return data_as_str + raise DeserializationError("Cannot deserialize content-type: {}".format(content_type)) + + @classmethod + def deserialize_from_http_generics(cls, body_bytes: Optional[Union[AnyStr, IO]], headers: Mapping) -> Any: + """Deserialize from HTTP response. + + Use bytes and headers to NOT use any requests/aiohttp or whatever + specific implementation. + Headers will tested for "content-type" + + :param bytes body_bytes: The body of the response. + :param dict headers: The headers of the response. + :returns: The deserialized data. + :rtype: object + """ + # Try to use content-type from headers if available + content_type = None + if "content-type" in headers: + content_type = headers["content-type"].split(";")[0].strip().lower() + # Ouch, this server did not declare what it sent... + # Let's guess it's JSON... + # Also, since Autorest was considering that an empty body was a valid JSON, + # need that test as well.... + else: + content_type = "application/json" + + if body_bytes: + return cls.deserialize_from_text(body_bytes, content_type) + return None + + +_LOGGER = logging.getLogger(__name__) + +try: + _long_type = long # type: ignore +except NameError: + _long_type = int + +TZ_UTC = datetime.timezone.utc + +_FLATTEN = re.compile(r"(? None: + self.additional_properties: Optional[Dict[str, Any]] = {} + for k in kwargs: # pylint: disable=consider-using-dict-items + if k not in self._attribute_map: + _LOGGER.warning("%s is not a known attribute of class %s and will be ignored", k, self.__class__) + elif k in self._validation and self._validation[k].get("readonly", False): + _LOGGER.warning("Readonly attribute %s will be ignored in class %s", k, self.__class__) + else: + setattr(self, k, kwargs[k]) + + def __eq__(self, other: Any) -> bool: + """Compare objects by comparing all attributes. + + :param object other: The object to compare + :returns: True if objects are equal + :rtype: bool + """ + if isinstance(other, self.__class__): + return self.__dict__ == other.__dict__ + return False + + def __ne__(self, other: Any) -> bool: + """Compare objects by comparing all attributes. + + :param object other: The object to compare + :returns: True if objects are not equal + :rtype: bool + """ + return not self.__eq__(other) + + def __str__(self) -> str: + return str(self.__dict__) + + @classmethod + def enable_additional_properties_sending(cls) -> None: + cls._attribute_map["additional_properties"] = {"key": "", "type": "{object}"} + + @classmethod + def is_xml_model(cls) -> bool: + try: + cls._xml_map # type: ignore + except AttributeError: + return False + return True + + @classmethod + def _create_xml_node(cls): + """Create XML node. + + :returns: The XML node + :rtype: xml.etree.ElementTree.Element + """ + try: + xml_map = cls._xml_map # type: ignore + except AttributeError: + xml_map = {} + + return _create_xml_node(xml_map.get("name", cls.__name__), xml_map.get("prefix", None), xml_map.get("ns", None)) + + def serialize(self, keep_readonly: bool = False, **kwargs: Any) -> JSON: + """Return the JSON that would be sent to server from this model. + + This is an alias to `as_dict(full_restapi_key_transformer, keep_readonly=False)`. + + If you want XML serialization, you can pass the kwargs is_xml=True. + + :param bool keep_readonly: If you want to serialize the readonly attributes + :returns: A dict JSON compatible object + :rtype: dict + """ + serializer = Serializer(self._infer_class_models()) + return serializer._serialize( # type: ignore # pylint: disable=protected-access + self, keep_readonly=keep_readonly, **kwargs + ) + + def as_dict( + self, + keep_readonly: bool = True, + key_transformer: Callable[[str, Dict[str, Any], Any], Any] = attribute_transformer, + **kwargs: Any + ) -> JSON: + """Return a dict that can be serialized using json.dump. + + Advanced usage might optionally use a callback as parameter: + + .. code::python + + def my_key_transformer(key, attr_desc, value): + return key + + Key is the attribute name used in Python. Attr_desc + is a dict of metadata. Currently contains 'type' with the + msrest type and 'key' with the RestAPI encoded key. + Value is the current value in this object. + + The string returned will be used to serialize the key. + If the return type is a list, this is considered hierarchical + result dict. + + See the three examples in this file: + + - attribute_transformer + - full_restapi_key_transformer + - last_restapi_key_transformer + + If you want XML serialization, you can pass the kwargs is_xml=True. + + :param bool keep_readonly: If you want to serialize the readonly attributes + :param function key_transformer: A key transformer function. + :returns: A dict JSON compatible object + :rtype: dict + """ + serializer = Serializer(self._infer_class_models()) + return serializer._serialize( # type: ignore # pylint: disable=protected-access + self, key_transformer=key_transformer, keep_readonly=keep_readonly, **kwargs + ) + + @classmethod + def _infer_class_models(cls): + try: + str_models = cls.__module__.rsplit(".", 1)[0] + models = sys.modules[str_models] + client_models = {k: v for k, v in models.__dict__.items() if isinstance(v, type)} + if cls.__name__ not in client_models: + raise ValueError("Not Autorest generated code") + except Exception: # pylint: disable=broad-exception-caught + # Assume it's not Autorest generated (tests?). Add ourselves as dependencies. + client_models = {cls.__name__: cls} + return client_models + + @classmethod + def deserialize(cls, data: Any, content_type: Optional[str] = None) -> Self: + """Parse a str using the RestAPI syntax and return a model. + + :param str data: A str using RestAPI structure. JSON by default. + :param str content_type: JSON by default, set application/xml if XML. + :returns: An instance of this model + :raises DeserializationError: if something went wrong + :rtype: Self + """ + deserializer = Deserializer(cls._infer_class_models()) + return deserializer(cls.__name__, data, content_type=content_type) # type: ignore + + @classmethod + def from_dict( + cls, + data: Any, + key_extractors: Optional[Callable[[str, Dict[str, Any], Any], Any]] = None, + content_type: Optional[str] = None, + ) -> Self: + """Parse a dict using given key extractor return a model. + + By default consider key + extractors (rest_key_case_insensitive_extractor, attribute_key_case_insensitive_extractor + and last_rest_key_case_insensitive_extractor) + + :param dict data: A dict using RestAPI structure + :param function key_extractors: A key extractor function. + :param str content_type: JSON by default, set application/xml if XML. + :returns: An instance of this model + :raises DeserializationError: if something went wrong + :rtype: Self + """ + deserializer = Deserializer(cls._infer_class_models()) + deserializer.key_extractors = ( # type: ignore + [ # type: ignore + attribute_key_case_insensitive_extractor, + rest_key_case_insensitive_extractor, + last_rest_key_case_insensitive_extractor, + ] + if key_extractors is None + else key_extractors + ) + return deserializer(cls.__name__, data, content_type=content_type) # type: ignore + + @classmethod + def _flatten_subtype(cls, key, objects): + if "_subtype_map" not in cls.__dict__: + return {} + result = dict(cls._subtype_map[key]) + for valuetype in cls._subtype_map[key].values(): + result.update(objects[valuetype]._flatten_subtype(key, objects)) # pylint: disable=protected-access + return result + + @classmethod + def _classify(cls, response, objects): + """Check the class _subtype_map for any child classes. + We want to ignore any inherited _subtype_maps. + + :param dict response: The initial data + :param dict objects: The class objects + :returns: The class to be used + :rtype: class + """ + for subtype_key in cls.__dict__.get("_subtype_map", {}).keys(): + subtype_value = None + + if not isinstance(response, ET.Element): + rest_api_response_key = cls._get_rest_key_parts(subtype_key)[-1] + subtype_value = response.get(rest_api_response_key, None) or response.get(subtype_key, None) + else: + subtype_value = xml_key_extractor(subtype_key, cls._attribute_map[subtype_key], response) + if subtype_value: + # Try to match base class. Can be class name only + # (bug to fix in Autorest to support x-ms-discriminator-name) + if cls.__name__ == subtype_value: + return cls + flatten_mapping_type = cls._flatten_subtype(subtype_key, objects) + try: + return objects[flatten_mapping_type[subtype_value]] # type: ignore + except KeyError: + _LOGGER.warning( + "Subtype value %s has no mapping, use base class %s.", + subtype_value, + cls.__name__, + ) + break + else: + _LOGGER.warning("Discriminator %s is absent or null, use base class %s.", subtype_key, cls.__name__) + break + return cls + + @classmethod + def _get_rest_key_parts(cls, attr_key): + """Get the RestAPI key of this attr, split it and decode part + :param str attr_key: Attribute key must be in attribute_map. + :returns: A list of RestAPI part + :rtype: list + """ + rest_split_key = _FLATTEN.split(cls._attribute_map[attr_key]["key"]) + return [_decode_attribute_map_key(key_part) for key_part in rest_split_key] + + +def _decode_attribute_map_key(key): + """This decode a key in an _attribute_map to the actual key we want to look at + inside the received data. + + :param str key: A key string from the generated code + :returns: The decoded key + :rtype: str + """ + return key.replace("\\.", ".") + + +class Serializer: # pylint: disable=too-many-public-methods + """Request object model serializer.""" + + basic_types = {str: "str", int: "int", bool: "bool", float: "float"} + + _xml_basic_types_serializers = {"bool": lambda x: str(x).lower()} + days = {0: "Mon", 1: "Tue", 2: "Wed", 3: "Thu", 4: "Fri", 5: "Sat", 6: "Sun"} + months = { + 1: "Jan", + 2: "Feb", + 3: "Mar", + 4: "Apr", + 5: "May", + 6: "Jun", + 7: "Jul", + 8: "Aug", + 9: "Sep", + 10: "Oct", + 11: "Nov", + 12: "Dec", + } + validation = { + "min_length": lambda x, y: len(x) < y, + "max_length": lambda x, y: len(x) > y, + "minimum": lambda x, y: x < y, + "maximum": lambda x, y: x > y, + "minimum_ex": lambda x, y: x <= y, + "maximum_ex": lambda x, y: x >= y, + "min_items": lambda x, y: len(x) < y, + "max_items": lambda x, y: len(x) > y, + "pattern": lambda x, y: not re.match(y, x, re.UNICODE), + "unique": lambda x, y: len(x) != len(set(x)), + "multiple": lambda x, y: x % y != 0, + } + + def __init__(self, classes: Optional[Mapping[str, type]] = None) -> None: + self.serialize_type = { + "iso-8601": Serializer.serialize_iso, + "rfc-1123": Serializer.serialize_rfc, + "unix-time": Serializer.serialize_unix, + "duration": Serializer.serialize_duration, + "date": Serializer.serialize_date, + "time": Serializer.serialize_time, + "decimal": Serializer.serialize_decimal, + "long": Serializer.serialize_long, + "bytearray": Serializer.serialize_bytearray, + "base64": Serializer.serialize_base64, + "object": self.serialize_object, + "[]": self.serialize_iter, + "{}": self.serialize_dict, + } + self.dependencies: Dict[str, type] = dict(classes) if classes else {} + self.key_transformer = full_restapi_key_transformer + self.client_side_validation = True + + def _serialize( # pylint: disable=too-many-nested-blocks, too-many-branches, too-many-statements, too-many-locals + self, target_obj, data_type=None, **kwargs + ): + """Serialize data into a string according to type. + + :param object target_obj: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str, dict + :raises SerializationError: if serialization fails. + :returns: The serialized data. + """ + key_transformer = kwargs.get("key_transformer", self.key_transformer) + keep_readonly = kwargs.get("keep_readonly", False) + if target_obj is None: + return None + + attr_name = None + class_name = target_obj.__class__.__name__ + + if data_type: + return self.serialize_data(target_obj, data_type, **kwargs) + + if not hasattr(target_obj, "_attribute_map"): + data_type = type(target_obj).__name__ + if data_type in self.basic_types.values(): + return self.serialize_data(target_obj, data_type, **kwargs) + + # Force "is_xml" kwargs if we detect a XML model + try: + is_xml_model_serialization = kwargs["is_xml"] + except KeyError: + is_xml_model_serialization = kwargs.setdefault("is_xml", target_obj.is_xml_model()) + + serialized = {} + if is_xml_model_serialization: + serialized = target_obj._create_xml_node() # pylint: disable=protected-access + try: + attributes = target_obj._attribute_map # pylint: disable=protected-access + for attr, attr_desc in attributes.items(): + attr_name = attr + if not keep_readonly and target_obj._validation.get( # pylint: disable=protected-access + attr_name, {} + ).get("readonly", False): + continue + + if attr_name == "additional_properties" and attr_desc["key"] == "": + if target_obj.additional_properties is not None: + serialized.update(target_obj.additional_properties) + continue + try: + + orig_attr = getattr(target_obj, attr) + if is_xml_model_serialization: + pass # Don't provide "transformer" for XML for now. Keep "orig_attr" + else: # JSON + keys, orig_attr = key_transformer(attr, attr_desc.copy(), orig_attr) + keys = keys if isinstance(keys, list) else [keys] + + kwargs["serialization_ctxt"] = attr_desc + new_attr = self.serialize_data(orig_attr, attr_desc["type"], **kwargs) + + if is_xml_model_serialization: + xml_desc = attr_desc.get("xml", {}) + xml_name = xml_desc.get("name", attr_desc["key"]) + xml_prefix = xml_desc.get("prefix", None) + xml_ns = xml_desc.get("ns", None) + if xml_desc.get("attr", False): + if xml_ns: + ET.register_namespace(xml_prefix, xml_ns) + xml_name = "{{{}}}{}".format(xml_ns, xml_name) + serialized.set(xml_name, new_attr) # type: ignore + continue + if xml_desc.get("text", False): + serialized.text = new_attr # type: ignore + continue + if isinstance(new_attr, list): + serialized.extend(new_attr) # type: ignore + elif isinstance(new_attr, ET.Element): + # If the down XML has no XML/Name, + # we MUST replace the tag with the local tag. But keeping the namespaces. + if "name" not in getattr(orig_attr, "_xml_map", {}): + splitted_tag = new_attr.tag.split("}") + if len(splitted_tag) == 2: # Namespace + new_attr.tag = "}".join([splitted_tag[0], xml_name]) + else: + new_attr.tag = xml_name + serialized.append(new_attr) # type: ignore + else: # That's a basic type + # Integrate namespace if necessary + local_node = _create_xml_node(xml_name, xml_prefix, xml_ns) + local_node.text = str(new_attr) + serialized.append(local_node) # type: ignore + else: # JSON + for k in reversed(keys): # type: ignore + new_attr = {k: new_attr} + + _new_attr = new_attr + _serialized = serialized + for k in keys: # type: ignore + if k not in _serialized: + _serialized.update(_new_attr) # type: ignore + _new_attr = _new_attr[k] # type: ignore + _serialized = _serialized[k] + except ValueError as err: + if isinstance(err, SerializationError): + raise + + except (AttributeError, KeyError, TypeError) as err: + msg = "Attribute {} in object {} cannot be serialized.\n{}".format(attr_name, class_name, str(target_obj)) + raise SerializationError(msg) from err + return serialized + + def body(self, data, data_type, **kwargs): + """Serialize data intended for a request body. + + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: dict + :raises SerializationError: if serialization fails. + :raises ValueError: if data is None + :returns: The serialized request body + """ + + # Just in case this is a dict + internal_data_type_str = data_type.strip("[]{}") + internal_data_type = self.dependencies.get(internal_data_type_str, None) + try: + is_xml_model_serialization = kwargs["is_xml"] + except KeyError: + if internal_data_type and issubclass(internal_data_type, Model): + is_xml_model_serialization = kwargs.setdefault("is_xml", internal_data_type.is_xml_model()) + else: + is_xml_model_serialization = False + if internal_data_type and not isinstance(internal_data_type, Enum): + try: + deserializer = Deserializer(self.dependencies) + # Since it's on serialization, it's almost sure that format is not JSON REST + # We're not able to deal with additional properties for now. + deserializer.additional_properties_detection = False + if is_xml_model_serialization: + deserializer.key_extractors = [ # type: ignore + attribute_key_case_insensitive_extractor, + ] + else: + deserializer.key_extractors = [ + rest_key_case_insensitive_extractor, + attribute_key_case_insensitive_extractor, + last_rest_key_case_insensitive_extractor, + ] + data = deserializer._deserialize(data_type, data) # pylint: disable=protected-access + except DeserializationError as err: + raise SerializationError("Unable to build a model: " + str(err)) from err + + return self._serialize(data, data_type, **kwargs) + + def url(self, name, data, data_type, **kwargs): + """Serialize data intended for a URL path. + + :param str name: The name of the URL path parameter. + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str + :returns: The serialized URL path + :raises TypeError: if serialization fails. + :raises ValueError: if data is None + """ + try: + output = self.serialize_data(data, data_type, **kwargs) + if data_type == "bool": + output = json.dumps(output) + + if kwargs.get("skip_quote") is True: + output = str(output) + output = output.replace("{", quote("{")).replace("}", quote("}")) + else: + output = quote(str(output), safe="") + except SerializationError as exc: + raise TypeError("{} must be type {}.".format(name, data_type)) from exc + return output + + def query(self, name, data, data_type, **kwargs): + """Serialize data intended for a URL query. + + :param str name: The name of the query parameter. + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str, list + :raises TypeError: if serialization fails. + :raises ValueError: if data is None + :returns: The serialized query parameter + """ + try: + # Treat the list aside, since we don't want to encode the div separator + if data_type.startswith("["): + internal_data_type = data_type[1:-1] + do_quote = not kwargs.get("skip_quote", False) + return self.serialize_iter(data, internal_data_type, do_quote=do_quote, **kwargs) + + # Not a list, regular serialization + output = self.serialize_data(data, data_type, **kwargs) + if data_type == "bool": + output = json.dumps(output) + if kwargs.get("skip_quote") is True: + output = str(output) + else: + output = quote(str(output), safe="") + except SerializationError as exc: + raise TypeError("{} must be type {}.".format(name, data_type)) from exc + return str(output) + + def header(self, name, data, data_type, **kwargs): + """Serialize data intended for a request header. + + :param str name: The name of the header. + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str + :raises TypeError: if serialization fails. + :raises ValueError: if data is None + :returns: The serialized header + """ + try: + if data_type in ["[str]"]: + data = ["" if d is None else d for d in data] + + output = self.serialize_data(data, data_type, **kwargs) + if data_type == "bool": + output = json.dumps(output) + except SerializationError as exc: + raise TypeError("{} must be type {}.".format(name, data_type)) from exc + return str(output) + + def serialize_data(self, data, data_type, **kwargs): + """Serialize generic data according to supplied data type. + + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :raises AttributeError: if required data is None. + :raises ValueError: if data is None + :raises SerializationError: if serialization fails. + :returns: The serialized data. + :rtype: str, int, float, bool, dict, list + """ + if data is None: + raise ValueError("No value for given attribute") + + try: + if data is CoreNull: + return None + if data_type in self.basic_types.values(): + return self.serialize_basic(data, data_type, **kwargs) + + if data_type in self.serialize_type: + return self.serialize_type[data_type](data, **kwargs) + + # If dependencies is empty, try with current data class + # It has to be a subclass of Enum anyway + enum_type = self.dependencies.get(data_type, data.__class__) + if issubclass(enum_type, Enum): + return Serializer.serialize_enum(data, enum_obj=enum_type) + + iter_type = data_type[0] + data_type[-1] + if iter_type in self.serialize_type: + return self.serialize_type[iter_type](data, data_type[1:-1], **kwargs) + + except (ValueError, TypeError) as err: + msg = "Unable to serialize value: {!r} as type: {!r}." + raise SerializationError(msg.format(data, data_type)) from err + return self._serialize(data, **kwargs) + + @classmethod + def _get_custom_serializers(cls, data_type, **kwargs): # pylint: disable=inconsistent-return-statements + custom_serializer = kwargs.get("basic_types_serializers", {}).get(data_type) + if custom_serializer: + return custom_serializer + if kwargs.get("is_xml", False): + return cls._xml_basic_types_serializers.get(data_type) + + @classmethod + def serialize_basic(cls, data, data_type, **kwargs): + """Serialize basic builting data type. + Serializes objects to str, int, float or bool. + + Possible kwargs: + - basic_types_serializers dict[str, callable] : If set, use the callable as serializer + - is_xml bool : If set, use xml_basic_types_serializers + + :param obj data: Object to be serialized. + :param str data_type: Type of object in the iterable. + :rtype: str, int, float, bool + :return: serialized object + """ + custom_serializer = cls._get_custom_serializers(data_type, **kwargs) + if custom_serializer: + return custom_serializer(data) + if data_type == "str": + return cls.serialize_unicode(data) + return eval(data_type)(data) # nosec # pylint: disable=eval-used + + @classmethod + def serialize_unicode(cls, data): + """Special handling for serializing unicode strings in Py2. + Encode to UTF-8 if unicode, otherwise handle as a str. + + :param str data: Object to be serialized. + :rtype: str + :return: serialized object + """ + try: # If I received an enum, return its value + return data.value + except AttributeError: + pass + + try: + if isinstance(data, unicode): # type: ignore + # Don't change it, JSON and XML ElementTree are totally able + # to serialize correctly u'' strings + return data + except NameError: + return str(data) + return str(data) + + def serialize_iter(self, data, iter_type, div=None, **kwargs): + """Serialize iterable. + + Supported kwargs: + - serialization_ctxt dict : The current entry of _attribute_map, or same format. + serialization_ctxt['type'] should be same as data_type. + - is_xml bool : If set, serialize as XML + + :param list data: Object to be serialized. + :param str iter_type: Type of object in the iterable. + :param str div: If set, this str will be used to combine the elements + in the iterable into a combined string. Default is 'None'. + Defaults to False. + :rtype: list, str + :return: serialized iterable + """ + if isinstance(data, str): + raise SerializationError("Refuse str type as a valid iter type.") + + serialization_ctxt = kwargs.get("serialization_ctxt", {}) + is_xml = kwargs.get("is_xml", False) + + serialized = [] + for d in data: + try: + serialized.append(self.serialize_data(d, iter_type, **kwargs)) + except ValueError as err: + if isinstance(err, SerializationError): + raise + serialized.append(None) + + if kwargs.get("do_quote", False): + serialized = ["" if s is None else quote(str(s), safe="") for s in serialized] + + if div: + serialized = ["" if s is None else str(s) for s in serialized] + serialized = div.join(serialized) + + if "xml" in serialization_ctxt or is_xml: + # XML serialization is more complicated + xml_desc = serialization_ctxt.get("xml", {}) + xml_name = xml_desc.get("name") + if not xml_name: + xml_name = serialization_ctxt["key"] + + # Create a wrap node if necessary (use the fact that Element and list have "append") + is_wrapped = xml_desc.get("wrapped", False) + node_name = xml_desc.get("itemsName", xml_name) + if is_wrapped: + final_result = _create_xml_node(xml_name, xml_desc.get("prefix", None), xml_desc.get("ns", None)) + else: + final_result = [] + # All list elements to "local_node" + for el in serialized: + if isinstance(el, ET.Element): + el_node = el + else: + el_node = _create_xml_node(node_name, xml_desc.get("prefix", None), xml_desc.get("ns", None)) + if el is not None: # Otherwise it writes "None" :-p + el_node.text = str(el) + final_result.append(el_node) + return final_result + return serialized + + def serialize_dict(self, attr, dict_type, **kwargs): + """Serialize a dictionary of objects. + + :param dict attr: Object to be serialized. + :param str dict_type: Type of object in the dictionary. + :rtype: dict + :return: serialized dictionary + """ + serialization_ctxt = kwargs.get("serialization_ctxt", {}) + serialized = {} + for key, value in attr.items(): + try: + serialized[self.serialize_unicode(key)] = self.serialize_data(value, dict_type, **kwargs) + except ValueError as err: + if isinstance(err, SerializationError): + raise + serialized[self.serialize_unicode(key)] = None + + if "xml" in serialization_ctxt: + # XML serialization is more complicated + xml_desc = serialization_ctxt["xml"] + xml_name = xml_desc["name"] + + final_result = _create_xml_node(xml_name, xml_desc.get("prefix", None), xml_desc.get("ns", None)) + for key, value in serialized.items(): + ET.SubElement(final_result, key).text = value + return final_result + + return serialized + + def serialize_object(self, attr, **kwargs): # pylint: disable=too-many-return-statements + """Serialize a generic object. + This will be handled as a dictionary. If object passed in is not + a basic type (str, int, float, dict, list) it will simply be + cast to str. + + :param dict attr: Object to be serialized. + :rtype: dict or str + :return: serialized object + """ + if attr is None: + return None + if isinstance(attr, ET.Element): + return attr + obj_type = type(attr) + if obj_type in self.basic_types: + return self.serialize_basic(attr, self.basic_types[obj_type], **kwargs) + if obj_type is _long_type: + return self.serialize_long(attr) + if obj_type is str: + return self.serialize_unicode(attr) + if obj_type is datetime.datetime: + return self.serialize_iso(attr) + if obj_type is datetime.date: + return self.serialize_date(attr) + if obj_type is datetime.time: + return self.serialize_time(attr) + if obj_type is datetime.timedelta: + return self.serialize_duration(attr) + if obj_type is decimal.Decimal: + return self.serialize_decimal(attr) + + # If it's a model or I know this dependency, serialize as a Model + if obj_type in self.dependencies.values() or isinstance(attr, Model): + return self._serialize(attr) + + if obj_type == dict: + serialized = {} + for key, value in attr.items(): + try: + serialized[self.serialize_unicode(key)] = self.serialize_object(value, **kwargs) + except ValueError: + serialized[self.serialize_unicode(key)] = None + return serialized + + if obj_type == list: + serialized = [] + for obj in attr: + try: + serialized.append(self.serialize_object(obj, **kwargs)) + except ValueError: + pass + return serialized + return str(attr) + + @staticmethod + def serialize_enum(attr, enum_obj=None): + try: + result = attr.value + except AttributeError: + result = attr + try: + enum_obj(result) # type: ignore + return result + except ValueError as exc: + for enum_value in enum_obj: # type: ignore + if enum_value.value.lower() == str(attr).lower(): + return enum_value.value + error = "{!r} is not valid value for enum {!r}" + raise SerializationError(error.format(attr, enum_obj)) from exc + + @staticmethod + def serialize_bytearray(attr, **kwargs): # pylint: disable=unused-argument + """Serialize bytearray into base-64 string. + + :param str attr: Object to be serialized. + :rtype: str + :return: serialized base64 + """ + return b64encode(attr).decode() + + @staticmethod + def serialize_base64(attr, **kwargs): # pylint: disable=unused-argument + """Serialize str into base-64 string. + + :param str attr: Object to be serialized. + :rtype: str + :return: serialized base64 + """ + encoded = b64encode(attr).decode("ascii") + return encoded.strip("=").replace("+", "-").replace("/", "_") + + @staticmethod + def serialize_decimal(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Decimal object to float. + + :param decimal attr: Object to be serialized. + :rtype: float + :return: serialized decimal + """ + return float(attr) + + @staticmethod + def serialize_long(attr, **kwargs): # pylint: disable=unused-argument + """Serialize long (Py2) or int (Py3). + + :param int attr: Object to be serialized. + :rtype: int/long + :return: serialized long + """ + return _long_type(attr) + + @staticmethod + def serialize_date(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Date object into ISO-8601 formatted string. + + :param Date attr: Object to be serialized. + :rtype: str + :return: serialized date + """ + if isinstance(attr, str): + attr = isodate.parse_date(attr) + t = "{:04}-{:02}-{:02}".format(attr.year, attr.month, attr.day) + return t + + @staticmethod + def serialize_time(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Time object into ISO-8601 formatted string. + + :param datetime.time attr: Object to be serialized. + :rtype: str + :return: serialized time + """ + if isinstance(attr, str): + attr = isodate.parse_time(attr) + t = "{:02}:{:02}:{:02}".format(attr.hour, attr.minute, attr.second) + if attr.microsecond: + t += ".{:02}".format(attr.microsecond) + return t + + @staticmethod + def serialize_duration(attr, **kwargs): # pylint: disable=unused-argument + """Serialize TimeDelta object into ISO-8601 formatted string. + + :param TimeDelta attr: Object to be serialized. + :rtype: str + :return: serialized duration + """ + if isinstance(attr, str): + attr = isodate.parse_duration(attr) + return isodate.duration_isoformat(attr) + + @staticmethod + def serialize_rfc(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Datetime object into RFC-1123 formatted string. + + :param Datetime attr: Object to be serialized. + :rtype: str + :raises TypeError: if format invalid. + :return: serialized rfc + """ + try: + if not attr.tzinfo: + _LOGGER.warning("Datetime with no tzinfo will be considered UTC.") + utc = attr.utctimetuple() + except AttributeError as exc: + raise TypeError("RFC1123 object must be valid Datetime object.") from exc + + return "{}, {:02} {} {:04} {:02}:{:02}:{:02} GMT".format( + Serializer.days[utc.tm_wday], + utc.tm_mday, + Serializer.months[utc.tm_mon], + utc.tm_year, + utc.tm_hour, + utc.tm_min, + utc.tm_sec, + ) + + @staticmethod + def serialize_iso(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Datetime object into ISO-8601 formatted string. + + :param Datetime attr: Object to be serialized. + :rtype: str + :raises SerializationError: if format invalid. + :return: serialized iso + """ + if isinstance(attr, str): + attr = isodate.parse_datetime(attr) + try: + if not attr.tzinfo: + _LOGGER.warning("Datetime with no tzinfo will be considered UTC.") + utc = attr.utctimetuple() + if utc.tm_year > 9999 or utc.tm_year < 1: + raise OverflowError("Hit max or min date") + + microseconds = str(attr.microsecond).rjust(6, "0").rstrip("0").ljust(3, "0") + if microseconds: + microseconds = "." + microseconds + date = "{:04}-{:02}-{:02}T{:02}:{:02}:{:02}".format( + utc.tm_year, utc.tm_mon, utc.tm_mday, utc.tm_hour, utc.tm_min, utc.tm_sec + ) + return date + microseconds + "Z" + except (ValueError, OverflowError) as err: + msg = "Unable to serialize datetime object." + raise SerializationError(msg) from err + except AttributeError as err: + msg = "ISO-8601 object must be valid Datetime object." + raise TypeError(msg) from err + + @staticmethod + def serialize_unix(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Datetime object into IntTime format. + This is represented as seconds. + + :param Datetime attr: Object to be serialized. + :rtype: int + :raises SerializationError: if format invalid + :return: serialied unix + """ + if isinstance(attr, int): + return attr + try: + if not attr.tzinfo: + _LOGGER.warning("Datetime with no tzinfo will be considered UTC.") + return int(calendar.timegm(attr.utctimetuple())) + except AttributeError as exc: + raise TypeError("Unix time object must be valid Datetime object.") from exc + + +def rest_key_extractor(attr, attr_desc, data): # pylint: disable=unused-argument + key = attr_desc["key"] + working_data = data + + while "." in key: + # Need the cast, as for some reasons "split" is typed as list[str | Any] + dict_keys = cast(List[str], _FLATTEN.split(key)) + if len(dict_keys) == 1: + key = _decode_attribute_map_key(dict_keys[0]) + break + working_key = _decode_attribute_map_key(dict_keys[0]) + working_data = working_data.get(working_key, data) + if working_data is None: + # If at any point while following flatten JSON path see None, it means + # that all properties under are None as well + return None + key = ".".join(dict_keys[1:]) + + return working_data.get(key) + + +def rest_key_case_insensitive_extractor( # pylint: disable=unused-argument, inconsistent-return-statements + attr, attr_desc, data +): + key = attr_desc["key"] + working_data = data + + while "." in key: + dict_keys = _FLATTEN.split(key) + if len(dict_keys) == 1: + key = _decode_attribute_map_key(dict_keys[0]) + break + working_key = _decode_attribute_map_key(dict_keys[0]) + working_data = attribute_key_case_insensitive_extractor(working_key, None, working_data) + if working_data is None: + # If at any point while following flatten JSON path see None, it means + # that all properties under are None as well + return None + key = ".".join(dict_keys[1:]) + + if working_data: + return attribute_key_case_insensitive_extractor(key, None, working_data) + + +def last_rest_key_extractor(attr, attr_desc, data): # pylint: disable=unused-argument + """Extract the attribute in "data" based on the last part of the JSON path key. + + :param str attr: The attribute to extract + :param dict attr_desc: The attribute description + :param dict data: The data to extract from + :rtype: object + :returns: The extracted attribute + """ + key = attr_desc["key"] + dict_keys = _FLATTEN.split(key) + return attribute_key_extractor(dict_keys[-1], None, data) + + +def last_rest_key_case_insensitive_extractor(attr, attr_desc, data): # pylint: disable=unused-argument + """Extract the attribute in "data" based on the last part of the JSON path key. + + This is the case insensitive version of "last_rest_key_extractor" + :param str attr: The attribute to extract + :param dict attr_desc: The attribute description + :param dict data: The data to extract from + :rtype: object + :returns: The extracted attribute + """ + key = attr_desc["key"] + dict_keys = _FLATTEN.split(key) + return attribute_key_case_insensitive_extractor(dict_keys[-1], None, data) + + +def attribute_key_extractor(attr, _, data): + return data.get(attr) + + +def attribute_key_case_insensitive_extractor(attr, _, data): + found_key = None + lower_attr = attr.lower() + for key in data: + if lower_attr == key.lower(): + found_key = key + break + + return data.get(found_key) + + +def _extract_name_from_internal_type(internal_type): + """Given an internal type XML description, extract correct XML name with namespace. + + :param dict internal_type: An model type + :rtype: tuple + :returns: A tuple XML name + namespace dict + """ + internal_type_xml_map = getattr(internal_type, "_xml_map", {}) + xml_name = internal_type_xml_map.get("name", internal_type.__name__) + xml_ns = internal_type_xml_map.get("ns", None) + if xml_ns: + xml_name = "{{{}}}{}".format(xml_ns, xml_name) + return xml_name + + +def xml_key_extractor(attr, attr_desc, data): # pylint: disable=unused-argument,too-many-return-statements + if isinstance(data, dict): + return None + + # Test if this model is XML ready first + if not isinstance(data, ET.Element): + return None + + xml_desc = attr_desc.get("xml", {}) + xml_name = xml_desc.get("name", attr_desc["key"]) + + # Look for a children + is_iter_type = attr_desc["type"].startswith("[") + is_wrapped = xml_desc.get("wrapped", False) + internal_type = attr_desc.get("internalType", None) + internal_type_xml_map = getattr(internal_type, "_xml_map", {}) + + # Integrate namespace if necessary + xml_ns = xml_desc.get("ns", internal_type_xml_map.get("ns", None)) + if xml_ns: + xml_name = "{{{}}}{}".format(xml_ns, xml_name) + + # If it's an attribute, that's simple + if xml_desc.get("attr", False): + return data.get(xml_name) + + # If it's x-ms-text, that's simple too + if xml_desc.get("text", False): + return data.text + + # Scenario where I take the local name: + # - Wrapped node + # - Internal type is an enum (considered basic types) + # - Internal type has no XML/Name node + if is_wrapped or (internal_type and (issubclass(internal_type, Enum) or "name" not in internal_type_xml_map)): + children = data.findall(xml_name) + # If internal type has a local name and it's not a list, I use that name + elif not is_iter_type and internal_type and "name" in internal_type_xml_map: + xml_name = _extract_name_from_internal_type(internal_type) + children = data.findall(xml_name) + # That's an array + else: + if internal_type: # Complex type, ignore itemsName and use the complex type name + items_name = _extract_name_from_internal_type(internal_type) + else: + items_name = xml_desc.get("itemsName", xml_name) + children = data.findall(items_name) + + if len(children) == 0: + if is_iter_type: + if is_wrapped: + return None # is_wrapped no node, we want None + return [] # not wrapped, assume empty list + return None # Assume it's not there, maybe an optional node. + + # If is_iter_type and not wrapped, return all found children + if is_iter_type: + if not is_wrapped: + return children + # Iter and wrapped, should have found one node only (the wrap one) + if len(children) != 1: + raise DeserializationError( + "Tried to deserialize an array not wrapped, and found several nodes '{}'. Maybe you should declare this array as wrapped?".format( + xml_name + ) + ) + return list(children[0]) # Might be empty list and that's ok. + + # Here it's not a itertype, we should have found one element only or empty + if len(children) > 1: + raise DeserializationError("Find several XML '{}' where it was not expected".format(xml_name)) + return children[0] + + +class Deserializer: + """Response object model deserializer. + + :param dict classes: Class type dictionary for deserializing complex types. + :ivar list key_extractors: Ordered list of extractors to be used by this deserializer. + """ + + basic_types = {str: "str", int: "int", bool: "bool", float: "float"} + + valid_date = re.compile(r"\d{4}[-]\d{2}[-]\d{2}T\d{2}:\d{2}:\d{2}\.?\d*Z?[-+]?[\d{2}]?:?[\d{2}]?") + + def __init__(self, classes: Optional[Mapping[str, type]] = None) -> None: + self.deserialize_type = { + "iso-8601": Deserializer.deserialize_iso, + "rfc-1123": Deserializer.deserialize_rfc, + "unix-time": Deserializer.deserialize_unix, + "duration": Deserializer.deserialize_duration, + "date": Deserializer.deserialize_date, + "time": Deserializer.deserialize_time, + "decimal": Deserializer.deserialize_decimal, + "long": Deserializer.deserialize_long, + "bytearray": Deserializer.deserialize_bytearray, + "base64": Deserializer.deserialize_base64, + "object": self.deserialize_object, + "[]": self.deserialize_iter, + "{}": self.deserialize_dict, + } + self.deserialize_expected_types = { + "duration": (isodate.Duration, datetime.timedelta), + "iso-8601": (datetime.datetime), + } + self.dependencies: Dict[str, type] = dict(classes) if classes else {} + self.key_extractors = [rest_key_extractor, xml_key_extractor] + # Additional properties only works if the "rest_key_extractor" is used to + # extract the keys. Making it to work whatever the key extractor is too much + # complicated, with no real scenario for now. + # So adding a flag to disable additional properties detection. This flag should be + # used if your expect the deserialization to NOT come from a JSON REST syntax. + # Otherwise, result are unexpected + self.additional_properties_detection = True + + def __call__(self, target_obj, response_data, content_type=None): + """Call the deserializer to process a REST response. + + :param str target_obj: Target data type to deserialize to. + :param requests.Response response_data: REST response object. + :param str content_type: Swagger "produces" if available. + :raises DeserializationError: if deserialization fails. + :return: Deserialized object. + :rtype: object + """ + data = self._unpack_content(response_data, content_type) + return self._deserialize(target_obj, data) + + def _deserialize(self, target_obj, data): # pylint: disable=inconsistent-return-statements + """Call the deserializer on a model. + + Data needs to be already deserialized as JSON or XML ElementTree + + :param str target_obj: Target data type to deserialize to. + :param object data: Object to deserialize. + :raises DeserializationError: if deserialization fails. + :return: Deserialized object. + :rtype: object + """ + # This is already a model, go recursive just in case + if hasattr(data, "_attribute_map"): + constants = [name for name, config in getattr(data, "_validation", {}).items() if config.get("constant")] + try: + for attr, mapconfig in data._attribute_map.items(): # pylint: disable=protected-access + if attr in constants: + continue + value = getattr(data, attr) + if value is None: + continue + local_type = mapconfig["type"] + internal_data_type = local_type.strip("[]{}") + if internal_data_type not in self.dependencies or isinstance(internal_data_type, Enum): + continue + setattr(data, attr, self._deserialize(local_type, value)) + return data + except AttributeError: + return + + response, class_name = self._classify_target(target_obj, data) + + if isinstance(response, str): + return self.deserialize_data(data, response) + if isinstance(response, type) and issubclass(response, Enum): + return self.deserialize_enum(data, response) + + if data is None or data is CoreNull: + return data + try: + attributes = response._attribute_map # type: ignore # pylint: disable=protected-access + d_attrs = {} + for attr, attr_desc in attributes.items(): + # Check empty string. If it's not empty, someone has a real "additionalProperties"... + if attr == "additional_properties" and attr_desc["key"] == "": + continue + raw_value = None + # Enhance attr_desc with some dynamic data + attr_desc = attr_desc.copy() # Do a copy, do not change the real one + internal_data_type = attr_desc["type"].strip("[]{}") + if internal_data_type in self.dependencies: + attr_desc["internalType"] = self.dependencies[internal_data_type] + + for key_extractor in self.key_extractors: + found_value = key_extractor(attr, attr_desc, data) + if found_value is not None: + if raw_value is not None and raw_value != found_value: + msg = ( + "Ignoring extracted value '%s' from %s for key '%s'" + " (duplicate extraction, follow extractors order)" + ) + _LOGGER.warning(msg, found_value, key_extractor, attr) + continue + raw_value = found_value + + value = self.deserialize_data(raw_value, attr_desc["type"]) + d_attrs[attr] = value + except (AttributeError, TypeError, KeyError) as err: + msg = "Unable to deserialize to object: " + class_name # type: ignore + raise DeserializationError(msg) from err + additional_properties = self._build_additional_properties(attributes, data) + return self._instantiate_model(response, d_attrs, additional_properties) + + def _build_additional_properties(self, attribute_map, data): + if not self.additional_properties_detection: + return None + if "additional_properties" in attribute_map and attribute_map.get("additional_properties", {}).get("key") != "": + # Check empty string. If it's not empty, someone has a real "additionalProperties" + return None + if isinstance(data, ET.Element): + data = {el.tag: el.text for el in data} + + known_keys = { + _decode_attribute_map_key(_FLATTEN.split(desc["key"])[0]) + for desc in attribute_map.values() + if desc["key"] != "" + } + present_keys = set(data.keys()) + missing_keys = present_keys - known_keys + return {key: data[key] for key in missing_keys} + + def _classify_target(self, target, data): + """Check to see whether the deserialization target object can + be classified into a subclass. + Once classification has been determined, initialize object. + + :param str target: The target object type to deserialize to. + :param str/dict data: The response data to deserialize. + :return: The classified target object and its class name. + :rtype: tuple + """ + if target is None: + return None, None + + if isinstance(target, str): + try: + target = self.dependencies[target] + except KeyError: + return target, target + + try: + target = target._classify(data, self.dependencies) # type: ignore # pylint: disable=protected-access + except AttributeError: + pass # Target is not a Model, no classify + return target, target.__class__.__name__ # type: ignore + + def failsafe_deserialize(self, target_obj, data, content_type=None): + """Ignores any errors encountered in deserialization, + and falls back to not deserializing the object. Recommended + for use in error deserialization, as we want to return the + HttpResponseError to users, and not have them deal with + a deserialization error. + + :param str target_obj: The target object type to deserialize to. + :param str/dict data: The response data to deserialize. + :param str content_type: Swagger "produces" if available. + :return: Deserialized object. + :rtype: object + """ + try: + return self(target_obj, data, content_type=content_type) + except: # pylint: disable=bare-except + _LOGGER.debug( + "Ran into a deserialization error. Ignoring since this is failsafe deserialization", exc_info=True + ) + return None + + @staticmethod + def _unpack_content(raw_data, content_type=None): + """Extract the correct structure for deserialization. + + If raw_data is a PipelineResponse, try to extract the result of RawDeserializer. + if we can't, raise. Your Pipeline should have a RawDeserializer. + + If not a pipeline response and raw_data is bytes or string, use content-type + to decode it. If no content-type, try JSON. + + If raw_data is something else, bypass all logic and return it directly. + + :param obj raw_data: Data to be processed. + :param str content_type: How to parse if raw_data is a string/bytes. + :raises JSONDecodeError: If JSON is requested and parsing is impossible. + :raises UnicodeDecodeError: If bytes is not UTF8 + :rtype: object + :return: Unpacked content. + """ + # Assume this is enough to detect a Pipeline Response without importing it + context = getattr(raw_data, "context", {}) + if context: + if RawDeserializer.CONTEXT_NAME in context: + return context[RawDeserializer.CONTEXT_NAME] + raise ValueError("This pipeline didn't have the RawDeserializer policy; can't deserialize") + + # Assume this is enough to recognize universal_http.ClientResponse without importing it + if hasattr(raw_data, "body"): + return RawDeserializer.deserialize_from_http_generics(raw_data.text(), raw_data.headers) + + # Assume this enough to recognize requests.Response without importing it. + if hasattr(raw_data, "_content_consumed"): + return RawDeserializer.deserialize_from_http_generics(raw_data.text, raw_data.headers) + + if isinstance(raw_data, (str, bytes)) or hasattr(raw_data, "read"): + return RawDeserializer.deserialize_from_text(raw_data, content_type) # type: ignore + return raw_data + + def _instantiate_model(self, response, attrs, additional_properties=None): + """Instantiate a response model passing in deserialized args. + + :param Response response: The response model class. + :param dict attrs: The deserialized response attributes. + :param dict additional_properties: Additional properties to be set. + :rtype: Response + :return: The instantiated response model. + """ + if callable(response): + subtype = getattr(response, "_subtype_map", {}) + try: + readonly = [ + k + for k, v in response._validation.items() # pylint: disable=protected-access # type: ignore + if v.get("readonly") + ] + const = [ + k + for k, v in response._validation.items() # pylint: disable=protected-access # type: ignore + if v.get("constant") + ] + kwargs = {k: v for k, v in attrs.items() if k not in subtype and k not in readonly + const} + response_obj = response(**kwargs) + for attr in readonly: + setattr(response_obj, attr, attrs.get(attr)) + if additional_properties: + response_obj.additional_properties = additional_properties # type: ignore + return response_obj + except TypeError as err: + msg = "Unable to deserialize {} into model {}. ".format(kwargs, response) # type: ignore + raise DeserializationError(msg + str(err)) from err + else: + try: + for attr, value in attrs.items(): + setattr(response, attr, value) + return response + except Exception as exp: + msg = "Unable to populate response model. " + msg += "Type: {}, Error: {}".format(type(response), exp) + raise DeserializationError(msg) from exp + + def deserialize_data(self, data, data_type): # pylint: disable=too-many-return-statements + """Process data for deserialization according to data type. + + :param str data: The response string to be deserialized. + :param str data_type: The type to deserialize to. + :raises DeserializationError: if deserialization fails. + :return: Deserialized object. + :rtype: object + """ + if data is None: + return data + + try: + if not data_type: + return data + if data_type in self.basic_types.values(): + return self.deserialize_basic(data, data_type) + if data_type in self.deserialize_type: + if isinstance(data, self.deserialize_expected_types.get(data_type, tuple())): + return data + + is_a_text_parsing_type = lambda x: x not in [ # pylint: disable=unnecessary-lambda-assignment + "object", + "[]", + r"{}", + ] + if isinstance(data, ET.Element) and is_a_text_parsing_type(data_type) and not data.text: + return None + data_val = self.deserialize_type[data_type](data) + return data_val + + iter_type = data_type[0] + data_type[-1] + if iter_type in self.deserialize_type: + return self.deserialize_type[iter_type](data, data_type[1:-1]) + + obj_type = self.dependencies[data_type] + if issubclass(obj_type, Enum): + if isinstance(data, ET.Element): + data = data.text + return self.deserialize_enum(data, obj_type) + + except (ValueError, TypeError, AttributeError) as err: + msg = "Unable to deserialize response data." + msg += " Data: {}, {}".format(data, data_type) + raise DeserializationError(msg) from err + return self._deserialize(obj_type, data) + + def deserialize_iter(self, attr, iter_type): + """Deserialize an iterable. + + :param list attr: Iterable to be deserialized. + :param str iter_type: The type of object in the iterable. + :return: Deserialized iterable. + :rtype: list + """ + if attr is None: + return None + if isinstance(attr, ET.Element): # If I receive an element here, get the children + attr = list(attr) + if not isinstance(attr, (list, set)): + raise DeserializationError("Cannot deserialize as [{}] an object of type {}".format(iter_type, type(attr))) + return [self.deserialize_data(a, iter_type) for a in attr] + + def deserialize_dict(self, attr, dict_type): + """Deserialize a dictionary. + + :param dict/list attr: Dictionary to be deserialized. Also accepts + a list of key, value pairs. + :param str dict_type: The object type of the items in the dictionary. + :return: Deserialized dictionary. + :rtype: dict + """ + if isinstance(attr, list): + return {x["key"]: self.deserialize_data(x["value"], dict_type) for x in attr} + + if isinstance(attr, ET.Element): + # Transform value into {"Key": "value"} + attr = {el.tag: el.text for el in attr} + return {k: self.deserialize_data(v, dict_type) for k, v in attr.items()} + + def deserialize_object(self, attr, **kwargs): # pylint: disable=too-many-return-statements + """Deserialize a generic object. + This will be handled as a dictionary. + + :param dict attr: Dictionary to be deserialized. + :return: Deserialized object. + :rtype: dict + :raises TypeError: if non-builtin datatype encountered. + """ + if attr is None: + return None + if isinstance(attr, ET.Element): + # Do no recurse on XML, just return the tree as-is + return attr + if isinstance(attr, str): + return self.deserialize_basic(attr, "str") + obj_type = type(attr) + if obj_type in self.basic_types: + return self.deserialize_basic(attr, self.basic_types[obj_type]) + if obj_type is _long_type: + return self.deserialize_long(attr) + + if obj_type == dict: + deserialized = {} + for key, value in attr.items(): + try: + deserialized[key] = self.deserialize_object(value, **kwargs) + except ValueError: + deserialized[key] = None + return deserialized + + if obj_type == list: + deserialized = [] + for obj in attr: + try: + deserialized.append(self.deserialize_object(obj, **kwargs)) + except ValueError: + pass + return deserialized + + error = "Cannot deserialize generic object with type: " + raise TypeError(error + str(obj_type)) + + def deserialize_basic(self, attr, data_type): # pylint: disable=too-many-return-statements + """Deserialize basic builtin data type from string. + Will attempt to convert to str, int, float and bool. + This function will also accept '1', '0', 'true' and 'false' as + valid bool values. + + :param str attr: response string to be deserialized. + :param str data_type: deserialization data type. + :return: Deserialized basic type. + :rtype: str, int, float or bool + :raises TypeError: if string format is not valid. + """ + # If we're here, data is supposed to be a basic type. + # If it's still an XML node, take the text + if isinstance(attr, ET.Element): + attr = attr.text + if not attr: + if data_type == "str": + # None or '', node is empty string. + return "" + # None or '', node with a strong type is None. + # Don't try to model "empty bool" or "empty int" + return None + + if data_type == "bool": + if attr in [True, False, 1, 0]: + return bool(attr) + if isinstance(attr, str): + if attr.lower() in ["true", "1"]: + return True + if attr.lower() in ["false", "0"]: + return False + raise TypeError("Invalid boolean value: {}".format(attr)) + + if data_type == "str": + return self.deserialize_unicode(attr) + return eval(data_type)(attr) # nosec # pylint: disable=eval-used + + @staticmethod + def deserialize_unicode(data): + """Preserve unicode objects in Python 2, otherwise return data + as a string. + + :param str data: response string to be deserialized. + :return: Deserialized string. + :rtype: str or unicode + """ + # We might be here because we have an enum modeled as string, + # and we try to deserialize a partial dict with enum inside + if isinstance(data, Enum): + return data + + # Consider this is real string + try: + if isinstance(data, unicode): # type: ignore + return data + except NameError: + return str(data) + return str(data) + + @staticmethod + def deserialize_enum(data, enum_obj): + """Deserialize string into enum object. + + If the string is not a valid enum value it will be returned as-is + and a warning will be logged. + + :param str data: Response string to be deserialized. If this value is + None or invalid it will be returned as-is. + :param Enum enum_obj: Enum object to deserialize to. + :return: Deserialized enum object. + :rtype: Enum + """ + if isinstance(data, enum_obj) or data is None: + return data + if isinstance(data, Enum): + data = data.value + if isinstance(data, int): + # Workaround. We might consider remove it in the future. + try: + return list(enum_obj.__members__.values())[data] + except IndexError as exc: + error = "{!r} is not a valid index for enum {!r}" + raise DeserializationError(error.format(data, enum_obj)) from exc + try: + return enum_obj(str(data)) + except ValueError: + for enum_value in enum_obj: + if enum_value.value.lower() == str(data).lower(): + return enum_value + # We don't fail anymore for unknown value, we deserialize as a string + _LOGGER.warning("Deserializer is not able to find %s as valid enum in %s", data, enum_obj) + return Deserializer.deserialize_unicode(data) + + @staticmethod + def deserialize_bytearray(attr): + """Deserialize string into bytearray. + + :param str attr: response string to be deserialized. + :return: Deserialized bytearray + :rtype: bytearray + :raises TypeError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + return bytearray(b64decode(attr)) # type: ignore + + @staticmethod + def deserialize_base64(attr): + """Deserialize base64 encoded string into string. + + :param str attr: response string to be deserialized. + :return: Deserialized base64 string + :rtype: bytearray + :raises TypeError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + padding = "=" * (3 - (len(attr) + 3) % 4) # type: ignore + attr = attr + padding # type: ignore + encoded = attr.replace("-", "+").replace("_", "/") + return b64decode(encoded) + + @staticmethod + def deserialize_decimal(attr): + """Deserialize string into Decimal object. + + :param str attr: response string to be deserialized. + :return: Deserialized decimal + :raises DeserializationError: if string format invalid. + :rtype: decimal + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + return decimal.Decimal(str(attr)) # type: ignore + except decimal.DecimalException as err: + msg = "Invalid decimal {}".format(attr) + raise DeserializationError(msg) from err + + @staticmethod + def deserialize_long(attr): + """Deserialize string into long (Py2) or int (Py3). + + :param str attr: response string to be deserialized. + :return: Deserialized int + :rtype: long or int + :raises ValueError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + return _long_type(attr) # type: ignore + + @staticmethod + def deserialize_duration(attr): + """Deserialize ISO-8601 formatted string into TimeDelta object. + + :param str attr: response string to be deserialized. + :return: Deserialized duration + :rtype: TimeDelta + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + duration = isodate.parse_duration(attr) + except (ValueError, OverflowError, AttributeError) as err: + msg = "Cannot deserialize duration object." + raise DeserializationError(msg) from err + return duration + + @staticmethod + def deserialize_date(attr): + """Deserialize ISO-8601 formatted string into Date object. + + :param str attr: response string to be deserialized. + :return: Deserialized date + :rtype: Date + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + if re.search(r"[^\W\d_]", attr, re.I + re.U): # type: ignore + raise DeserializationError("Date must have only digits and -. Received: %s" % attr) + # This must NOT use defaultmonth/defaultday. Using None ensure this raises an exception. + return isodate.parse_date(attr, defaultmonth=0, defaultday=0) + + @staticmethod + def deserialize_time(attr): + """Deserialize ISO-8601 formatted string into time object. + + :param str attr: response string to be deserialized. + :return: Deserialized time + :rtype: datetime.time + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + if re.search(r"[^\W\d_]", attr, re.I + re.U): # type: ignore + raise DeserializationError("Date must have only digits and -. Received: %s" % attr) + return isodate.parse_time(attr) + + @staticmethod + def deserialize_rfc(attr): + """Deserialize RFC-1123 formatted string into Datetime object. + + :param str attr: response string to be deserialized. + :return: Deserialized RFC datetime + :rtype: Datetime + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + parsed_date = email.utils.parsedate_tz(attr) # type: ignore + date_obj = datetime.datetime( + *parsed_date[:6], tzinfo=datetime.timezone(datetime.timedelta(minutes=(parsed_date[9] or 0) / 60)) + ) + if not date_obj.tzinfo: + date_obj = date_obj.astimezone(tz=TZ_UTC) + except ValueError as err: + msg = "Cannot deserialize to rfc datetime object." + raise DeserializationError(msg) from err + return date_obj + + @staticmethod + def deserialize_iso(attr): + """Deserialize ISO-8601 formatted string into Datetime object. + + :param str attr: response string to be deserialized. + :return: Deserialized ISO datetime + :rtype: Datetime + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + attr = attr.upper() # type: ignore + match = Deserializer.valid_date.match(attr) + if not match: + raise ValueError("Invalid datetime string: " + attr) + + check_decimal = attr.split(".") + if len(check_decimal) > 1: + decimal_str = "" + for digit in check_decimal[1]: + if digit.isdigit(): + decimal_str += digit + else: + break + if len(decimal_str) > 6: + attr = attr.replace(decimal_str, decimal_str[0:6]) + + date_obj = isodate.parse_datetime(attr) + test_utc = date_obj.utctimetuple() + if test_utc.tm_year > 9999 or test_utc.tm_year < 1: + raise OverflowError("Hit max or min date") + except (ValueError, OverflowError, AttributeError) as err: + msg = "Cannot deserialize datetime object." + raise DeserializationError(msg) from err + return date_obj + + @staticmethod + def deserialize_unix(attr): + """Serialize Datetime object into IntTime format. + This is represented as seconds. + + :param int attr: Object to be serialized. + :return: Deserialized datetime + :rtype: Datetime + :raises DeserializationError: if format invalid + """ + if isinstance(attr, ET.Element): + attr = int(attr.text) # type: ignore + try: + attr = int(attr) + date_obj = datetime.datetime.fromtimestamp(attr, TZ_UTC) + except ValueError as err: + msg = "Cannot deserialize to unix datetime object." + raise DeserializationError(msg) from err + return date_obj diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/NoNamespaceFlagVersionTolerant/anything_client/_utils/utils.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/NoNamespaceFlagVersionTolerant/anything_client/_utils/utils.py new file mode 100644 index 00000000000..39b612f39a9 --- /dev/null +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/NoNamespaceFlagVersionTolerant/anything_client/_utils/utils.py @@ -0,0 +1,25 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from abc import ABC +from typing import Generic, TYPE_CHECKING, TypeVar + +if TYPE_CHECKING: + from .serialization import Deserializer, Serializer + + +TClient = TypeVar("TClient") +TConfig = TypeVar("TConfig") + + +class ClientMixinABC(ABC, Generic[TClient, TConfig]): + """DO NOT use this class. It is for internal typing use only.""" + + _client: TClient + _config: TConfig + _serialize: "Serializer" + _deserialize: "Deserializer" diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/NoNamespaceFlagVersionTolerant/anything_client/_vendor.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/NoNamespaceFlagVersionTolerant/anything_client/_vendor.py deleted file mode 100644 index db0a5a9a33b..00000000000 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/NoNamespaceFlagVersionTolerant/anything_client/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) AutoRest Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import AnythingClientConfiguration - -if TYPE_CHECKING: - from azure.core import PipelineClient - - from ._serialization import Deserializer, Serializer - - -class AnythingClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "PipelineClient" - _config: AnythingClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/NoNamespaceFlagVersionTolerant/anything_client/aio/_client.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/NoNamespaceFlagVersionTolerant/anything_client/aio/_client.py index 328e25d83cf..8e3a540c4c5 100644 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/NoNamespaceFlagVersionTolerant/anything_client/aio/_client.py +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/NoNamespaceFlagVersionTolerant/anything_client/aio/_client.py @@ -14,7 +14,7 @@ from azure.core.pipeline import policies from azure.core.rest import AsyncHttpResponse, HttpRequest -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import AnythingClientConfiguration from ._operations import AnythingClientOperationsMixin diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/NoNamespaceFlagVersionTolerant/anything_client/aio/_operations/_operations.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/NoNamespaceFlagVersionTolerant/anything_client/aio/_operations/_operations.py index a8f7389fad7..d895e2acf61 100644 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/NoNamespaceFlagVersionTolerant/anything_client/aio/_operations/_operations.py +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/NoNamespaceFlagVersionTolerant/anything_client/aio/_operations/_operations.py @@ -9,6 +9,7 @@ from collections.abc import MutableMapping from typing import Any, Callable, Dict, Optional, TypeVar, cast +from azure.core import AsyncPipelineClient from azure.core.exceptions import ( ClientAuthenticationError, HttpResponseError, @@ -30,13 +31,14 @@ build_anything_put_object_request, build_anything_put_string_request, ) -from .._vendor import AnythingClientMixinABC +from ..._utils.utils import ClientMixinABC +from .._configuration import AnythingClientConfiguration T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, AsyncHttpResponse], T, Dict[str, Any]], Any]] -class AnythingClientOperationsMixin(AnythingClientMixinABC): +class AnythingClientOperationsMixin(ClientMixinABC[AsyncPipelineClient, AnythingClientConfiguration]): @distributed_trace_async async def get_object(self, **kwargs: Any) -> Any: diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/NoNamespaceFlagVersionTolerant/anything_client/aio/_vendor.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/NoNamespaceFlagVersionTolerant/anything_client/aio/_vendor.py deleted file mode 100644 index c99b54eef8d..00000000000 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/NoNamespaceFlagVersionTolerant/anything_client/aio/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) AutoRest Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import AnythingClientConfiguration - -if TYPE_CHECKING: - from azure.core import AsyncPipelineClient - - from .._serialization import Deserializer, Serializer - - -class AnythingClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "AsyncPipelineClient" - _config: AnythingClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/NoOperationsVersionTolerant/nooperationsversiontolerant/_utils/__init__.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/NoOperationsVersionTolerant/nooperationsversiontolerant/_utils/__init__.py new file mode 100644 index 00000000000..0af9b28f660 --- /dev/null +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/NoOperationsVersionTolerant/nooperationsversiontolerant/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/NoOperationsVersionTolerant/nooperationsversiontolerant/_utils/serialization.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/NoOperationsVersionTolerant/nooperationsversiontolerant/_utils/serialization.py new file mode 100644 index 00000000000..f5187701d7b --- /dev/null +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/NoOperationsVersionTolerant/nooperationsversiontolerant/_utils/serialization.py @@ -0,0 +1,2032 @@ +# pylint: disable=line-too-long,useless-suppression,too-many-lines +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +# pyright: reportUnnecessaryTypeIgnoreComment=false + +from base64 import b64decode, b64encode +import calendar +import datetime +import decimal +import email +from enum import Enum +import json +import logging +import re +import sys +import codecs +from typing import ( + Dict, + Any, + cast, + Optional, + Union, + AnyStr, + IO, + Mapping, + Callable, + MutableMapping, + List, +) + +try: + from urllib import quote # type: ignore +except ImportError: + from urllib.parse import quote +import xml.etree.ElementTree as ET + +import isodate # type: ignore +from typing_extensions import Self + +from azure.core.exceptions import DeserializationError, SerializationError +from azure.core.serialization import NULL as CoreNull + +_BOM = codecs.BOM_UTF8.decode(encoding="utf-8") + +JSON = MutableMapping[str, Any] + + +class RawDeserializer: + + # Accept "text" because we're open minded people... + JSON_REGEXP = re.compile(r"^(application|text)/([a-z+.]+\+)?json$") + + # Name used in context + CONTEXT_NAME = "deserialized_data" + + @classmethod + def deserialize_from_text(cls, data: Optional[Union[AnyStr, IO]], content_type: Optional[str] = None) -> Any: + """Decode data according to content-type. + + Accept a stream of data as well, but will be load at once in memory for now. + + If no content-type, will return the string version (not bytes, not stream) + + :param data: Input, could be bytes or stream (will be decoded with UTF8) or text + :type data: str or bytes or IO + :param str content_type: The content type. + :return: The deserialized data. + :rtype: object + """ + if hasattr(data, "read"): + # Assume a stream + data = cast(IO, data).read() + + if isinstance(data, bytes): + data_as_str = data.decode(encoding="utf-8-sig") + else: + # Explain to mypy the correct type. + data_as_str = cast(str, data) + + # Remove Byte Order Mark if present in string + data_as_str = data_as_str.lstrip(_BOM) + + if content_type is None: + return data + + if cls.JSON_REGEXP.match(content_type): + try: + return json.loads(data_as_str) + except ValueError as err: + raise DeserializationError("JSON is invalid: {}".format(err), err) from err + elif "xml" in (content_type or []): + try: + + try: + if isinstance(data, unicode): # type: ignore + # If I'm Python 2.7 and unicode XML will scream if I try a "fromstring" on unicode string + data_as_str = data_as_str.encode(encoding="utf-8") # type: ignore + except NameError: + pass + + return ET.fromstring(data_as_str) # nosec + except ET.ParseError as err: + # It might be because the server has an issue, and returned JSON with + # content-type XML.... + # So let's try a JSON load, and if it's still broken + # let's flow the initial exception + def _json_attemp(data): + try: + return True, json.loads(data) + except ValueError: + return False, None # Don't care about this one + + success, json_result = _json_attemp(data) + if success: + return json_result + # If i'm here, it's not JSON, it's not XML, let's scream + # and raise the last context in this block (the XML exception) + # The function hack is because Py2.7 messes up with exception + # context otherwise. + _LOGGER.critical("Wasn't XML not JSON, failing") + raise DeserializationError("XML is invalid") from err + elif content_type.startswith("text/"): + return data_as_str + raise DeserializationError("Cannot deserialize content-type: {}".format(content_type)) + + @classmethod + def deserialize_from_http_generics(cls, body_bytes: Optional[Union[AnyStr, IO]], headers: Mapping) -> Any: + """Deserialize from HTTP response. + + Use bytes and headers to NOT use any requests/aiohttp or whatever + specific implementation. + Headers will tested for "content-type" + + :param bytes body_bytes: The body of the response. + :param dict headers: The headers of the response. + :returns: The deserialized data. + :rtype: object + """ + # Try to use content-type from headers if available + content_type = None + if "content-type" in headers: + content_type = headers["content-type"].split(";")[0].strip().lower() + # Ouch, this server did not declare what it sent... + # Let's guess it's JSON... + # Also, since Autorest was considering that an empty body was a valid JSON, + # need that test as well.... + else: + content_type = "application/json" + + if body_bytes: + return cls.deserialize_from_text(body_bytes, content_type) + return None + + +_LOGGER = logging.getLogger(__name__) + +try: + _long_type = long # type: ignore +except NameError: + _long_type = int + +TZ_UTC = datetime.timezone.utc + +_FLATTEN = re.compile(r"(? None: + self.additional_properties: Optional[Dict[str, Any]] = {} + for k in kwargs: # pylint: disable=consider-using-dict-items + if k not in self._attribute_map: + _LOGGER.warning("%s is not a known attribute of class %s and will be ignored", k, self.__class__) + elif k in self._validation and self._validation[k].get("readonly", False): + _LOGGER.warning("Readonly attribute %s will be ignored in class %s", k, self.__class__) + else: + setattr(self, k, kwargs[k]) + + def __eq__(self, other: Any) -> bool: + """Compare objects by comparing all attributes. + + :param object other: The object to compare + :returns: True if objects are equal + :rtype: bool + """ + if isinstance(other, self.__class__): + return self.__dict__ == other.__dict__ + return False + + def __ne__(self, other: Any) -> bool: + """Compare objects by comparing all attributes. + + :param object other: The object to compare + :returns: True if objects are not equal + :rtype: bool + """ + return not self.__eq__(other) + + def __str__(self) -> str: + return str(self.__dict__) + + @classmethod + def enable_additional_properties_sending(cls) -> None: + cls._attribute_map["additional_properties"] = {"key": "", "type": "{object}"} + + @classmethod + def is_xml_model(cls) -> bool: + try: + cls._xml_map # type: ignore + except AttributeError: + return False + return True + + @classmethod + def _create_xml_node(cls): + """Create XML node. + + :returns: The XML node + :rtype: xml.etree.ElementTree.Element + """ + try: + xml_map = cls._xml_map # type: ignore + except AttributeError: + xml_map = {} + + return _create_xml_node(xml_map.get("name", cls.__name__), xml_map.get("prefix", None), xml_map.get("ns", None)) + + def serialize(self, keep_readonly: bool = False, **kwargs: Any) -> JSON: + """Return the JSON that would be sent to server from this model. + + This is an alias to `as_dict(full_restapi_key_transformer, keep_readonly=False)`. + + If you want XML serialization, you can pass the kwargs is_xml=True. + + :param bool keep_readonly: If you want to serialize the readonly attributes + :returns: A dict JSON compatible object + :rtype: dict + """ + serializer = Serializer(self._infer_class_models()) + return serializer._serialize( # type: ignore # pylint: disable=protected-access + self, keep_readonly=keep_readonly, **kwargs + ) + + def as_dict( + self, + keep_readonly: bool = True, + key_transformer: Callable[[str, Dict[str, Any], Any], Any] = attribute_transformer, + **kwargs: Any + ) -> JSON: + """Return a dict that can be serialized using json.dump. + + Advanced usage might optionally use a callback as parameter: + + .. code::python + + def my_key_transformer(key, attr_desc, value): + return key + + Key is the attribute name used in Python. Attr_desc + is a dict of metadata. Currently contains 'type' with the + msrest type and 'key' with the RestAPI encoded key. + Value is the current value in this object. + + The string returned will be used to serialize the key. + If the return type is a list, this is considered hierarchical + result dict. + + See the three examples in this file: + + - attribute_transformer + - full_restapi_key_transformer + - last_restapi_key_transformer + + If you want XML serialization, you can pass the kwargs is_xml=True. + + :param bool keep_readonly: If you want to serialize the readonly attributes + :param function key_transformer: A key transformer function. + :returns: A dict JSON compatible object + :rtype: dict + """ + serializer = Serializer(self._infer_class_models()) + return serializer._serialize( # type: ignore # pylint: disable=protected-access + self, key_transformer=key_transformer, keep_readonly=keep_readonly, **kwargs + ) + + @classmethod + def _infer_class_models(cls): + try: + str_models = cls.__module__.rsplit(".", 1)[0] + models = sys.modules[str_models] + client_models = {k: v for k, v in models.__dict__.items() if isinstance(v, type)} + if cls.__name__ not in client_models: + raise ValueError("Not Autorest generated code") + except Exception: # pylint: disable=broad-exception-caught + # Assume it's not Autorest generated (tests?). Add ourselves as dependencies. + client_models = {cls.__name__: cls} + return client_models + + @classmethod + def deserialize(cls, data: Any, content_type: Optional[str] = None) -> Self: + """Parse a str using the RestAPI syntax and return a model. + + :param str data: A str using RestAPI structure. JSON by default. + :param str content_type: JSON by default, set application/xml if XML. + :returns: An instance of this model + :raises DeserializationError: if something went wrong + :rtype: Self + """ + deserializer = Deserializer(cls._infer_class_models()) + return deserializer(cls.__name__, data, content_type=content_type) # type: ignore + + @classmethod + def from_dict( + cls, + data: Any, + key_extractors: Optional[Callable[[str, Dict[str, Any], Any], Any]] = None, + content_type: Optional[str] = None, + ) -> Self: + """Parse a dict using given key extractor return a model. + + By default consider key + extractors (rest_key_case_insensitive_extractor, attribute_key_case_insensitive_extractor + and last_rest_key_case_insensitive_extractor) + + :param dict data: A dict using RestAPI structure + :param function key_extractors: A key extractor function. + :param str content_type: JSON by default, set application/xml if XML. + :returns: An instance of this model + :raises DeserializationError: if something went wrong + :rtype: Self + """ + deserializer = Deserializer(cls._infer_class_models()) + deserializer.key_extractors = ( # type: ignore + [ # type: ignore + attribute_key_case_insensitive_extractor, + rest_key_case_insensitive_extractor, + last_rest_key_case_insensitive_extractor, + ] + if key_extractors is None + else key_extractors + ) + return deserializer(cls.__name__, data, content_type=content_type) # type: ignore + + @classmethod + def _flatten_subtype(cls, key, objects): + if "_subtype_map" not in cls.__dict__: + return {} + result = dict(cls._subtype_map[key]) + for valuetype in cls._subtype_map[key].values(): + result.update(objects[valuetype]._flatten_subtype(key, objects)) # pylint: disable=protected-access + return result + + @classmethod + def _classify(cls, response, objects): + """Check the class _subtype_map for any child classes. + We want to ignore any inherited _subtype_maps. + + :param dict response: The initial data + :param dict objects: The class objects + :returns: The class to be used + :rtype: class + """ + for subtype_key in cls.__dict__.get("_subtype_map", {}).keys(): + subtype_value = None + + if not isinstance(response, ET.Element): + rest_api_response_key = cls._get_rest_key_parts(subtype_key)[-1] + subtype_value = response.get(rest_api_response_key, None) or response.get(subtype_key, None) + else: + subtype_value = xml_key_extractor(subtype_key, cls._attribute_map[subtype_key], response) + if subtype_value: + # Try to match base class. Can be class name only + # (bug to fix in Autorest to support x-ms-discriminator-name) + if cls.__name__ == subtype_value: + return cls + flatten_mapping_type = cls._flatten_subtype(subtype_key, objects) + try: + return objects[flatten_mapping_type[subtype_value]] # type: ignore + except KeyError: + _LOGGER.warning( + "Subtype value %s has no mapping, use base class %s.", + subtype_value, + cls.__name__, + ) + break + else: + _LOGGER.warning("Discriminator %s is absent or null, use base class %s.", subtype_key, cls.__name__) + break + return cls + + @classmethod + def _get_rest_key_parts(cls, attr_key): + """Get the RestAPI key of this attr, split it and decode part + :param str attr_key: Attribute key must be in attribute_map. + :returns: A list of RestAPI part + :rtype: list + """ + rest_split_key = _FLATTEN.split(cls._attribute_map[attr_key]["key"]) + return [_decode_attribute_map_key(key_part) for key_part in rest_split_key] + + +def _decode_attribute_map_key(key): + """This decode a key in an _attribute_map to the actual key we want to look at + inside the received data. + + :param str key: A key string from the generated code + :returns: The decoded key + :rtype: str + """ + return key.replace("\\.", ".") + + +class Serializer: # pylint: disable=too-many-public-methods + """Request object model serializer.""" + + basic_types = {str: "str", int: "int", bool: "bool", float: "float"} + + _xml_basic_types_serializers = {"bool": lambda x: str(x).lower()} + days = {0: "Mon", 1: "Tue", 2: "Wed", 3: "Thu", 4: "Fri", 5: "Sat", 6: "Sun"} + months = { + 1: "Jan", + 2: "Feb", + 3: "Mar", + 4: "Apr", + 5: "May", + 6: "Jun", + 7: "Jul", + 8: "Aug", + 9: "Sep", + 10: "Oct", + 11: "Nov", + 12: "Dec", + } + validation = { + "min_length": lambda x, y: len(x) < y, + "max_length": lambda x, y: len(x) > y, + "minimum": lambda x, y: x < y, + "maximum": lambda x, y: x > y, + "minimum_ex": lambda x, y: x <= y, + "maximum_ex": lambda x, y: x >= y, + "min_items": lambda x, y: len(x) < y, + "max_items": lambda x, y: len(x) > y, + "pattern": lambda x, y: not re.match(y, x, re.UNICODE), + "unique": lambda x, y: len(x) != len(set(x)), + "multiple": lambda x, y: x % y != 0, + } + + def __init__(self, classes: Optional[Mapping[str, type]] = None) -> None: + self.serialize_type = { + "iso-8601": Serializer.serialize_iso, + "rfc-1123": Serializer.serialize_rfc, + "unix-time": Serializer.serialize_unix, + "duration": Serializer.serialize_duration, + "date": Serializer.serialize_date, + "time": Serializer.serialize_time, + "decimal": Serializer.serialize_decimal, + "long": Serializer.serialize_long, + "bytearray": Serializer.serialize_bytearray, + "base64": Serializer.serialize_base64, + "object": self.serialize_object, + "[]": self.serialize_iter, + "{}": self.serialize_dict, + } + self.dependencies: Dict[str, type] = dict(classes) if classes else {} + self.key_transformer = full_restapi_key_transformer + self.client_side_validation = True + + def _serialize( # pylint: disable=too-many-nested-blocks, too-many-branches, too-many-statements, too-many-locals + self, target_obj, data_type=None, **kwargs + ): + """Serialize data into a string according to type. + + :param object target_obj: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str, dict + :raises SerializationError: if serialization fails. + :returns: The serialized data. + """ + key_transformer = kwargs.get("key_transformer", self.key_transformer) + keep_readonly = kwargs.get("keep_readonly", False) + if target_obj is None: + return None + + attr_name = None + class_name = target_obj.__class__.__name__ + + if data_type: + return self.serialize_data(target_obj, data_type, **kwargs) + + if not hasattr(target_obj, "_attribute_map"): + data_type = type(target_obj).__name__ + if data_type in self.basic_types.values(): + return self.serialize_data(target_obj, data_type, **kwargs) + + # Force "is_xml" kwargs if we detect a XML model + try: + is_xml_model_serialization = kwargs["is_xml"] + except KeyError: + is_xml_model_serialization = kwargs.setdefault("is_xml", target_obj.is_xml_model()) + + serialized = {} + if is_xml_model_serialization: + serialized = target_obj._create_xml_node() # pylint: disable=protected-access + try: + attributes = target_obj._attribute_map # pylint: disable=protected-access + for attr, attr_desc in attributes.items(): + attr_name = attr + if not keep_readonly and target_obj._validation.get( # pylint: disable=protected-access + attr_name, {} + ).get("readonly", False): + continue + + if attr_name == "additional_properties" and attr_desc["key"] == "": + if target_obj.additional_properties is not None: + serialized.update(target_obj.additional_properties) + continue + try: + + orig_attr = getattr(target_obj, attr) + if is_xml_model_serialization: + pass # Don't provide "transformer" for XML for now. Keep "orig_attr" + else: # JSON + keys, orig_attr = key_transformer(attr, attr_desc.copy(), orig_attr) + keys = keys if isinstance(keys, list) else [keys] + + kwargs["serialization_ctxt"] = attr_desc + new_attr = self.serialize_data(orig_attr, attr_desc["type"], **kwargs) + + if is_xml_model_serialization: + xml_desc = attr_desc.get("xml", {}) + xml_name = xml_desc.get("name", attr_desc["key"]) + xml_prefix = xml_desc.get("prefix", None) + xml_ns = xml_desc.get("ns", None) + if xml_desc.get("attr", False): + if xml_ns: + ET.register_namespace(xml_prefix, xml_ns) + xml_name = "{{{}}}{}".format(xml_ns, xml_name) + serialized.set(xml_name, new_attr) # type: ignore + continue + if xml_desc.get("text", False): + serialized.text = new_attr # type: ignore + continue + if isinstance(new_attr, list): + serialized.extend(new_attr) # type: ignore + elif isinstance(new_attr, ET.Element): + # If the down XML has no XML/Name, + # we MUST replace the tag with the local tag. But keeping the namespaces. + if "name" not in getattr(orig_attr, "_xml_map", {}): + splitted_tag = new_attr.tag.split("}") + if len(splitted_tag) == 2: # Namespace + new_attr.tag = "}".join([splitted_tag[0], xml_name]) + else: + new_attr.tag = xml_name + serialized.append(new_attr) # type: ignore + else: # That's a basic type + # Integrate namespace if necessary + local_node = _create_xml_node(xml_name, xml_prefix, xml_ns) + local_node.text = str(new_attr) + serialized.append(local_node) # type: ignore + else: # JSON + for k in reversed(keys): # type: ignore + new_attr = {k: new_attr} + + _new_attr = new_attr + _serialized = serialized + for k in keys: # type: ignore + if k not in _serialized: + _serialized.update(_new_attr) # type: ignore + _new_attr = _new_attr[k] # type: ignore + _serialized = _serialized[k] + except ValueError as err: + if isinstance(err, SerializationError): + raise + + except (AttributeError, KeyError, TypeError) as err: + msg = "Attribute {} in object {} cannot be serialized.\n{}".format(attr_name, class_name, str(target_obj)) + raise SerializationError(msg) from err + return serialized + + def body(self, data, data_type, **kwargs): + """Serialize data intended for a request body. + + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: dict + :raises SerializationError: if serialization fails. + :raises ValueError: if data is None + :returns: The serialized request body + """ + + # Just in case this is a dict + internal_data_type_str = data_type.strip("[]{}") + internal_data_type = self.dependencies.get(internal_data_type_str, None) + try: + is_xml_model_serialization = kwargs["is_xml"] + except KeyError: + if internal_data_type and issubclass(internal_data_type, Model): + is_xml_model_serialization = kwargs.setdefault("is_xml", internal_data_type.is_xml_model()) + else: + is_xml_model_serialization = False + if internal_data_type and not isinstance(internal_data_type, Enum): + try: + deserializer = Deserializer(self.dependencies) + # Since it's on serialization, it's almost sure that format is not JSON REST + # We're not able to deal with additional properties for now. + deserializer.additional_properties_detection = False + if is_xml_model_serialization: + deserializer.key_extractors = [ # type: ignore + attribute_key_case_insensitive_extractor, + ] + else: + deserializer.key_extractors = [ + rest_key_case_insensitive_extractor, + attribute_key_case_insensitive_extractor, + last_rest_key_case_insensitive_extractor, + ] + data = deserializer._deserialize(data_type, data) # pylint: disable=protected-access + except DeserializationError as err: + raise SerializationError("Unable to build a model: " + str(err)) from err + + return self._serialize(data, data_type, **kwargs) + + def url(self, name, data, data_type, **kwargs): + """Serialize data intended for a URL path. + + :param str name: The name of the URL path parameter. + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str + :returns: The serialized URL path + :raises TypeError: if serialization fails. + :raises ValueError: if data is None + """ + try: + output = self.serialize_data(data, data_type, **kwargs) + if data_type == "bool": + output = json.dumps(output) + + if kwargs.get("skip_quote") is True: + output = str(output) + output = output.replace("{", quote("{")).replace("}", quote("}")) + else: + output = quote(str(output), safe="") + except SerializationError as exc: + raise TypeError("{} must be type {}.".format(name, data_type)) from exc + return output + + def query(self, name, data, data_type, **kwargs): + """Serialize data intended for a URL query. + + :param str name: The name of the query parameter. + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str, list + :raises TypeError: if serialization fails. + :raises ValueError: if data is None + :returns: The serialized query parameter + """ + try: + # Treat the list aside, since we don't want to encode the div separator + if data_type.startswith("["): + internal_data_type = data_type[1:-1] + do_quote = not kwargs.get("skip_quote", False) + return self.serialize_iter(data, internal_data_type, do_quote=do_quote, **kwargs) + + # Not a list, regular serialization + output = self.serialize_data(data, data_type, **kwargs) + if data_type == "bool": + output = json.dumps(output) + if kwargs.get("skip_quote") is True: + output = str(output) + else: + output = quote(str(output), safe="") + except SerializationError as exc: + raise TypeError("{} must be type {}.".format(name, data_type)) from exc + return str(output) + + def header(self, name, data, data_type, **kwargs): + """Serialize data intended for a request header. + + :param str name: The name of the header. + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str + :raises TypeError: if serialization fails. + :raises ValueError: if data is None + :returns: The serialized header + """ + try: + if data_type in ["[str]"]: + data = ["" if d is None else d for d in data] + + output = self.serialize_data(data, data_type, **kwargs) + if data_type == "bool": + output = json.dumps(output) + except SerializationError as exc: + raise TypeError("{} must be type {}.".format(name, data_type)) from exc + return str(output) + + def serialize_data(self, data, data_type, **kwargs): + """Serialize generic data according to supplied data type. + + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :raises AttributeError: if required data is None. + :raises ValueError: if data is None + :raises SerializationError: if serialization fails. + :returns: The serialized data. + :rtype: str, int, float, bool, dict, list + """ + if data is None: + raise ValueError("No value for given attribute") + + try: + if data is CoreNull: + return None + if data_type in self.basic_types.values(): + return self.serialize_basic(data, data_type, **kwargs) + + if data_type in self.serialize_type: + return self.serialize_type[data_type](data, **kwargs) + + # If dependencies is empty, try with current data class + # It has to be a subclass of Enum anyway + enum_type = self.dependencies.get(data_type, data.__class__) + if issubclass(enum_type, Enum): + return Serializer.serialize_enum(data, enum_obj=enum_type) + + iter_type = data_type[0] + data_type[-1] + if iter_type in self.serialize_type: + return self.serialize_type[iter_type](data, data_type[1:-1], **kwargs) + + except (ValueError, TypeError) as err: + msg = "Unable to serialize value: {!r} as type: {!r}." + raise SerializationError(msg.format(data, data_type)) from err + return self._serialize(data, **kwargs) + + @classmethod + def _get_custom_serializers(cls, data_type, **kwargs): # pylint: disable=inconsistent-return-statements + custom_serializer = kwargs.get("basic_types_serializers", {}).get(data_type) + if custom_serializer: + return custom_serializer + if kwargs.get("is_xml", False): + return cls._xml_basic_types_serializers.get(data_type) + + @classmethod + def serialize_basic(cls, data, data_type, **kwargs): + """Serialize basic builting data type. + Serializes objects to str, int, float or bool. + + Possible kwargs: + - basic_types_serializers dict[str, callable] : If set, use the callable as serializer + - is_xml bool : If set, use xml_basic_types_serializers + + :param obj data: Object to be serialized. + :param str data_type: Type of object in the iterable. + :rtype: str, int, float, bool + :return: serialized object + """ + custom_serializer = cls._get_custom_serializers(data_type, **kwargs) + if custom_serializer: + return custom_serializer(data) + if data_type == "str": + return cls.serialize_unicode(data) + return eval(data_type)(data) # nosec # pylint: disable=eval-used + + @classmethod + def serialize_unicode(cls, data): + """Special handling for serializing unicode strings in Py2. + Encode to UTF-8 if unicode, otherwise handle as a str. + + :param str data: Object to be serialized. + :rtype: str + :return: serialized object + """ + try: # If I received an enum, return its value + return data.value + except AttributeError: + pass + + try: + if isinstance(data, unicode): # type: ignore + # Don't change it, JSON and XML ElementTree are totally able + # to serialize correctly u'' strings + return data + except NameError: + return str(data) + return str(data) + + def serialize_iter(self, data, iter_type, div=None, **kwargs): + """Serialize iterable. + + Supported kwargs: + - serialization_ctxt dict : The current entry of _attribute_map, or same format. + serialization_ctxt['type'] should be same as data_type. + - is_xml bool : If set, serialize as XML + + :param list data: Object to be serialized. + :param str iter_type: Type of object in the iterable. + :param str div: If set, this str will be used to combine the elements + in the iterable into a combined string. Default is 'None'. + Defaults to False. + :rtype: list, str + :return: serialized iterable + """ + if isinstance(data, str): + raise SerializationError("Refuse str type as a valid iter type.") + + serialization_ctxt = kwargs.get("serialization_ctxt", {}) + is_xml = kwargs.get("is_xml", False) + + serialized = [] + for d in data: + try: + serialized.append(self.serialize_data(d, iter_type, **kwargs)) + except ValueError as err: + if isinstance(err, SerializationError): + raise + serialized.append(None) + + if kwargs.get("do_quote", False): + serialized = ["" if s is None else quote(str(s), safe="") for s in serialized] + + if div: + serialized = ["" if s is None else str(s) for s in serialized] + serialized = div.join(serialized) + + if "xml" in serialization_ctxt or is_xml: + # XML serialization is more complicated + xml_desc = serialization_ctxt.get("xml", {}) + xml_name = xml_desc.get("name") + if not xml_name: + xml_name = serialization_ctxt["key"] + + # Create a wrap node if necessary (use the fact that Element and list have "append") + is_wrapped = xml_desc.get("wrapped", False) + node_name = xml_desc.get("itemsName", xml_name) + if is_wrapped: + final_result = _create_xml_node(xml_name, xml_desc.get("prefix", None), xml_desc.get("ns", None)) + else: + final_result = [] + # All list elements to "local_node" + for el in serialized: + if isinstance(el, ET.Element): + el_node = el + else: + el_node = _create_xml_node(node_name, xml_desc.get("prefix", None), xml_desc.get("ns", None)) + if el is not None: # Otherwise it writes "None" :-p + el_node.text = str(el) + final_result.append(el_node) + return final_result + return serialized + + def serialize_dict(self, attr, dict_type, **kwargs): + """Serialize a dictionary of objects. + + :param dict attr: Object to be serialized. + :param str dict_type: Type of object in the dictionary. + :rtype: dict + :return: serialized dictionary + """ + serialization_ctxt = kwargs.get("serialization_ctxt", {}) + serialized = {} + for key, value in attr.items(): + try: + serialized[self.serialize_unicode(key)] = self.serialize_data(value, dict_type, **kwargs) + except ValueError as err: + if isinstance(err, SerializationError): + raise + serialized[self.serialize_unicode(key)] = None + + if "xml" in serialization_ctxt: + # XML serialization is more complicated + xml_desc = serialization_ctxt["xml"] + xml_name = xml_desc["name"] + + final_result = _create_xml_node(xml_name, xml_desc.get("prefix", None), xml_desc.get("ns", None)) + for key, value in serialized.items(): + ET.SubElement(final_result, key).text = value + return final_result + + return serialized + + def serialize_object(self, attr, **kwargs): # pylint: disable=too-many-return-statements + """Serialize a generic object. + This will be handled as a dictionary. If object passed in is not + a basic type (str, int, float, dict, list) it will simply be + cast to str. + + :param dict attr: Object to be serialized. + :rtype: dict or str + :return: serialized object + """ + if attr is None: + return None + if isinstance(attr, ET.Element): + return attr + obj_type = type(attr) + if obj_type in self.basic_types: + return self.serialize_basic(attr, self.basic_types[obj_type], **kwargs) + if obj_type is _long_type: + return self.serialize_long(attr) + if obj_type is str: + return self.serialize_unicode(attr) + if obj_type is datetime.datetime: + return self.serialize_iso(attr) + if obj_type is datetime.date: + return self.serialize_date(attr) + if obj_type is datetime.time: + return self.serialize_time(attr) + if obj_type is datetime.timedelta: + return self.serialize_duration(attr) + if obj_type is decimal.Decimal: + return self.serialize_decimal(attr) + + # If it's a model or I know this dependency, serialize as a Model + if obj_type in self.dependencies.values() or isinstance(attr, Model): + return self._serialize(attr) + + if obj_type == dict: + serialized = {} + for key, value in attr.items(): + try: + serialized[self.serialize_unicode(key)] = self.serialize_object(value, **kwargs) + except ValueError: + serialized[self.serialize_unicode(key)] = None + return serialized + + if obj_type == list: + serialized = [] + for obj in attr: + try: + serialized.append(self.serialize_object(obj, **kwargs)) + except ValueError: + pass + return serialized + return str(attr) + + @staticmethod + def serialize_enum(attr, enum_obj=None): + try: + result = attr.value + except AttributeError: + result = attr + try: + enum_obj(result) # type: ignore + return result + except ValueError as exc: + for enum_value in enum_obj: # type: ignore + if enum_value.value.lower() == str(attr).lower(): + return enum_value.value + error = "{!r} is not valid value for enum {!r}" + raise SerializationError(error.format(attr, enum_obj)) from exc + + @staticmethod + def serialize_bytearray(attr, **kwargs): # pylint: disable=unused-argument + """Serialize bytearray into base-64 string. + + :param str attr: Object to be serialized. + :rtype: str + :return: serialized base64 + """ + return b64encode(attr).decode() + + @staticmethod + def serialize_base64(attr, **kwargs): # pylint: disable=unused-argument + """Serialize str into base-64 string. + + :param str attr: Object to be serialized. + :rtype: str + :return: serialized base64 + """ + encoded = b64encode(attr).decode("ascii") + return encoded.strip("=").replace("+", "-").replace("/", "_") + + @staticmethod + def serialize_decimal(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Decimal object to float. + + :param decimal attr: Object to be serialized. + :rtype: float + :return: serialized decimal + """ + return float(attr) + + @staticmethod + def serialize_long(attr, **kwargs): # pylint: disable=unused-argument + """Serialize long (Py2) or int (Py3). + + :param int attr: Object to be serialized. + :rtype: int/long + :return: serialized long + """ + return _long_type(attr) + + @staticmethod + def serialize_date(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Date object into ISO-8601 formatted string. + + :param Date attr: Object to be serialized. + :rtype: str + :return: serialized date + """ + if isinstance(attr, str): + attr = isodate.parse_date(attr) + t = "{:04}-{:02}-{:02}".format(attr.year, attr.month, attr.day) + return t + + @staticmethod + def serialize_time(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Time object into ISO-8601 formatted string. + + :param datetime.time attr: Object to be serialized. + :rtype: str + :return: serialized time + """ + if isinstance(attr, str): + attr = isodate.parse_time(attr) + t = "{:02}:{:02}:{:02}".format(attr.hour, attr.minute, attr.second) + if attr.microsecond: + t += ".{:02}".format(attr.microsecond) + return t + + @staticmethod + def serialize_duration(attr, **kwargs): # pylint: disable=unused-argument + """Serialize TimeDelta object into ISO-8601 formatted string. + + :param TimeDelta attr: Object to be serialized. + :rtype: str + :return: serialized duration + """ + if isinstance(attr, str): + attr = isodate.parse_duration(attr) + return isodate.duration_isoformat(attr) + + @staticmethod + def serialize_rfc(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Datetime object into RFC-1123 formatted string. + + :param Datetime attr: Object to be serialized. + :rtype: str + :raises TypeError: if format invalid. + :return: serialized rfc + """ + try: + if not attr.tzinfo: + _LOGGER.warning("Datetime with no tzinfo will be considered UTC.") + utc = attr.utctimetuple() + except AttributeError as exc: + raise TypeError("RFC1123 object must be valid Datetime object.") from exc + + return "{}, {:02} {} {:04} {:02}:{:02}:{:02} GMT".format( + Serializer.days[utc.tm_wday], + utc.tm_mday, + Serializer.months[utc.tm_mon], + utc.tm_year, + utc.tm_hour, + utc.tm_min, + utc.tm_sec, + ) + + @staticmethod + def serialize_iso(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Datetime object into ISO-8601 formatted string. + + :param Datetime attr: Object to be serialized. + :rtype: str + :raises SerializationError: if format invalid. + :return: serialized iso + """ + if isinstance(attr, str): + attr = isodate.parse_datetime(attr) + try: + if not attr.tzinfo: + _LOGGER.warning("Datetime with no tzinfo will be considered UTC.") + utc = attr.utctimetuple() + if utc.tm_year > 9999 or utc.tm_year < 1: + raise OverflowError("Hit max or min date") + + microseconds = str(attr.microsecond).rjust(6, "0").rstrip("0").ljust(3, "0") + if microseconds: + microseconds = "." + microseconds + date = "{:04}-{:02}-{:02}T{:02}:{:02}:{:02}".format( + utc.tm_year, utc.tm_mon, utc.tm_mday, utc.tm_hour, utc.tm_min, utc.tm_sec + ) + return date + microseconds + "Z" + except (ValueError, OverflowError) as err: + msg = "Unable to serialize datetime object." + raise SerializationError(msg) from err + except AttributeError as err: + msg = "ISO-8601 object must be valid Datetime object." + raise TypeError(msg) from err + + @staticmethod + def serialize_unix(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Datetime object into IntTime format. + This is represented as seconds. + + :param Datetime attr: Object to be serialized. + :rtype: int + :raises SerializationError: if format invalid + :return: serialied unix + """ + if isinstance(attr, int): + return attr + try: + if not attr.tzinfo: + _LOGGER.warning("Datetime with no tzinfo will be considered UTC.") + return int(calendar.timegm(attr.utctimetuple())) + except AttributeError as exc: + raise TypeError("Unix time object must be valid Datetime object.") from exc + + +def rest_key_extractor(attr, attr_desc, data): # pylint: disable=unused-argument + key = attr_desc["key"] + working_data = data + + while "." in key: + # Need the cast, as for some reasons "split" is typed as list[str | Any] + dict_keys = cast(List[str], _FLATTEN.split(key)) + if len(dict_keys) == 1: + key = _decode_attribute_map_key(dict_keys[0]) + break + working_key = _decode_attribute_map_key(dict_keys[0]) + working_data = working_data.get(working_key, data) + if working_data is None: + # If at any point while following flatten JSON path see None, it means + # that all properties under are None as well + return None + key = ".".join(dict_keys[1:]) + + return working_data.get(key) + + +def rest_key_case_insensitive_extractor( # pylint: disable=unused-argument, inconsistent-return-statements + attr, attr_desc, data +): + key = attr_desc["key"] + working_data = data + + while "." in key: + dict_keys = _FLATTEN.split(key) + if len(dict_keys) == 1: + key = _decode_attribute_map_key(dict_keys[0]) + break + working_key = _decode_attribute_map_key(dict_keys[0]) + working_data = attribute_key_case_insensitive_extractor(working_key, None, working_data) + if working_data is None: + # If at any point while following flatten JSON path see None, it means + # that all properties under are None as well + return None + key = ".".join(dict_keys[1:]) + + if working_data: + return attribute_key_case_insensitive_extractor(key, None, working_data) + + +def last_rest_key_extractor(attr, attr_desc, data): # pylint: disable=unused-argument + """Extract the attribute in "data" based on the last part of the JSON path key. + + :param str attr: The attribute to extract + :param dict attr_desc: The attribute description + :param dict data: The data to extract from + :rtype: object + :returns: The extracted attribute + """ + key = attr_desc["key"] + dict_keys = _FLATTEN.split(key) + return attribute_key_extractor(dict_keys[-1], None, data) + + +def last_rest_key_case_insensitive_extractor(attr, attr_desc, data): # pylint: disable=unused-argument + """Extract the attribute in "data" based on the last part of the JSON path key. + + This is the case insensitive version of "last_rest_key_extractor" + :param str attr: The attribute to extract + :param dict attr_desc: The attribute description + :param dict data: The data to extract from + :rtype: object + :returns: The extracted attribute + """ + key = attr_desc["key"] + dict_keys = _FLATTEN.split(key) + return attribute_key_case_insensitive_extractor(dict_keys[-1], None, data) + + +def attribute_key_extractor(attr, _, data): + return data.get(attr) + + +def attribute_key_case_insensitive_extractor(attr, _, data): + found_key = None + lower_attr = attr.lower() + for key in data: + if lower_attr == key.lower(): + found_key = key + break + + return data.get(found_key) + + +def _extract_name_from_internal_type(internal_type): + """Given an internal type XML description, extract correct XML name with namespace. + + :param dict internal_type: An model type + :rtype: tuple + :returns: A tuple XML name + namespace dict + """ + internal_type_xml_map = getattr(internal_type, "_xml_map", {}) + xml_name = internal_type_xml_map.get("name", internal_type.__name__) + xml_ns = internal_type_xml_map.get("ns", None) + if xml_ns: + xml_name = "{{{}}}{}".format(xml_ns, xml_name) + return xml_name + + +def xml_key_extractor(attr, attr_desc, data): # pylint: disable=unused-argument,too-many-return-statements + if isinstance(data, dict): + return None + + # Test if this model is XML ready first + if not isinstance(data, ET.Element): + return None + + xml_desc = attr_desc.get("xml", {}) + xml_name = xml_desc.get("name", attr_desc["key"]) + + # Look for a children + is_iter_type = attr_desc["type"].startswith("[") + is_wrapped = xml_desc.get("wrapped", False) + internal_type = attr_desc.get("internalType", None) + internal_type_xml_map = getattr(internal_type, "_xml_map", {}) + + # Integrate namespace if necessary + xml_ns = xml_desc.get("ns", internal_type_xml_map.get("ns", None)) + if xml_ns: + xml_name = "{{{}}}{}".format(xml_ns, xml_name) + + # If it's an attribute, that's simple + if xml_desc.get("attr", False): + return data.get(xml_name) + + # If it's x-ms-text, that's simple too + if xml_desc.get("text", False): + return data.text + + # Scenario where I take the local name: + # - Wrapped node + # - Internal type is an enum (considered basic types) + # - Internal type has no XML/Name node + if is_wrapped or (internal_type and (issubclass(internal_type, Enum) or "name" not in internal_type_xml_map)): + children = data.findall(xml_name) + # If internal type has a local name and it's not a list, I use that name + elif not is_iter_type and internal_type and "name" in internal_type_xml_map: + xml_name = _extract_name_from_internal_type(internal_type) + children = data.findall(xml_name) + # That's an array + else: + if internal_type: # Complex type, ignore itemsName and use the complex type name + items_name = _extract_name_from_internal_type(internal_type) + else: + items_name = xml_desc.get("itemsName", xml_name) + children = data.findall(items_name) + + if len(children) == 0: + if is_iter_type: + if is_wrapped: + return None # is_wrapped no node, we want None + return [] # not wrapped, assume empty list + return None # Assume it's not there, maybe an optional node. + + # If is_iter_type and not wrapped, return all found children + if is_iter_type: + if not is_wrapped: + return children + # Iter and wrapped, should have found one node only (the wrap one) + if len(children) != 1: + raise DeserializationError( + "Tried to deserialize an array not wrapped, and found several nodes '{}'. Maybe you should declare this array as wrapped?".format( + xml_name + ) + ) + return list(children[0]) # Might be empty list and that's ok. + + # Here it's not a itertype, we should have found one element only or empty + if len(children) > 1: + raise DeserializationError("Find several XML '{}' where it was not expected".format(xml_name)) + return children[0] + + +class Deserializer: + """Response object model deserializer. + + :param dict classes: Class type dictionary for deserializing complex types. + :ivar list key_extractors: Ordered list of extractors to be used by this deserializer. + """ + + basic_types = {str: "str", int: "int", bool: "bool", float: "float"} + + valid_date = re.compile(r"\d{4}[-]\d{2}[-]\d{2}T\d{2}:\d{2}:\d{2}\.?\d*Z?[-+]?[\d{2}]?:?[\d{2}]?") + + def __init__(self, classes: Optional[Mapping[str, type]] = None) -> None: + self.deserialize_type = { + "iso-8601": Deserializer.deserialize_iso, + "rfc-1123": Deserializer.deserialize_rfc, + "unix-time": Deserializer.deserialize_unix, + "duration": Deserializer.deserialize_duration, + "date": Deserializer.deserialize_date, + "time": Deserializer.deserialize_time, + "decimal": Deserializer.deserialize_decimal, + "long": Deserializer.deserialize_long, + "bytearray": Deserializer.deserialize_bytearray, + "base64": Deserializer.deserialize_base64, + "object": self.deserialize_object, + "[]": self.deserialize_iter, + "{}": self.deserialize_dict, + } + self.deserialize_expected_types = { + "duration": (isodate.Duration, datetime.timedelta), + "iso-8601": (datetime.datetime), + } + self.dependencies: Dict[str, type] = dict(classes) if classes else {} + self.key_extractors = [rest_key_extractor, xml_key_extractor] + # Additional properties only works if the "rest_key_extractor" is used to + # extract the keys. Making it to work whatever the key extractor is too much + # complicated, with no real scenario for now. + # So adding a flag to disable additional properties detection. This flag should be + # used if your expect the deserialization to NOT come from a JSON REST syntax. + # Otherwise, result are unexpected + self.additional_properties_detection = True + + def __call__(self, target_obj, response_data, content_type=None): + """Call the deserializer to process a REST response. + + :param str target_obj: Target data type to deserialize to. + :param requests.Response response_data: REST response object. + :param str content_type: Swagger "produces" if available. + :raises DeserializationError: if deserialization fails. + :return: Deserialized object. + :rtype: object + """ + data = self._unpack_content(response_data, content_type) + return self._deserialize(target_obj, data) + + def _deserialize(self, target_obj, data): # pylint: disable=inconsistent-return-statements + """Call the deserializer on a model. + + Data needs to be already deserialized as JSON or XML ElementTree + + :param str target_obj: Target data type to deserialize to. + :param object data: Object to deserialize. + :raises DeserializationError: if deserialization fails. + :return: Deserialized object. + :rtype: object + """ + # This is already a model, go recursive just in case + if hasattr(data, "_attribute_map"): + constants = [name for name, config in getattr(data, "_validation", {}).items() if config.get("constant")] + try: + for attr, mapconfig in data._attribute_map.items(): # pylint: disable=protected-access + if attr in constants: + continue + value = getattr(data, attr) + if value is None: + continue + local_type = mapconfig["type"] + internal_data_type = local_type.strip("[]{}") + if internal_data_type not in self.dependencies or isinstance(internal_data_type, Enum): + continue + setattr(data, attr, self._deserialize(local_type, value)) + return data + except AttributeError: + return + + response, class_name = self._classify_target(target_obj, data) + + if isinstance(response, str): + return self.deserialize_data(data, response) + if isinstance(response, type) and issubclass(response, Enum): + return self.deserialize_enum(data, response) + + if data is None or data is CoreNull: + return data + try: + attributes = response._attribute_map # type: ignore # pylint: disable=protected-access + d_attrs = {} + for attr, attr_desc in attributes.items(): + # Check empty string. If it's not empty, someone has a real "additionalProperties"... + if attr == "additional_properties" and attr_desc["key"] == "": + continue + raw_value = None + # Enhance attr_desc with some dynamic data + attr_desc = attr_desc.copy() # Do a copy, do not change the real one + internal_data_type = attr_desc["type"].strip("[]{}") + if internal_data_type in self.dependencies: + attr_desc["internalType"] = self.dependencies[internal_data_type] + + for key_extractor in self.key_extractors: + found_value = key_extractor(attr, attr_desc, data) + if found_value is not None: + if raw_value is not None and raw_value != found_value: + msg = ( + "Ignoring extracted value '%s' from %s for key '%s'" + " (duplicate extraction, follow extractors order)" + ) + _LOGGER.warning(msg, found_value, key_extractor, attr) + continue + raw_value = found_value + + value = self.deserialize_data(raw_value, attr_desc["type"]) + d_attrs[attr] = value + except (AttributeError, TypeError, KeyError) as err: + msg = "Unable to deserialize to object: " + class_name # type: ignore + raise DeserializationError(msg) from err + additional_properties = self._build_additional_properties(attributes, data) + return self._instantiate_model(response, d_attrs, additional_properties) + + def _build_additional_properties(self, attribute_map, data): + if not self.additional_properties_detection: + return None + if "additional_properties" in attribute_map and attribute_map.get("additional_properties", {}).get("key") != "": + # Check empty string. If it's not empty, someone has a real "additionalProperties" + return None + if isinstance(data, ET.Element): + data = {el.tag: el.text for el in data} + + known_keys = { + _decode_attribute_map_key(_FLATTEN.split(desc["key"])[0]) + for desc in attribute_map.values() + if desc["key"] != "" + } + present_keys = set(data.keys()) + missing_keys = present_keys - known_keys + return {key: data[key] for key in missing_keys} + + def _classify_target(self, target, data): + """Check to see whether the deserialization target object can + be classified into a subclass. + Once classification has been determined, initialize object. + + :param str target: The target object type to deserialize to. + :param str/dict data: The response data to deserialize. + :return: The classified target object and its class name. + :rtype: tuple + """ + if target is None: + return None, None + + if isinstance(target, str): + try: + target = self.dependencies[target] + except KeyError: + return target, target + + try: + target = target._classify(data, self.dependencies) # type: ignore # pylint: disable=protected-access + except AttributeError: + pass # Target is not a Model, no classify + return target, target.__class__.__name__ # type: ignore + + def failsafe_deserialize(self, target_obj, data, content_type=None): + """Ignores any errors encountered in deserialization, + and falls back to not deserializing the object. Recommended + for use in error deserialization, as we want to return the + HttpResponseError to users, and not have them deal with + a deserialization error. + + :param str target_obj: The target object type to deserialize to. + :param str/dict data: The response data to deserialize. + :param str content_type: Swagger "produces" if available. + :return: Deserialized object. + :rtype: object + """ + try: + return self(target_obj, data, content_type=content_type) + except: # pylint: disable=bare-except + _LOGGER.debug( + "Ran into a deserialization error. Ignoring since this is failsafe deserialization", exc_info=True + ) + return None + + @staticmethod + def _unpack_content(raw_data, content_type=None): + """Extract the correct structure for deserialization. + + If raw_data is a PipelineResponse, try to extract the result of RawDeserializer. + if we can't, raise. Your Pipeline should have a RawDeserializer. + + If not a pipeline response and raw_data is bytes or string, use content-type + to decode it. If no content-type, try JSON. + + If raw_data is something else, bypass all logic and return it directly. + + :param obj raw_data: Data to be processed. + :param str content_type: How to parse if raw_data is a string/bytes. + :raises JSONDecodeError: If JSON is requested and parsing is impossible. + :raises UnicodeDecodeError: If bytes is not UTF8 + :rtype: object + :return: Unpacked content. + """ + # Assume this is enough to detect a Pipeline Response without importing it + context = getattr(raw_data, "context", {}) + if context: + if RawDeserializer.CONTEXT_NAME in context: + return context[RawDeserializer.CONTEXT_NAME] + raise ValueError("This pipeline didn't have the RawDeserializer policy; can't deserialize") + + # Assume this is enough to recognize universal_http.ClientResponse without importing it + if hasattr(raw_data, "body"): + return RawDeserializer.deserialize_from_http_generics(raw_data.text(), raw_data.headers) + + # Assume this enough to recognize requests.Response without importing it. + if hasattr(raw_data, "_content_consumed"): + return RawDeserializer.deserialize_from_http_generics(raw_data.text, raw_data.headers) + + if isinstance(raw_data, (str, bytes)) or hasattr(raw_data, "read"): + return RawDeserializer.deserialize_from_text(raw_data, content_type) # type: ignore + return raw_data + + def _instantiate_model(self, response, attrs, additional_properties=None): + """Instantiate a response model passing in deserialized args. + + :param Response response: The response model class. + :param dict attrs: The deserialized response attributes. + :param dict additional_properties: Additional properties to be set. + :rtype: Response + :return: The instantiated response model. + """ + if callable(response): + subtype = getattr(response, "_subtype_map", {}) + try: + readonly = [ + k + for k, v in response._validation.items() # pylint: disable=protected-access # type: ignore + if v.get("readonly") + ] + const = [ + k + for k, v in response._validation.items() # pylint: disable=protected-access # type: ignore + if v.get("constant") + ] + kwargs = {k: v for k, v in attrs.items() if k not in subtype and k not in readonly + const} + response_obj = response(**kwargs) + for attr in readonly: + setattr(response_obj, attr, attrs.get(attr)) + if additional_properties: + response_obj.additional_properties = additional_properties # type: ignore + return response_obj + except TypeError as err: + msg = "Unable to deserialize {} into model {}. ".format(kwargs, response) # type: ignore + raise DeserializationError(msg + str(err)) from err + else: + try: + for attr, value in attrs.items(): + setattr(response, attr, value) + return response + except Exception as exp: + msg = "Unable to populate response model. " + msg += "Type: {}, Error: {}".format(type(response), exp) + raise DeserializationError(msg) from exp + + def deserialize_data(self, data, data_type): # pylint: disable=too-many-return-statements + """Process data for deserialization according to data type. + + :param str data: The response string to be deserialized. + :param str data_type: The type to deserialize to. + :raises DeserializationError: if deserialization fails. + :return: Deserialized object. + :rtype: object + """ + if data is None: + return data + + try: + if not data_type: + return data + if data_type in self.basic_types.values(): + return self.deserialize_basic(data, data_type) + if data_type in self.deserialize_type: + if isinstance(data, self.deserialize_expected_types.get(data_type, tuple())): + return data + + is_a_text_parsing_type = lambda x: x not in [ # pylint: disable=unnecessary-lambda-assignment + "object", + "[]", + r"{}", + ] + if isinstance(data, ET.Element) and is_a_text_parsing_type(data_type) and not data.text: + return None + data_val = self.deserialize_type[data_type](data) + return data_val + + iter_type = data_type[0] + data_type[-1] + if iter_type in self.deserialize_type: + return self.deserialize_type[iter_type](data, data_type[1:-1]) + + obj_type = self.dependencies[data_type] + if issubclass(obj_type, Enum): + if isinstance(data, ET.Element): + data = data.text + return self.deserialize_enum(data, obj_type) + + except (ValueError, TypeError, AttributeError) as err: + msg = "Unable to deserialize response data." + msg += " Data: {}, {}".format(data, data_type) + raise DeserializationError(msg) from err + return self._deserialize(obj_type, data) + + def deserialize_iter(self, attr, iter_type): + """Deserialize an iterable. + + :param list attr: Iterable to be deserialized. + :param str iter_type: The type of object in the iterable. + :return: Deserialized iterable. + :rtype: list + """ + if attr is None: + return None + if isinstance(attr, ET.Element): # If I receive an element here, get the children + attr = list(attr) + if not isinstance(attr, (list, set)): + raise DeserializationError("Cannot deserialize as [{}] an object of type {}".format(iter_type, type(attr))) + return [self.deserialize_data(a, iter_type) for a in attr] + + def deserialize_dict(self, attr, dict_type): + """Deserialize a dictionary. + + :param dict/list attr: Dictionary to be deserialized. Also accepts + a list of key, value pairs. + :param str dict_type: The object type of the items in the dictionary. + :return: Deserialized dictionary. + :rtype: dict + """ + if isinstance(attr, list): + return {x["key"]: self.deserialize_data(x["value"], dict_type) for x in attr} + + if isinstance(attr, ET.Element): + # Transform value into {"Key": "value"} + attr = {el.tag: el.text for el in attr} + return {k: self.deserialize_data(v, dict_type) for k, v in attr.items()} + + def deserialize_object(self, attr, **kwargs): # pylint: disable=too-many-return-statements + """Deserialize a generic object. + This will be handled as a dictionary. + + :param dict attr: Dictionary to be deserialized. + :return: Deserialized object. + :rtype: dict + :raises TypeError: if non-builtin datatype encountered. + """ + if attr is None: + return None + if isinstance(attr, ET.Element): + # Do no recurse on XML, just return the tree as-is + return attr + if isinstance(attr, str): + return self.deserialize_basic(attr, "str") + obj_type = type(attr) + if obj_type in self.basic_types: + return self.deserialize_basic(attr, self.basic_types[obj_type]) + if obj_type is _long_type: + return self.deserialize_long(attr) + + if obj_type == dict: + deserialized = {} + for key, value in attr.items(): + try: + deserialized[key] = self.deserialize_object(value, **kwargs) + except ValueError: + deserialized[key] = None + return deserialized + + if obj_type == list: + deserialized = [] + for obj in attr: + try: + deserialized.append(self.deserialize_object(obj, **kwargs)) + except ValueError: + pass + return deserialized + + error = "Cannot deserialize generic object with type: " + raise TypeError(error + str(obj_type)) + + def deserialize_basic(self, attr, data_type): # pylint: disable=too-many-return-statements + """Deserialize basic builtin data type from string. + Will attempt to convert to str, int, float and bool. + This function will also accept '1', '0', 'true' and 'false' as + valid bool values. + + :param str attr: response string to be deserialized. + :param str data_type: deserialization data type. + :return: Deserialized basic type. + :rtype: str, int, float or bool + :raises TypeError: if string format is not valid. + """ + # If we're here, data is supposed to be a basic type. + # If it's still an XML node, take the text + if isinstance(attr, ET.Element): + attr = attr.text + if not attr: + if data_type == "str": + # None or '', node is empty string. + return "" + # None or '', node with a strong type is None. + # Don't try to model "empty bool" or "empty int" + return None + + if data_type == "bool": + if attr in [True, False, 1, 0]: + return bool(attr) + if isinstance(attr, str): + if attr.lower() in ["true", "1"]: + return True + if attr.lower() in ["false", "0"]: + return False + raise TypeError("Invalid boolean value: {}".format(attr)) + + if data_type == "str": + return self.deserialize_unicode(attr) + return eval(data_type)(attr) # nosec # pylint: disable=eval-used + + @staticmethod + def deserialize_unicode(data): + """Preserve unicode objects in Python 2, otherwise return data + as a string. + + :param str data: response string to be deserialized. + :return: Deserialized string. + :rtype: str or unicode + """ + # We might be here because we have an enum modeled as string, + # and we try to deserialize a partial dict with enum inside + if isinstance(data, Enum): + return data + + # Consider this is real string + try: + if isinstance(data, unicode): # type: ignore + return data + except NameError: + return str(data) + return str(data) + + @staticmethod + def deserialize_enum(data, enum_obj): + """Deserialize string into enum object. + + If the string is not a valid enum value it will be returned as-is + and a warning will be logged. + + :param str data: Response string to be deserialized. If this value is + None or invalid it will be returned as-is. + :param Enum enum_obj: Enum object to deserialize to. + :return: Deserialized enum object. + :rtype: Enum + """ + if isinstance(data, enum_obj) or data is None: + return data + if isinstance(data, Enum): + data = data.value + if isinstance(data, int): + # Workaround. We might consider remove it in the future. + try: + return list(enum_obj.__members__.values())[data] + except IndexError as exc: + error = "{!r} is not a valid index for enum {!r}" + raise DeserializationError(error.format(data, enum_obj)) from exc + try: + return enum_obj(str(data)) + except ValueError: + for enum_value in enum_obj: + if enum_value.value.lower() == str(data).lower(): + return enum_value + # We don't fail anymore for unknown value, we deserialize as a string + _LOGGER.warning("Deserializer is not able to find %s as valid enum in %s", data, enum_obj) + return Deserializer.deserialize_unicode(data) + + @staticmethod + def deserialize_bytearray(attr): + """Deserialize string into bytearray. + + :param str attr: response string to be deserialized. + :return: Deserialized bytearray + :rtype: bytearray + :raises TypeError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + return bytearray(b64decode(attr)) # type: ignore + + @staticmethod + def deserialize_base64(attr): + """Deserialize base64 encoded string into string. + + :param str attr: response string to be deserialized. + :return: Deserialized base64 string + :rtype: bytearray + :raises TypeError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + padding = "=" * (3 - (len(attr) + 3) % 4) # type: ignore + attr = attr + padding # type: ignore + encoded = attr.replace("-", "+").replace("_", "/") + return b64decode(encoded) + + @staticmethod + def deserialize_decimal(attr): + """Deserialize string into Decimal object. + + :param str attr: response string to be deserialized. + :return: Deserialized decimal + :raises DeserializationError: if string format invalid. + :rtype: decimal + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + return decimal.Decimal(str(attr)) # type: ignore + except decimal.DecimalException as err: + msg = "Invalid decimal {}".format(attr) + raise DeserializationError(msg) from err + + @staticmethod + def deserialize_long(attr): + """Deserialize string into long (Py2) or int (Py3). + + :param str attr: response string to be deserialized. + :return: Deserialized int + :rtype: long or int + :raises ValueError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + return _long_type(attr) # type: ignore + + @staticmethod + def deserialize_duration(attr): + """Deserialize ISO-8601 formatted string into TimeDelta object. + + :param str attr: response string to be deserialized. + :return: Deserialized duration + :rtype: TimeDelta + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + duration = isodate.parse_duration(attr) + except (ValueError, OverflowError, AttributeError) as err: + msg = "Cannot deserialize duration object." + raise DeserializationError(msg) from err + return duration + + @staticmethod + def deserialize_date(attr): + """Deserialize ISO-8601 formatted string into Date object. + + :param str attr: response string to be deserialized. + :return: Deserialized date + :rtype: Date + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + if re.search(r"[^\W\d_]", attr, re.I + re.U): # type: ignore + raise DeserializationError("Date must have only digits and -. Received: %s" % attr) + # This must NOT use defaultmonth/defaultday. Using None ensure this raises an exception. + return isodate.parse_date(attr, defaultmonth=0, defaultday=0) + + @staticmethod + def deserialize_time(attr): + """Deserialize ISO-8601 formatted string into time object. + + :param str attr: response string to be deserialized. + :return: Deserialized time + :rtype: datetime.time + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + if re.search(r"[^\W\d_]", attr, re.I + re.U): # type: ignore + raise DeserializationError("Date must have only digits and -. Received: %s" % attr) + return isodate.parse_time(attr) + + @staticmethod + def deserialize_rfc(attr): + """Deserialize RFC-1123 formatted string into Datetime object. + + :param str attr: response string to be deserialized. + :return: Deserialized RFC datetime + :rtype: Datetime + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + parsed_date = email.utils.parsedate_tz(attr) # type: ignore + date_obj = datetime.datetime( + *parsed_date[:6], tzinfo=datetime.timezone(datetime.timedelta(minutes=(parsed_date[9] or 0) / 60)) + ) + if not date_obj.tzinfo: + date_obj = date_obj.astimezone(tz=TZ_UTC) + except ValueError as err: + msg = "Cannot deserialize to rfc datetime object." + raise DeserializationError(msg) from err + return date_obj + + @staticmethod + def deserialize_iso(attr): + """Deserialize ISO-8601 formatted string into Datetime object. + + :param str attr: response string to be deserialized. + :return: Deserialized ISO datetime + :rtype: Datetime + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + attr = attr.upper() # type: ignore + match = Deserializer.valid_date.match(attr) + if not match: + raise ValueError("Invalid datetime string: " + attr) + + check_decimal = attr.split(".") + if len(check_decimal) > 1: + decimal_str = "" + for digit in check_decimal[1]: + if digit.isdigit(): + decimal_str += digit + else: + break + if len(decimal_str) > 6: + attr = attr.replace(decimal_str, decimal_str[0:6]) + + date_obj = isodate.parse_datetime(attr) + test_utc = date_obj.utctimetuple() + if test_utc.tm_year > 9999 or test_utc.tm_year < 1: + raise OverflowError("Hit max or min date") + except (ValueError, OverflowError, AttributeError) as err: + msg = "Cannot deserialize datetime object." + raise DeserializationError(msg) from err + return date_obj + + @staticmethod + def deserialize_unix(attr): + """Serialize Datetime object into IntTime format. + This is represented as seconds. + + :param int attr: Object to be serialized. + :return: Deserialized datetime + :rtype: Datetime + :raises DeserializationError: if format invalid + """ + if isinstance(attr, ET.Element): + attr = int(attr.text) # type: ignore + try: + attr = int(attr) + date_obj = datetime.datetime.fromtimestamp(attr, TZ_UTC) + except ValueError as err: + msg = "Cannot deserialize to unix datetime object." + raise DeserializationError(msg) from err + return date_obj diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/NonStringEnumsVersionTolerant/nonstringenumsversiontolerant/_client.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/NonStringEnumsVersionTolerant/nonstringenumsversiontolerant/_client.py index 3cbfee7fb3d..284e036b29f 100644 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/NonStringEnumsVersionTolerant/nonstringenumsversiontolerant/_client.py +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/NonStringEnumsVersionTolerant/nonstringenumsversiontolerant/_client.py @@ -15,7 +15,7 @@ from azure.core.rest import HttpRequest, HttpResponse from ._configuration import NonStringEnumsClientConfiguration -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer from .operations import FloatOperations, IntOperations diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/NonStringEnumsVersionTolerant/nonstringenumsversiontolerant/_utils/__init__.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/NonStringEnumsVersionTolerant/nonstringenumsversiontolerant/_utils/__init__.py new file mode 100644 index 00000000000..0af9b28f660 --- /dev/null +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/NonStringEnumsVersionTolerant/nonstringenumsversiontolerant/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/NonStringEnumsVersionTolerant/nonstringenumsversiontolerant/_utils/serialization.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/NonStringEnumsVersionTolerant/nonstringenumsversiontolerant/_utils/serialization.py new file mode 100644 index 00000000000..f5187701d7b --- /dev/null +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/NonStringEnumsVersionTolerant/nonstringenumsversiontolerant/_utils/serialization.py @@ -0,0 +1,2032 @@ +# pylint: disable=line-too-long,useless-suppression,too-many-lines +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +# pyright: reportUnnecessaryTypeIgnoreComment=false + +from base64 import b64decode, b64encode +import calendar +import datetime +import decimal +import email +from enum import Enum +import json +import logging +import re +import sys +import codecs +from typing import ( + Dict, + Any, + cast, + Optional, + Union, + AnyStr, + IO, + Mapping, + Callable, + MutableMapping, + List, +) + +try: + from urllib import quote # type: ignore +except ImportError: + from urllib.parse import quote +import xml.etree.ElementTree as ET + +import isodate # type: ignore +from typing_extensions import Self + +from azure.core.exceptions import DeserializationError, SerializationError +from azure.core.serialization import NULL as CoreNull + +_BOM = codecs.BOM_UTF8.decode(encoding="utf-8") + +JSON = MutableMapping[str, Any] + + +class RawDeserializer: + + # Accept "text" because we're open minded people... + JSON_REGEXP = re.compile(r"^(application|text)/([a-z+.]+\+)?json$") + + # Name used in context + CONTEXT_NAME = "deserialized_data" + + @classmethod + def deserialize_from_text(cls, data: Optional[Union[AnyStr, IO]], content_type: Optional[str] = None) -> Any: + """Decode data according to content-type. + + Accept a stream of data as well, but will be load at once in memory for now. + + If no content-type, will return the string version (not bytes, not stream) + + :param data: Input, could be bytes or stream (will be decoded with UTF8) or text + :type data: str or bytes or IO + :param str content_type: The content type. + :return: The deserialized data. + :rtype: object + """ + if hasattr(data, "read"): + # Assume a stream + data = cast(IO, data).read() + + if isinstance(data, bytes): + data_as_str = data.decode(encoding="utf-8-sig") + else: + # Explain to mypy the correct type. + data_as_str = cast(str, data) + + # Remove Byte Order Mark if present in string + data_as_str = data_as_str.lstrip(_BOM) + + if content_type is None: + return data + + if cls.JSON_REGEXP.match(content_type): + try: + return json.loads(data_as_str) + except ValueError as err: + raise DeserializationError("JSON is invalid: {}".format(err), err) from err + elif "xml" in (content_type or []): + try: + + try: + if isinstance(data, unicode): # type: ignore + # If I'm Python 2.7 and unicode XML will scream if I try a "fromstring" on unicode string + data_as_str = data_as_str.encode(encoding="utf-8") # type: ignore + except NameError: + pass + + return ET.fromstring(data_as_str) # nosec + except ET.ParseError as err: + # It might be because the server has an issue, and returned JSON with + # content-type XML.... + # So let's try a JSON load, and if it's still broken + # let's flow the initial exception + def _json_attemp(data): + try: + return True, json.loads(data) + except ValueError: + return False, None # Don't care about this one + + success, json_result = _json_attemp(data) + if success: + return json_result + # If i'm here, it's not JSON, it's not XML, let's scream + # and raise the last context in this block (the XML exception) + # The function hack is because Py2.7 messes up with exception + # context otherwise. + _LOGGER.critical("Wasn't XML not JSON, failing") + raise DeserializationError("XML is invalid") from err + elif content_type.startswith("text/"): + return data_as_str + raise DeserializationError("Cannot deserialize content-type: {}".format(content_type)) + + @classmethod + def deserialize_from_http_generics(cls, body_bytes: Optional[Union[AnyStr, IO]], headers: Mapping) -> Any: + """Deserialize from HTTP response. + + Use bytes and headers to NOT use any requests/aiohttp or whatever + specific implementation. + Headers will tested for "content-type" + + :param bytes body_bytes: The body of the response. + :param dict headers: The headers of the response. + :returns: The deserialized data. + :rtype: object + """ + # Try to use content-type from headers if available + content_type = None + if "content-type" in headers: + content_type = headers["content-type"].split(";")[0].strip().lower() + # Ouch, this server did not declare what it sent... + # Let's guess it's JSON... + # Also, since Autorest was considering that an empty body was a valid JSON, + # need that test as well.... + else: + content_type = "application/json" + + if body_bytes: + return cls.deserialize_from_text(body_bytes, content_type) + return None + + +_LOGGER = logging.getLogger(__name__) + +try: + _long_type = long # type: ignore +except NameError: + _long_type = int + +TZ_UTC = datetime.timezone.utc + +_FLATTEN = re.compile(r"(? None: + self.additional_properties: Optional[Dict[str, Any]] = {} + for k in kwargs: # pylint: disable=consider-using-dict-items + if k not in self._attribute_map: + _LOGGER.warning("%s is not a known attribute of class %s and will be ignored", k, self.__class__) + elif k in self._validation and self._validation[k].get("readonly", False): + _LOGGER.warning("Readonly attribute %s will be ignored in class %s", k, self.__class__) + else: + setattr(self, k, kwargs[k]) + + def __eq__(self, other: Any) -> bool: + """Compare objects by comparing all attributes. + + :param object other: The object to compare + :returns: True if objects are equal + :rtype: bool + """ + if isinstance(other, self.__class__): + return self.__dict__ == other.__dict__ + return False + + def __ne__(self, other: Any) -> bool: + """Compare objects by comparing all attributes. + + :param object other: The object to compare + :returns: True if objects are not equal + :rtype: bool + """ + return not self.__eq__(other) + + def __str__(self) -> str: + return str(self.__dict__) + + @classmethod + def enable_additional_properties_sending(cls) -> None: + cls._attribute_map["additional_properties"] = {"key": "", "type": "{object}"} + + @classmethod + def is_xml_model(cls) -> bool: + try: + cls._xml_map # type: ignore + except AttributeError: + return False + return True + + @classmethod + def _create_xml_node(cls): + """Create XML node. + + :returns: The XML node + :rtype: xml.etree.ElementTree.Element + """ + try: + xml_map = cls._xml_map # type: ignore + except AttributeError: + xml_map = {} + + return _create_xml_node(xml_map.get("name", cls.__name__), xml_map.get("prefix", None), xml_map.get("ns", None)) + + def serialize(self, keep_readonly: bool = False, **kwargs: Any) -> JSON: + """Return the JSON that would be sent to server from this model. + + This is an alias to `as_dict(full_restapi_key_transformer, keep_readonly=False)`. + + If you want XML serialization, you can pass the kwargs is_xml=True. + + :param bool keep_readonly: If you want to serialize the readonly attributes + :returns: A dict JSON compatible object + :rtype: dict + """ + serializer = Serializer(self._infer_class_models()) + return serializer._serialize( # type: ignore # pylint: disable=protected-access + self, keep_readonly=keep_readonly, **kwargs + ) + + def as_dict( + self, + keep_readonly: bool = True, + key_transformer: Callable[[str, Dict[str, Any], Any], Any] = attribute_transformer, + **kwargs: Any + ) -> JSON: + """Return a dict that can be serialized using json.dump. + + Advanced usage might optionally use a callback as parameter: + + .. code::python + + def my_key_transformer(key, attr_desc, value): + return key + + Key is the attribute name used in Python. Attr_desc + is a dict of metadata. Currently contains 'type' with the + msrest type and 'key' with the RestAPI encoded key. + Value is the current value in this object. + + The string returned will be used to serialize the key. + If the return type is a list, this is considered hierarchical + result dict. + + See the three examples in this file: + + - attribute_transformer + - full_restapi_key_transformer + - last_restapi_key_transformer + + If you want XML serialization, you can pass the kwargs is_xml=True. + + :param bool keep_readonly: If you want to serialize the readonly attributes + :param function key_transformer: A key transformer function. + :returns: A dict JSON compatible object + :rtype: dict + """ + serializer = Serializer(self._infer_class_models()) + return serializer._serialize( # type: ignore # pylint: disable=protected-access + self, key_transformer=key_transformer, keep_readonly=keep_readonly, **kwargs + ) + + @classmethod + def _infer_class_models(cls): + try: + str_models = cls.__module__.rsplit(".", 1)[0] + models = sys.modules[str_models] + client_models = {k: v for k, v in models.__dict__.items() if isinstance(v, type)} + if cls.__name__ not in client_models: + raise ValueError("Not Autorest generated code") + except Exception: # pylint: disable=broad-exception-caught + # Assume it's not Autorest generated (tests?). Add ourselves as dependencies. + client_models = {cls.__name__: cls} + return client_models + + @classmethod + def deserialize(cls, data: Any, content_type: Optional[str] = None) -> Self: + """Parse a str using the RestAPI syntax and return a model. + + :param str data: A str using RestAPI structure. JSON by default. + :param str content_type: JSON by default, set application/xml if XML. + :returns: An instance of this model + :raises DeserializationError: if something went wrong + :rtype: Self + """ + deserializer = Deserializer(cls._infer_class_models()) + return deserializer(cls.__name__, data, content_type=content_type) # type: ignore + + @classmethod + def from_dict( + cls, + data: Any, + key_extractors: Optional[Callable[[str, Dict[str, Any], Any], Any]] = None, + content_type: Optional[str] = None, + ) -> Self: + """Parse a dict using given key extractor return a model. + + By default consider key + extractors (rest_key_case_insensitive_extractor, attribute_key_case_insensitive_extractor + and last_rest_key_case_insensitive_extractor) + + :param dict data: A dict using RestAPI structure + :param function key_extractors: A key extractor function. + :param str content_type: JSON by default, set application/xml if XML. + :returns: An instance of this model + :raises DeserializationError: if something went wrong + :rtype: Self + """ + deserializer = Deserializer(cls._infer_class_models()) + deserializer.key_extractors = ( # type: ignore + [ # type: ignore + attribute_key_case_insensitive_extractor, + rest_key_case_insensitive_extractor, + last_rest_key_case_insensitive_extractor, + ] + if key_extractors is None + else key_extractors + ) + return deserializer(cls.__name__, data, content_type=content_type) # type: ignore + + @classmethod + def _flatten_subtype(cls, key, objects): + if "_subtype_map" not in cls.__dict__: + return {} + result = dict(cls._subtype_map[key]) + for valuetype in cls._subtype_map[key].values(): + result.update(objects[valuetype]._flatten_subtype(key, objects)) # pylint: disable=protected-access + return result + + @classmethod + def _classify(cls, response, objects): + """Check the class _subtype_map for any child classes. + We want to ignore any inherited _subtype_maps. + + :param dict response: The initial data + :param dict objects: The class objects + :returns: The class to be used + :rtype: class + """ + for subtype_key in cls.__dict__.get("_subtype_map", {}).keys(): + subtype_value = None + + if not isinstance(response, ET.Element): + rest_api_response_key = cls._get_rest_key_parts(subtype_key)[-1] + subtype_value = response.get(rest_api_response_key, None) or response.get(subtype_key, None) + else: + subtype_value = xml_key_extractor(subtype_key, cls._attribute_map[subtype_key], response) + if subtype_value: + # Try to match base class. Can be class name only + # (bug to fix in Autorest to support x-ms-discriminator-name) + if cls.__name__ == subtype_value: + return cls + flatten_mapping_type = cls._flatten_subtype(subtype_key, objects) + try: + return objects[flatten_mapping_type[subtype_value]] # type: ignore + except KeyError: + _LOGGER.warning( + "Subtype value %s has no mapping, use base class %s.", + subtype_value, + cls.__name__, + ) + break + else: + _LOGGER.warning("Discriminator %s is absent or null, use base class %s.", subtype_key, cls.__name__) + break + return cls + + @classmethod + def _get_rest_key_parts(cls, attr_key): + """Get the RestAPI key of this attr, split it and decode part + :param str attr_key: Attribute key must be in attribute_map. + :returns: A list of RestAPI part + :rtype: list + """ + rest_split_key = _FLATTEN.split(cls._attribute_map[attr_key]["key"]) + return [_decode_attribute_map_key(key_part) for key_part in rest_split_key] + + +def _decode_attribute_map_key(key): + """This decode a key in an _attribute_map to the actual key we want to look at + inside the received data. + + :param str key: A key string from the generated code + :returns: The decoded key + :rtype: str + """ + return key.replace("\\.", ".") + + +class Serializer: # pylint: disable=too-many-public-methods + """Request object model serializer.""" + + basic_types = {str: "str", int: "int", bool: "bool", float: "float"} + + _xml_basic_types_serializers = {"bool": lambda x: str(x).lower()} + days = {0: "Mon", 1: "Tue", 2: "Wed", 3: "Thu", 4: "Fri", 5: "Sat", 6: "Sun"} + months = { + 1: "Jan", + 2: "Feb", + 3: "Mar", + 4: "Apr", + 5: "May", + 6: "Jun", + 7: "Jul", + 8: "Aug", + 9: "Sep", + 10: "Oct", + 11: "Nov", + 12: "Dec", + } + validation = { + "min_length": lambda x, y: len(x) < y, + "max_length": lambda x, y: len(x) > y, + "minimum": lambda x, y: x < y, + "maximum": lambda x, y: x > y, + "minimum_ex": lambda x, y: x <= y, + "maximum_ex": lambda x, y: x >= y, + "min_items": lambda x, y: len(x) < y, + "max_items": lambda x, y: len(x) > y, + "pattern": lambda x, y: not re.match(y, x, re.UNICODE), + "unique": lambda x, y: len(x) != len(set(x)), + "multiple": lambda x, y: x % y != 0, + } + + def __init__(self, classes: Optional[Mapping[str, type]] = None) -> None: + self.serialize_type = { + "iso-8601": Serializer.serialize_iso, + "rfc-1123": Serializer.serialize_rfc, + "unix-time": Serializer.serialize_unix, + "duration": Serializer.serialize_duration, + "date": Serializer.serialize_date, + "time": Serializer.serialize_time, + "decimal": Serializer.serialize_decimal, + "long": Serializer.serialize_long, + "bytearray": Serializer.serialize_bytearray, + "base64": Serializer.serialize_base64, + "object": self.serialize_object, + "[]": self.serialize_iter, + "{}": self.serialize_dict, + } + self.dependencies: Dict[str, type] = dict(classes) if classes else {} + self.key_transformer = full_restapi_key_transformer + self.client_side_validation = True + + def _serialize( # pylint: disable=too-many-nested-blocks, too-many-branches, too-many-statements, too-many-locals + self, target_obj, data_type=None, **kwargs + ): + """Serialize data into a string according to type. + + :param object target_obj: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str, dict + :raises SerializationError: if serialization fails. + :returns: The serialized data. + """ + key_transformer = kwargs.get("key_transformer", self.key_transformer) + keep_readonly = kwargs.get("keep_readonly", False) + if target_obj is None: + return None + + attr_name = None + class_name = target_obj.__class__.__name__ + + if data_type: + return self.serialize_data(target_obj, data_type, **kwargs) + + if not hasattr(target_obj, "_attribute_map"): + data_type = type(target_obj).__name__ + if data_type in self.basic_types.values(): + return self.serialize_data(target_obj, data_type, **kwargs) + + # Force "is_xml" kwargs if we detect a XML model + try: + is_xml_model_serialization = kwargs["is_xml"] + except KeyError: + is_xml_model_serialization = kwargs.setdefault("is_xml", target_obj.is_xml_model()) + + serialized = {} + if is_xml_model_serialization: + serialized = target_obj._create_xml_node() # pylint: disable=protected-access + try: + attributes = target_obj._attribute_map # pylint: disable=protected-access + for attr, attr_desc in attributes.items(): + attr_name = attr + if not keep_readonly and target_obj._validation.get( # pylint: disable=protected-access + attr_name, {} + ).get("readonly", False): + continue + + if attr_name == "additional_properties" and attr_desc["key"] == "": + if target_obj.additional_properties is not None: + serialized.update(target_obj.additional_properties) + continue + try: + + orig_attr = getattr(target_obj, attr) + if is_xml_model_serialization: + pass # Don't provide "transformer" for XML for now. Keep "orig_attr" + else: # JSON + keys, orig_attr = key_transformer(attr, attr_desc.copy(), orig_attr) + keys = keys if isinstance(keys, list) else [keys] + + kwargs["serialization_ctxt"] = attr_desc + new_attr = self.serialize_data(orig_attr, attr_desc["type"], **kwargs) + + if is_xml_model_serialization: + xml_desc = attr_desc.get("xml", {}) + xml_name = xml_desc.get("name", attr_desc["key"]) + xml_prefix = xml_desc.get("prefix", None) + xml_ns = xml_desc.get("ns", None) + if xml_desc.get("attr", False): + if xml_ns: + ET.register_namespace(xml_prefix, xml_ns) + xml_name = "{{{}}}{}".format(xml_ns, xml_name) + serialized.set(xml_name, new_attr) # type: ignore + continue + if xml_desc.get("text", False): + serialized.text = new_attr # type: ignore + continue + if isinstance(new_attr, list): + serialized.extend(new_attr) # type: ignore + elif isinstance(new_attr, ET.Element): + # If the down XML has no XML/Name, + # we MUST replace the tag with the local tag. But keeping the namespaces. + if "name" not in getattr(orig_attr, "_xml_map", {}): + splitted_tag = new_attr.tag.split("}") + if len(splitted_tag) == 2: # Namespace + new_attr.tag = "}".join([splitted_tag[0], xml_name]) + else: + new_attr.tag = xml_name + serialized.append(new_attr) # type: ignore + else: # That's a basic type + # Integrate namespace if necessary + local_node = _create_xml_node(xml_name, xml_prefix, xml_ns) + local_node.text = str(new_attr) + serialized.append(local_node) # type: ignore + else: # JSON + for k in reversed(keys): # type: ignore + new_attr = {k: new_attr} + + _new_attr = new_attr + _serialized = serialized + for k in keys: # type: ignore + if k not in _serialized: + _serialized.update(_new_attr) # type: ignore + _new_attr = _new_attr[k] # type: ignore + _serialized = _serialized[k] + except ValueError as err: + if isinstance(err, SerializationError): + raise + + except (AttributeError, KeyError, TypeError) as err: + msg = "Attribute {} in object {} cannot be serialized.\n{}".format(attr_name, class_name, str(target_obj)) + raise SerializationError(msg) from err + return serialized + + def body(self, data, data_type, **kwargs): + """Serialize data intended for a request body. + + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: dict + :raises SerializationError: if serialization fails. + :raises ValueError: if data is None + :returns: The serialized request body + """ + + # Just in case this is a dict + internal_data_type_str = data_type.strip("[]{}") + internal_data_type = self.dependencies.get(internal_data_type_str, None) + try: + is_xml_model_serialization = kwargs["is_xml"] + except KeyError: + if internal_data_type and issubclass(internal_data_type, Model): + is_xml_model_serialization = kwargs.setdefault("is_xml", internal_data_type.is_xml_model()) + else: + is_xml_model_serialization = False + if internal_data_type and not isinstance(internal_data_type, Enum): + try: + deserializer = Deserializer(self.dependencies) + # Since it's on serialization, it's almost sure that format is not JSON REST + # We're not able to deal with additional properties for now. + deserializer.additional_properties_detection = False + if is_xml_model_serialization: + deserializer.key_extractors = [ # type: ignore + attribute_key_case_insensitive_extractor, + ] + else: + deserializer.key_extractors = [ + rest_key_case_insensitive_extractor, + attribute_key_case_insensitive_extractor, + last_rest_key_case_insensitive_extractor, + ] + data = deserializer._deserialize(data_type, data) # pylint: disable=protected-access + except DeserializationError as err: + raise SerializationError("Unable to build a model: " + str(err)) from err + + return self._serialize(data, data_type, **kwargs) + + def url(self, name, data, data_type, **kwargs): + """Serialize data intended for a URL path. + + :param str name: The name of the URL path parameter. + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str + :returns: The serialized URL path + :raises TypeError: if serialization fails. + :raises ValueError: if data is None + """ + try: + output = self.serialize_data(data, data_type, **kwargs) + if data_type == "bool": + output = json.dumps(output) + + if kwargs.get("skip_quote") is True: + output = str(output) + output = output.replace("{", quote("{")).replace("}", quote("}")) + else: + output = quote(str(output), safe="") + except SerializationError as exc: + raise TypeError("{} must be type {}.".format(name, data_type)) from exc + return output + + def query(self, name, data, data_type, **kwargs): + """Serialize data intended for a URL query. + + :param str name: The name of the query parameter. + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str, list + :raises TypeError: if serialization fails. + :raises ValueError: if data is None + :returns: The serialized query parameter + """ + try: + # Treat the list aside, since we don't want to encode the div separator + if data_type.startswith("["): + internal_data_type = data_type[1:-1] + do_quote = not kwargs.get("skip_quote", False) + return self.serialize_iter(data, internal_data_type, do_quote=do_quote, **kwargs) + + # Not a list, regular serialization + output = self.serialize_data(data, data_type, **kwargs) + if data_type == "bool": + output = json.dumps(output) + if kwargs.get("skip_quote") is True: + output = str(output) + else: + output = quote(str(output), safe="") + except SerializationError as exc: + raise TypeError("{} must be type {}.".format(name, data_type)) from exc + return str(output) + + def header(self, name, data, data_type, **kwargs): + """Serialize data intended for a request header. + + :param str name: The name of the header. + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str + :raises TypeError: if serialization fails. + :raises ValueError: if data is None + :returns: The serialized header + """ + try: + if data_type in ["[str]"]: + data = ["" if d is None else d for d in data] + + output = self.serialize_data(data, data_type, **kwargs) + if data_type == "bool": + output = json.dumps(output) + except SerializationError as exc: + raise TypeError("{} must be type {}.".format(name, data_type)) from exc + return str(output) + + def serialize_data(self, data, data_type, **kwargs): + """Serialize generic data according to supplied data type. + + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :raises AttributeError: if required data is None. + :raises ValueError: if data is None + :raises SerializationError: if serialization fails. + :returns: The serialized data. + :rtype: str, int, float, bool, dict, list + """ + if data is None: + raise ValueError("No value for given attribute") + + try: + if data is CoreNull: + return None + if data_type in self.basic_types.values(): + return self.serialize_basic(data, data_type, **kwargs) + + if data_type in self.serialize_type: + return self.serialize_type[data_type](data, **kwargs) + + # If dependencies is empty, try with current data class + # It has to be a subclass of Enum anyway + enum_type = self.dependencies.get(data_type, data.__class__) + if issubclass(enum_type, Enum): + return Serializer.serialize_enum(data, enum_obj=enum_type) + + iter_type = data_type[0] + data_type[-1] + if iter_type in self.serialize_type: + return self.serialize_type[iter_type](data, data_type[1:-1], **kwargs) + + except (ValueError, TypeError) as err: + msg = "Unable to serialize value: {!r} as type: {!r}." + raise SerializationError(msg.format(data, data_type)) from err + return self._serialize(data, **kwargs) + + @classmethod + def _get_custom_serializers(cls, data_type, **kwargs): # pylint: disable=inconsistent-return-statements + custom_serializer = kwargs.get("basic_types_serializers", {}).get(data_type) + if custom_serializer: + return custom_serializer + if kwargs.get("is_xml", False): + return cls._xml_basic_types_serializers.get(data_type) + + @classmethod + def serialize_basic(cls, data, data_type, **kwargs): + """Serialize basic builting data type. + Serializes objects to str, int, float or bool. + + Possible kwargs: + - basic_types_serializers dict[str, callable] : If set, use the callable as serializer + - is_xml bool : If set, use xml_basic_types_serializers + + :param obj data: Object to be serialized. + :param str data_type: Type of object in the iterable. + :rtype: str, int, float, bool + :return: serialized object + """ + custom_serializer = cls._get_custom_serializers(data_type, **kwargs) + if custom_serializer: + return custom_serializer(data) + if data_type == "str": + return cls.serialize_unicode(data) + return eval(data_type)(data) # nosec # pylint: disable=eval-used + + @classmethod + def serialize_unicode(cls, data): + """Special handling for serializing unicode strings in Py2. + Encode to UTF-8 if unicode, otherwise handle as a str. + + :param str data: Object to be serialized. + :rtype: str + :return: serialized object + """ + try: # If I received an enum, return its value + return data.value + except AttributeError: + pass + + try: + if isinstance(data, unicode): # type: ignore + # Don't change it, JSON and XML ElementTree are totally able + # to serialize correctly u'' strings + return data + except NameError: + return str(data) + return str(data) + + def serialize_iter(self, data, iter_type, div=None, **kwargs): + """Serialize iterable. + + Supported kwargs: + - serialization_ctxt dict : The current entry of _attribute_map, or same format. + serialization_ctxt['type'] should be same as data_type. + - is_xml bool : If set, serialize as XML + + :param list data: Object to be serialized. + :param str iter_type: Type of object in the iterable. + :param str div: If set, this str will be used to combine the elements + in the iterable into a combined string. Default is 'None'. + Defaults to False. + :rtype: list, str + :return: serialized iterable + """ + if isinstance(data, str): + raise SerializationError("Refuse str type as a valid iter type.") + + serialization_ctxt = kwargs.get("serialization_ctxt", {}) + is_xml = kwargs.get("is_xml", False) + + serialized = [] + for d in data: + try: + serialized.append(self.serialize_data(d, iter_type, **kwargs)) + except ValueError as err: + if isinstance(err, SerializationError): + raise + serialized.append(None) + + if kwargs.get("do_quote", False): + serialized = ["" if s is None else quote(str(s), safe="") for s in serialized] + + if div: + serialized = ["" if s is None else str(s) for s in serialized] + serialized = div.join(serialized) + + if "xml" in serialization_ctxt or is_xml: + # XML serialization is more complicated + xml_desc = serialization_ctxt.get("xml", {}) + xml_name = xml_desc.get("name") + if not xml_name: + xml_name = serialization_ctxt["key"] + + # Create a wrap node if necessary (use the fact that Element and list have "append") + is_wrapped = xml_desc.get("wrapped", False) + node_name = xml_desc.get("itemsName", xml_name) + if is_wrapped: + final_result = _create_xml_node(xml_name, xml_desc.get("prefix", None), xml_desc.get("ns", None)) + else: + final_result = [] + # All list elements to "local_node" + for el in serialized: + if isinstance(el, ET.Element): + el_node = el + else: + el_node = _create_xml_node(node_name, xml_desc.get("prefix", None), xml_desc.get("ns", None)) + if el is not None: # Otherwise it writes "None" :-p + el_node.text = str(el) + final_result.append(el_node) + return final_result + return serialized + + def serialize_dict(self, attr, dict_type, **kwargs): + """Serialize a dictionary of objects. + + :param dict attr: Object to be serialized. + :param str dict_type: Type of object in the dictionary. + :rtype: dict + :return: serialized dictionary + """ + serialization_ctxt = kwargs.get("serialization_ctxt", {}) + serialized = {} + for key, value in attr.items(): + try: + serialized[self.serialize_unicode(key)] = self.serialize_data(value, dict_type, **kwargs) + except ValueError as err: + if isinstance(err, SerializationError): + raise + serialized[self.serialize_unicode(key)] = None + + if "xml" in serialization_ctxt: + # XML serialization is more complicated + xml_desc = serialization_ctxt["xml"] + xml_name = xml_desc["name"] + + final_result = _create_xml_node(xml_name, xml_desc.get("prefix", None), xml_desc.get("ns", None)) + for key, value in serialized.items(): + ET.SubElement(final_result, key).text = value + return final_result + + return serialized + + def serialize_object(self, attr, **kwargs): # pylint: disable=too-many-return-statements + """Serialize a generic object. + This will be handled as a dictionary. If object passed in is not + a basic type (str, int, float, dict, list) it will simply be + cast to str. + + :param dict attr: Object to be serialized. + :rtype: dict or str + :return: serialized object + """ + if attr is None: + return None + if isinstance(attr, ET.Element): + return attr + obj_type = type(attr) + if obj_type in self.basic_types: + return self.serialize_basic(attr, self.basic_types[obj_type], **kwargs) + if obj_type is _long_type: + return self.serialize_long(attr) + if obj_type is str: + return self.serialize_unicode(attr) + if obj_type is datetime.datetime: + return self.serialize_iso(attr) + if obj_type is datetime.date: + return self.serialize_date(attr) + if obj_type is datetime.time: + return self.serialize_time(attr) + if obj_type is datetime.timedelta: + return self.serialize_duration(attr) + if obj_type is decimal.Decimal: + return self.serialize_decimal(attr) + + # If it's a model or I know this dependency, serialize as a Model + if obj_type in self.dependencies.values() or isinstance(attr, Model): + return self._serialize(attr) + + if obj_type == dict: + serialized = {} + for key, value in attr.items(): + try: + serialized[self.serialize_unicode(key)] = self.serialize_object(value, **kwargs) + except ValueError: + serialized[self.serialize_unicode(key)] = None + return serialized + + if obj_type == list: + serialized = [] + for obj in attr: + try: + serialized.append(self.serialize_object(obj, **kwargs)) + except ValueError: + pass + return serialized + return str(attr) + + @staticmethod + def serialize_enum(attr, enum_obj=None): + try: + result = attr.value + except AttributeError: + result = attr + try: + enum_obj(result) # type: ignore + return result + except ValueError as exc: + for enum_value in enum_obj: # type: ignore + if enum_value.value.lower() == str(attr).lower(): + return enum_value.value + error = "{!r} is not valid value for enum {!r}" + raise SerializationError(error.format(attr, enum_obj)) from exc + + @staticmethod + def serialize_bytearray(attr, **kwargs): # pylint: disable=unused-argument + """Serialize bytearray into base-64 string. + + :param str attr: Object to be serialized. + :rtype: str + :return: serialized base64 + """ + return b64encode(attr).decode() + + @staticmethod + def serialize_base64(attr, **kwargs): # pylint: disable=unused-argument + """Serialize str into base-64 string. + + :param str attr: Object to be serialized. + :rtype: str + :return: serialized base64 + """ + encoded = b64encode(attr).decode("ascii") + return encoded.strip("=").replace("+", "-").replace("/", "_") + + @staticmethod + def serialize_decimal(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Decimal object to float. + + :param decimal attr: Object to be serialized. + :rtype: float + :return: serialized decimal + """ + return float(attr) + + @staticmethod + def serialize_long(attr, **kwargs): # pylint: disable=unused-argument + """Serialize long (Py2) or int (Py3). + + :param int attr: Object to be serialized. + :rtype: int/long + :return: serialized long + """ + return _long_type(attr) + + @staticmethod + def serialize_date(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Date object into ISO-8601 formatted string. + + :param Date attr: Object to be serialized. + :rtype: str + :return: serialized date + """ + if isinstance(attr, str): + attr = isodate.parse_date(attr) + t = "{:04}-{:02}-{:02}".format(attr.year, attr.month, attr.day) + return t + + @staticmethod + def serialize_time(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Time object into ISO-8601 formatted string. + + :param datetime.time attr: Object to be serialized. + :rtype: str + :return: serialized time + """ + if isinstance(attr, str): + attr = isodate.parse_time(attr) + t = "{:02}:{:02}:{:02}".format(attr.hour, attr.minute, attr.second) + if attr.microsecond: + t += ".{:02}".format(attr.microsecond) + return t + + @staticmethod + def serialize_duration(attr, **kwargs): # pylint: disable=unused-argument + """Serialize TimeDelta object into ISO-8601 formatted string. + + :param TimeDelta attr: Object to be serialized. + :rtype: str + :return: serialized duration + """ + if isinstance(attr, str): + attr = isodate.parse_duration(attr) + return isodate.duration_isoformat(attr) + + @staticmethod + def serialize_rfc(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Datetime object into RFC-1123 formatted string. + + :param Datetime attr: Object to be serialized. + :rtype: str + :raises TypeError: if format invalid. + :return: serialized rfc + """ + try: + if not attr.tzinfo: + _LOGGER.warning("Datetime with no tzinfo will be considered UTC.") + utc = attr.utctimetuple() + except AttributeError as exc: + raise TypeError("RFC1123 object must be valid Datetime object.") from exc + + return "{}, {:02} {} {:04} {:02}:{:02}:{:02} GMT".format( + Serializer.days[utc.tm_wday], + utc.tm_mday, + Serializer.months[utc.tm_mon], + utc.tm_year, + utc.tm_hour, + utc.tm_min, + utc.tm_sec, + ) + + @staticmethod + def serialize_iso(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Datetime object into ISO-8601 formatted string. + + :param Datetime attr: Object to be serialized. + :rtype: str + :raises SerializationError: if format invalid. + :return: serialized iso + """ + if isinstance(attr, str): + attr = isodate.parse_datetime(attr) + try: + if not attr.tzinfo: + _LOGGER.warning("Datetime with no tzinfo will be considered UTC.") + utc = attr.utctimetuple() + if utc.tm_year > 9999 or utc.tm_year < 1: + raise OverflowError("Hit max or min date") + + microseconds = str(attr.microsecond).rjust(6, "0").rstrip("0").ljust(3, "0") + if microseconds: + microseconds = "." + microseconds + date = "{:04}-{:02}-{:02}T{:02}:{:02}:{:02}".format( + utc.tm_year, utc.tm_mon, utc.tm_mday, utc.tm_hour, utc.tm_min, utc.tm_sec + ) + return date + microseconds + "Z" + except (ValueError, OverflowError) as err: + msg = "Unable to serialize datetime object." + raise SerializationError(msg) from err + except AttributeError as err: + msg = "ISO-8601 object must be valid Datetime object." + raise TypeError(msg) from err + + @staticmethod + def serialize_unix(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Datetime object into IntTime format. + This is represented as seconds. + + :param Datetime attr: Object to be serialized. + :rtype: int + :raises SerializationError: if format invalid + :return: serialied unix + """ + if isinstance(attr, int): + return attr + try: + if not attr.tzinfo: + _LOGGER.warning("Datetime with no tzinfo will be considered UTC.") + return int(calendar.timegm(attr.utctimetuple())) + except AttributeError as exc: + raise TypeError("Unix time object must be valid Datetime object.") from exc + + +def rest_key_extractor(attr, attr_desc, data): # pylint: disable=unused-argument + key = attr_desc["key"] + working_data = data + + while "." in key: + # Need the cast, as for some reasons "split" is typed as list[str | Any] + dict_keys = cast(List[str], _FLATTEN.split(key)) + if len(dict_keys) == 1: + key = _decode_attribute_map_key(dict_keys[0]) + break + working_key = _decode_attribute_map_key(dict_keys[0]) + working_data = working_data.get(working_key, data) + if working_data is None: + # If at any point while following flatten JSON path see None, it means + # that all properties under are None as well + return None + key = ".".join(dict_keys[1:]) + + return working_data.get(key) + + +def rest_key_case_insensitive_extractor( # pylint: disable=unused-argument, inconsistent-return-statements + attr, attr_desc, data +): + key = attr_desc["key"] + working_data = data + + while "." in key: + dict_keys = _FLATTEN.split(key) + if len(dict_keys) == 1: + key = _decode_attribute_map_key(dict_keys[0]) + break + working_key = _decode_attribute_map_key(dict_keys[0]) + working_data = attribute_key_case_insensitive_extractor(working_key, None, working_data) + if working_data is None: + # If at any point while following flatten JSON path see None, it means + # that all properties under are None as well + return None + key = ".".join(dict_keys[1:]) + + if working_data: + return attribute_key_case_insensitive_extractor(key, None, working_data) + + +def last_rest_key_extractor(attr, attr_desc, data): # pylint: disable=unused-argument + """Extract the attribute in "data" based on the last part of the JSON path key. + + :param str attr: The attribute to extract + :param dict attr_desc: The attribute description + :param dict data: The data to extract from + :rtype: object + :returns: The extracted attribute + """ + key = attr_desc["key"] + dict_keys = _FLATTEN.split(key) + return attribute_key_extractor(dict_keys[-1], None, data) + + +def last_rest_key_case_insensitive_extractor(attr, attr_desc, data): # pylint: disable=unused-argument + """Extract the attribute in "data" based on the last part of the JSON path key. + + This is the case insensitive version of "last_rest_key_extractor" + :param str attr: The attribute to extract + :param dict attr_desc: The attribute description + :param dict data: The data to extract from + :rtype: object + :returns: The extracted attribute + """ + key = attr_desc["key"] + dict_keys = _FLATTEN.split(key) + return attribute_key_case_insensitive_extractor(dict_keys[-1], None, data) + + +def attribute_key_extractor(attr, _, data): + return data.get(attr) + + +def attribute_key_case_insensitive_extractor(attr, _, data): + found_key = None + lower_attr = attr.lower() + for key in data: + if lower_attr == key.lower(): + found_key = key + break + + return data.get(found_key) + + +def _extract_name_from_internal_type(internal_type): + """Given an internal type XML description, extract correct XML name with namespace. + + :param dict internal_type: An model type + :rtype: tuple + :returns: A tuple XML name + namespace dict + """ + internal_type_xml_map = getattr(internal_type, "_xml_map", {}) + xml_name = internal_type_xml_map.get("name", internal_type.__name__) + xml_ns = internal_type_xml_map.get("ns", None) + if xml_ns: + xml_name = "{{{}}}{}".format(xml_ns, xml_name) + return xml_name + + +def xml_key_extractor(attr, attr_desc, data): # pylint: disable=unused-argument,too-many-return-statements + if isinstance(data, dict): + return None + + # Test if this model is XML ready first + if not isinstance(data, ET.Element): + return None + + xml_desc = attr_desc.get("xml", {}) + xml_name = xml_desc.get("name", attr_desc["key"]) + + # Look for a children + is_iter_type = attr_desc["type"].startswith("[") + is_wrapped = xml_desc.get("wrapped", False) + internal_type = attr_desc.get("internalType", None) + internal_type_xml_map = getattr(internal_type, "_xml_map", {}) + + # Integrate namespace if necessary + xml_ns = xml_desc.get("ns", internal_type_xml_map.get("ns", None)) + if xml_ns: + xml_name = "{{{}}}{}".format(xml_ns, xml_name) + + # If it's an attribute, that's simple + if xml_desc.get("attr", False): + return data.get(xml_name) + + # If it's x-ms-text, that's simple too + if xml_desc.get("text", False): + return data.text + + # Scenario where I take the local name: + # - Wrapped node + # - Internal type is an enum (considered basic types) + # - Internal type has no XML/Name node + if is_wrapped or (internal_type and (issubclass(internal_type, Enum) or "name" not in internal_type_xml_map)): + children = data.findall(xml_name) + # If internal type has a local name and it's not a list, I use that name + elif not is_iter_type and internal_type and "name" in internal_type_xml_map: + xml_name = _extract_name_from_internal_type(internal_type) + children = data.findall(xml_name) + # That's an array + else: + if internal_type: # Complex type, ignore itemsName and use the complex type name + items_name = _extract_name_from_internal_type(internal_type) + else: + items_name = xml_desc.get("itemsName", xml_name) + children = data.findall(items_name) + + if len(children) == 0: + if is_iter_type: + if is_wrapped: + return None # is_wrapped no node, we want None + return [] # not wrapped, assume empty list + return None # Assume it's not there, maybe an optional node. + + # If is_iter_type and not wrapped, return all found children + if is_iter_type: + if not is_wrapped: + return children + # Iter and wrapped, should have found one node only (the wrap one) + if len(children) != 1: + raise DeserializationError( + "Tried to deserialize an array not wrapped, and found several nodes '{}'. Maybe you should declare this array as wrapped?".format( + xml_name + ) + ) + return list(children[0]) # Might be empty list and that's ok. + + # Here it's not a itertype, we should have found one element only or empty + if len(children) > 1: + raise DeserializationError("Find several XML '{}' where it was not expected".format(xml_name)) + return children[0] + + +class Deserializer: + """Response object model deserializer. + + :param dict classes: Class type dictionary for deserializing complex types. + :ivar list key_extractors: Ordered list of extractors to be used by this deserializer. + """ + + basic_types = {str: "str", int: "int", bool: "bool", float: "float"} + + valid_date = re.compile(r"\d{4}[-]\d{2}[-]\d{2}T\d{2}:\d{2}:\d{2}\.?\d*Z?[-+]?[\d{2}]?:?[\d{2}]?") + + def __init__(self, classes: Optional[Mapping[str, type]] = None) -> None: + self.deserialize_type = { + "iso-8601": Deserializer.deserialize_iso, + "rfc-1123": Deserializer.deserialize_rfc, + "unix-time": Deserializer.deserialize_unix, + "duration": Deserializer.deserialize_duration, + "date": Deserializer.deserialize_date, + "time": Deserializer.deserialize_time, + "decimal": Deserializer.deserialize_decimal, + "long": Deserializer.deserialize_long, + "bytearray": Deserializer.deserialize_bytearray, + "base64": Deserializer.deserialize_base64, + "object": self.deserialize_object, + "[]": self.deserialize_iter, + "{}": self.deserialize_dict, + } + self.deserialize_expected_types = { + "duration": (isodate.Duration, datetime.timedelta), + "iso-8601": (datetime.datetime), + } + self.dependencies: Dict[str, type] = dict(classes) if classes else {} + self.key_extractors = [rest_key_extractor, xml_key_extractor] + # Additional properties only works if the "rest_key_extractor" is used to + # extract the keys. Making it to work whatever the key extractor is too much + # complicated, with no real scenario for now. + # So adding a flag to disable additional properties detection. This flag should be + # used if your expect the deserialization to NOT come from a JSON REST syntax. + # Otherwise, result are unexpected + self.additional_properties_detection = True + + def __call__(self, target_obj, response_data, content_type=None): + """Call the deserializer to process a REST response. + + :param str target_obj: Target data type to deserialize to. + :param requests.Response response_data: REST response object. + :param str content_type: Swagger "produces" if available. + :raises DeserializationError: if deserialization fails. + :return: Deserialized object. + :rtype: object + """ + data = self._unpack_content(response_data, content_type) + return self._deserialize(target_obj, data) + + def _deserialize(self, target_obj, data): # pylint: disable=inconsistent-return-statements + """Call the deserializer on a model. + + Data needs to be already deserialized as JSON or XML ElementTree + + :param str target_obj: Target data type to deserialize to. + :param object data: Object to deserialize. + :raises DeserializationError: if deserialization fails. + :return: Deserialized object. + :rtype: object + """ + # This is already a model, go recursive just in case + if hasattr(data, "_attribute_map"): + constants = [name for name, config in getattr(data, "_validation", {}).items() if config.get("constant")] + try: + for attr, mapconfig in data._attribute_map.items(): # pylint: disable=protected-access + if attr in constants: + continue + value = getattr(data, attr) + if value is None: + continue + local_type = mapconfig["type"] + internal_data_type = local_type.strip("[]{}") + if internal_data_type not in self.dependencies or isinstance(internal_data_type, Enum): + continue + setattr(data, attr, self._deserialize(local_type, value)) + return data + except AttributeError: + return + + response, class_name = self._classify_target(target_obj, data) + + if isinstance(response, str): + return self.deserialize_data(data, response) + if isinstance(response, type) and issubclass(response, Enum): + return self.deserialize_enum(data, response) + + if data is None or data is CoreNull: + return data + try: + attributes = response._attribute_map # type: ignore # pylint: disable=protected-access + d_attrs = {} + for attr, attr_desc in attributes.items(): + # Check empty string. If it's not empty, someone has a real "additionalProperties"... + if attr == "additional_properties" and attr_desc["key"] == "": + continue + raw_value = None + # Enhance attr_desc with some dynamic data + attr_desc = attr_desc.copy() # Do a copy, do not change the real one + internal_data_type = attr_desc["type"].strip("[]{}") + if internal_data_type in self.dependencies: + attr_desc["internalType"] = self.dependencies[internal_data_type] + + for key_extractor in self.key_extractors: + found_value = key_extractor(attr, attr_desc, data) + if found_value is not None: + if raw_value is not None and raw_value != found_value: + msg = ( + "Ignoring extracted value '%s' from %s for key '%s'" + " (duplicate extraction, follow extractors order)" + ) + _LOGGER.warning(msg, found_value, key_extractor, attr) + continue + raw_value = found_value + + value = self.deserialize_data(raw_value, attr_desc["type"]) + d_attrs[attr] = value + except (AttributeError, TypeError, KeyError) as err: + msg = "Unable to deserialize to object: " + class_name # type: ignore + raise DeserializationError(msg) from err + additional_properties = self._build_additional_properties(attributes, data) + return self._instantiate_model(response, d_attrs, additional_properties) + + def _build_additional_properties(self, attribute_map, data): + if not self.additional_properties_detection: + return None + if "additional_properties" in attribute_map and attribute_map.get("additional_properties", {}).get("key") != "": + # Check empty string. If it's not empty, someone has a real "additionalProperties" + return None + if isinstance(data, ET.Element): + data = {el.tag: el.text for el in data} + + known_keys = { + _decode_attribute_map_key(_FLATTEN.split(desc["key"])[0]) + for desc in attribute_map.values() + if desc["key"] != "" + } + present_keys = set(data.keys()) + missing_keys = present_keys - known_keys + return {key: data[key] for key in missing_keys} + + def _classify_target(self, target, data): + """Check to see whether the deserialization target object can + be classified into a subclass. + Once classification has been determined, initialize object. + + :param str target: The target object type to deserialize to. + :param str/dict data: The response data to deserialize. + :return: The classified target object and its class name. + :rtype: tuple + """ + if target is None: + return None, None + + if isinstance(target, str): + try: + target = self.dependencies[target] + except KeyError: + return target, target + + try: + target = target._classify(data, self.dependencies) # type: ignore # pylint: disable=protected-access + except AttributeError: + pass # Target is not a Model, no classify + return target, target.__class__.__name__ # type: ignore + + def failsafe_deserialize(self, target_obj, data, content_type=None): + """Ignores any errors encountered in deserialization, + and falls back to not deserializing the object. Recommended + for use in error deserialization, as we want to return the + HttpResponseError to users, and not have them deal with + a deserialization error. + + :param str target_obj: The target object type to deserialize to. + :param str/dict data: The response data to deserialize. + :param str content_type: Swagger "produces" if available. + :return: Deserialized object. + :rtype: object + """ + try: + return self(target_obj, data, content_type=content_type) + except: # pylint: disable=bare-except + _LOGGER.debug( + "Ran into a deserialization error. Ignoring since this is failsafe deserialization", exc_info=True + ) + return None + + @staticmethod + def _unpack_content(raw_data, content_type=None): + """Extract the correct structure for deserialization. + + If raw_data is a PipelineResponse, try to extract the result of RawDeserializer. + if we can't, raise. Your Pipeline should have a RawDeserializer. + + If not a pipeline response and raw_data is bytes or string, use content-type + to decode it. If no content-type, try JSON. + + If raw_data is something else, bypass all logic and return it directly. + + :param obj raw_data: Data to be processed. + :param str content_type: How to parse if raw_data is a string/bytes. + :raises JSONDecodeError: If JSON is requested and parsing is impossible. + :raises UnicodeDecodeError: If bytes is not UTF8 + :rtype: object + :return: Unpacked content. + """ + # Assume this is enough to detect a Pipeline Response without importing it + context = getattr(raw_data, "context", {}) + if context: + if RawDeserializer.CONTEXT_NAME in context: + return context[RawDeserializer.CONTEXT_NAME] + raise ValueError("This pipeline didn't have the RawDeserializer policy; can't deserialize") + + # Assume this is enough to recognize universal_http.ClientResponse without importing it + if hasattr(raw_data, "body"): + return RawDeserializer.deserialize_from_http_generics(raw_data.text(), raw_data.headers) + + # Assume this enough to recognize requests.Response without importing it. + if hasattr(raw_data, "_content_consumed"): + return RawDeserializer.deserialize_from_http_generics(raw_data.text, raw_data.headers) + + if isinstance(raw_data, (str, bytes)) or hasattr(raw_data, "read"): + return RawDeserializer.deserialize_from_text(raw_data, content_type) # type: ignore + return raw_data + + def _instantiate_model(self, response, attrs, additional_properties=None): + """Instantiate a response model passing in deserialized args. + + :param Response response: The response model class. + :param dict attrs: The deserialized response attributes. + :param dict additional_properties: Additional properties to be set. + :rtype: Response + :return: The instantiated response model. + """ + if callable(response): + subtype = getattr(response, "_subtype_map", {}) + try: + readonly = [ + k + for k, v in response._validation.items() # pylint: disable=protected-access # type: ignore + if v.get("readonly") + ] + const = [ + k + for k, v in response._validation.items() # pylint: disable=protected-access # type: ignore + if v.get("constant") + ] + kwargs = {k: v for k, v in attrs.items() if k not in subtype and k not in readonly + const} + response_obj = response(**kwargs) + for attr in readonly: + setattr(response_obj, attr, attrs.get(attr)) + if additional_properties: + response_obj.additional_properties = additional_properties # type: ignore + return response_obj + except TypeError as err: + msg = "Unable to deserialize {} into model {}. ".format(kwargs, response) # type: ignore + raise DeserializationError(msg + str(err)) from err + else: + try: + for attr, value in attrs.items(): + setattr(response, attr, value) + return response + except Exception as exp: + msg = "Unable to populate response model. " + msg += "Type: {}, Error: {}".format(type(response), exp) + raise DeserializationError(msg) from exp + + def deserialize_data(self, data, data_type): # pylint: disable=too-many-return-statements + """Process data for deserialization according to data type. + + :param str data: The response string to be deserialized. + :param str data_type: The type to deserialize to. + :raises DeserializationError: if deserialization fails. + :return: Deserialized object. + :rtype: object + """ + if data is None: + return data + + try: + if not data_type: + return data + if data_type in self.basic_types.values(): + return self.deserialize_basic(data, data_type) + if data_type in self.deserialize_type: + if isinstance(data, self.deserialize_expected_types.get(data_type, tuple())): + return data + + is_a_text_parsing_type = lambda x: x not in [ # pylint: disable=unnecessary-lambda-assignment + "object", + "[]", + r"{}", + ] + if isinstance(data, ET.Element) and is_a_text_parsing_type(data_type) and not data.text: + return None + data_val = self.deserialize_type[data_type](data) + return data_val + + iter_type = data_type[0] + data_type[-1] + if iter_type in self.deserialize_type: + return self.deserialize_type[iter_type](data, data_type[1:-1]) + + obj_type = self.dependencies[data_type] + if issubclass(obj_type, Enum): + if isinstance(data, ET.Element): + data = data.text + return self.deserialize_enum(data, obj_type) + + except (ValueError, TypeError, AttributeError) as err: + msg = "Unable to deserialize response data." + msg += " Data: {}, {}".format(data, data_type) + raise DeserializationError(msg) from err + return self._deserialize(obj_type, data) + + def deserialize_iter(self, attr, iter_type): + """Deserialize an iterable. + + :param list attr: Iterable to be deserialized. + :param str iter_type: The type of object in the iterable. + :return: Deserialized iterable. + :rtype: list + """ + if attr is None: + return None + if isinstance(attr, ET.Element): # If I receive an element here, get the children + attr = list(attr) + if not isinstance(attr, (list, set)): + raise DeserializationError("Cannot deserialize as [{}] an object of type {}".format(iter_type, type(attr))) + return [self.deserialize_data(a, iter_type) for a in attr] + + def deserialize_dict(self, attr, dict_type): + """Deserialize a dictionary. + + :param dict/list attr: Dictionary to be deserialized. Also accepts + a list of key, value pairs. + :param str dict_type: The object type of the items in the dictionary. + :return: Deserialized dictionary. + :rtype: dict + """ + if isinstance(attr, list): + return {x["key"]: self.deserialize_data(x["value"], dict_type) for x in attr} + + if isinstance(attr, ET.Element): + # Transform value into {"Key": "value"} + attr = {el.tag: el.text for el in attr} + return {k: self.deserialize_data(v, dict_type) for k, v in attr.items()} + + def deserialize_object(self, attr, **kwargs): # pylint: disable=too-many-return-statements + """Deserialize a generic object. + This will be handled as a dictionary. + + :param dict attr: Dictionary to be deserialized. + :return: Deserialized object. + :rtype: dict + :raises TypeError: if non-builtin datatype encountered. + """ + if attr is None: + return None + if isinstance(attr, ET.Element): + # Do no recurse on XML, just return the tree as-is + return attr + if isinstance(attr, str): + return self.deserialize_basic(attr, "str") + obj_type = type(attr) + if obj_type in self.basic_types: + return self.deserialize_basic(attr, self.basic_types[obj_type]) + if obj_type is _long_type: + return self.deserialize_long(attr) + + if obj_type == dict: + deserialized = {} + for key, value in attr.items(): + try: + deserialized[key] = self.deserialize_object(value, **kwargs) + except ValueError: + deserialized[key] = None + return deserialized + + if obj_type == list: + deserialized = [] + for obj in attr: + try: + deserialized.append(self.deserialize_object(obj, **kwargs)) + except ValueError: + pass + return deserialized + + error = "Cannot deserialize generic object with type: " + raise TypeError(error + str(obj_type)) + + def deserialize_basic(self, attr, data_type): # pylint: disable=too-many-return-statements + """Deserialize basic builtin data type from string. + Will attempt to convert to str, int, float and bool. + This function will also accept '1', '0', 'true' and 'false' as + valid bool values. + + :param str attr: response string to be deserialized. + :param str data_type: deserialization data type. + :return: Deserialized basic type. + :rtype: str, int, float or bool + :raises TypeError: if string format is not valid. + """ + # If we're here, data is supposed to be a basic type. + # If it's still an XML node, take the text + if isinstance(attr, ET.Element): + attr = attr.text + if not attr: + if data_type == "str": + # None or '', node is empty string. + return "" + # None or '', node with a strong type is None. + # Don't try to model "empty bool" or "empty int" + return None + + if data_type == "bool": + if attr in [True, False, 1, 0]: + return bool(attr) + if isinstance(attr, str): + if attr.lower() in ["true", "1"]: + return True + if attr.lower() in ["false", "0"]: + return False + raise TypeError("Invalid boolean value: {}".format(attr)) + + if data_type == "str": + return self.deserialize_unicode(attr) + return eval(data_type)(attr) # nosec # pylint: disable=eval-used + + @staticmethod + def deserialize_unicode(data): + """Preserve unicode objects in Python 2, otherwise return data + as a string. + + :param str data: response string to be deserialized. + :return: Deserialized string. + :rtype: str or unicode + """ + # We might be here because we have an enum modeled as string, + # and we try to deserialize a partial dict with enum inside + if isinstance(data, Enum): + return data + + # Consider this is real string + try: + if isinstance(data, unicode): # type: ignore + return data + except NameError: + return str(data) + return str(data) + + @staticmethod + def deserialize_enum(data, enum_obj): + """Deserialize string into enum object. + + If the string is not a valid enum value it will be returned as-is + and a warning will be logged. + + :param str data: Response string to be deserialized. If this value is + None or invalid it will be returned as-is. + :param Enum enum_obj: Enum object to deserialize to. + :return: Deserialized enum object. + :rtype: Enum + """ + if isinstance(data, enum_obj) or data is None: + return data + if isinstance(data, Enum): + data = data.value + if isinstance(data, int): + # Workaround. We might consider remove it in the future. + try: + return list(enum_obj.__members__.values())[data] + except IndexError as exc: + error = "{!r} is not a valid index for enum {!r}" + raise DeserializationError(error.format(data, enum_obj)) from exc + try: + return enum_obj(str(data)) + except ValueError: + for enum_value in enum_obj: + if enum_value.value.lower() == str(data).lower(): + return enum_value + # We don't fail anymore for unknown value, we deserialize as a string + _LOGGER.warning("Deserializer is not able to find %s as valid enum in %s", data, enum_obj) + return Deserializer.deserialize_unicode(data) + + @staticmethod + def deserialize_bytearray(attr): + """Deserialize string into bytearray. + + :param str attr: response string to be deserialized. + :return: Deserialized bytearray + :rtype: bytearray + :raises TypeError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + return bytearray(b64decode(attr)) # type: ignore + + @staticmethod + def deserialize_base64(attr): + """Deserialize base64 encoded string into string. + + :param str attr: response string to be deserialized. + :return: Deserialized base64 string + :rtype: bytearray + :raises TypeError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + padding = "=" * (3 - (len(attr) + 3) % 4) # type: ignore + attr = attr + padding # type: ignore + encoded = attr.replace("-", "+").replace("_", "/") + return b64decode(encoded) + + @staticmethod + def deserialize_decimal(attr): + """Deserialize string into Decimal object. + + :param str attr: response string to be deserialized. + :return: Deserialized decimal + :raises DeserializationError: if string format invalid. + :rtype: decimal + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + return decimal.Decimal(str(attr)) # type: ignore + except decimal.DecimalException as err: + msg = "Invalid decimal {}".format(attr) + raise DeserializationError(msg) from err + + @staticmethod + def deserialize_long(attr): + """Deserialize string into long (Py2) or int (Py3). + + :param str attr: response string to be deserialized. + :return: Deserialized int + :rtype: long or int + :raises ValueError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + return _long_type(attr) # type: ignore + + @staticmethod + def deserialize_duration(attr): + """Deserialize ISO-8601 formatted string into TimeDelta object. + + :param str attr: response string to be deserialized. + :return: Deserialized duration + :rtype: TimeDelta + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + duration = isodate.parse_duration(attr) + except (ValueError, OverflowError, AttributeError) as err: + msg = "Cannot deserialize duration object." + raise DeserializationError(msg) from err + return duration + + @staticmethod + def deserialize_date(attr): + """Deserialize ISO-8601 formatted string into Date object. + + :param str attr: response string to be deserialized. + :return: Deserialized date + :rtype: Date + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + if re.search(r"[^\W\d_]", attr, re.I + re.U): # type: ignore + raise DeserializationError("Date must have only digits and -. Received: %s" % attr) + # This must NOT use defaultmonth/defaultday. Using None ensure this raises an exception. + return isodate.parse_date(attr, defaultmonth=0, defaultday=0) + + @staticmethod + def deserialize_time(attr): + """Deserialize ISO-8601 formatted string into time object. + + :param str attr: response string to be deserialized. + :return: Deserialized time + :rtype: datetime.time + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + if re.search(r"[^\W\d_]", attr, re.I + re.U): # type: ignore + raise DeserializationError("Date must have only digits and -. Received: %s" % attr) + return isodate.parse_time(attr) + + @staticmethod + def deserialize_rfc(attr): + """Deserialize RFC-1123 formatted string into Datetime object. + + :param str attr: response string to be deserialized. + :return: Deserialized RFC datetime + :rtype: Datetime + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + parsed_date = email.utils.parsedate_tz(attr) # type: ignore + date_obj = datetime.datetime( + *parsed_date[:6], tzinfo=datetime.timezone(datetime.timedelta(minutes=(parsed_date[9] or 0) / 60)) + ) + if not date_obj.tzinfo: + date_obj = date_obj.astimezone(tz=TZ_UTC) + except ValueError as err: + msg = "Cannot deserialize to rfc datetime object." + raise DeserializationError(msg) from err + return date_obj + + @staticmethod + def deserialize_iso(attr): + """Deserialize ISO-8601 formatted string into Datetime object. + + :param str attr: response string to be deserialized. + :return: Deserialized ISO datetime + :rtype: Datetime + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + attr = attr.upper() # type: ignore + match = Deserializer.valid_date.match(attr) + if not match: + raise ValueError("Invalid datetime string: " + attr) + + check_decimal = attr.split(".") + if len(check_decimal) > 1: + decimal_str = "" + for digit in check_decimal[1]: + if digit.isdigit(): + decimal_str += digit + else: + break + if len(decimal_str) > 6: + attr = attr.replace(decimal_str, decimal_str[0:6]) + + date_obj = isodate.parse_datetime(attr) + test_utc = date_obj.utctimetuple() + if test_utc.tm_year > 9999 or test_utc.tm_year < 1: + raise OverflowError("Hit max or min date") + except (ValueError, OverflowError, AttributeError) as err: + msg = "Cannot deserialize datetime object." + raise DeserializationError(msg) from err + return date_obj + + @staticmethod + def deserialize_unix(attr): + """Serialize Datetime object into IntTime format. + This is represented as seconds. + + :param int attr: Object to be serialized. + :return: Deserialized datetime + :rtype: Datetime + :raises DeserializationError: if format invalid + """ + if isinstance(attr, ET.Element): + attr = int(attr.text) # type: ignore + try: + attr = int(attr) + date_obj = datetime.datetime.fromtimestamp(attr, TZ_UTC) + except ValueError as err: + msg = "Cannot deserialize to unix datetime object." + raise DeserializationError(msg) from err + return date_obj diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/NonStringEnumsVersionTolerant/nonstringenumsversiontolerant/aio/_client.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/NonStringEnumsVersionTolerant/nonstringenumsversiontolerant/aio/_client.py index 46f8c40bb92..f6e123a9361 100644 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/NonStringEnumsVersionTolerant/nonstringenumsversiontolerant/aio/_client.py +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/NonStringEnumsVersionTolerant/nonstringenumsversiontolerant/aio/_client.py @@ -14,7 +14,7 @@ from azure.core.pipeline import policies from azure.core.rest import AsyncHttpResponse, HttpRequest -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import NonStringEnumsClientConfiguration from .operations import FloatOperations, IntOperations diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/NonStringEnumsVersionTolerant/nonstringenumsversiontolerant/aio/operations/_operations.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/NonStringEnumsVersionTolerant/nonstringenumsversiontolerant/aio/operations/_operations.py index 2edd5aab136..0aefa6f3bb2 100644 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/NonStringEnumsVersionTolerant/nonstringenumsversiontolerant/aio/operations/_operations.py +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/NonStringEnumsVersionTolerant/nonstringenumsversiontolerant/aio/operations/_operations.py @@ -22,7 +22,7 @@ from azure.core.tracing.decorator_async import distributed_trace_async from azure.core.utils import case_insensitive_dict -from ..._serialization import Deserializer, Serializer +from ..._utils.serialization import Deserializer, Serializer from ...operations._operations import ( build_float_get_request, build_float_put_request, diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/NonStringEnumsVersionTolerant/nonstringenumsversiontolerant/operations/_operations.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/NonStringEnumsVersionTolerant/nonstringenumsversiontolerant/operations/_operations.py index bfecf8941f4..2a41d8e2d00 100644 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/NonStringEnumsVersionTolerant/nonstringenumsversiontolerant/operations/_operations.py +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/NonStringEnumsVersionTolerant/nonstringenumsversiontolerant/operations/_operations.py @@ -23,7 +23,7 @@ from azure.core.utils import case_insensitive_dict from .._configuration import NonStringEnumsClientConfiguration -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ObjectTypeVersionTolerant/objecttypeversiontolerant/_client.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ObjectTypeVersionTolerant/objecttypeversiontolerant/_client.py index bde48d72ba0..319d3aacd92 100644 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ObjectTypeVersionTolerant/objecttypeversiontolerant/_client.py +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ObjectTypeVersionTolerant/objecttypeversiontolerant/_client.py @@ -16,7 +16,7 @@ from ._configuration import ObjectTypeClientConfiguration from ._operations import ObjectTypeClientOperationsMixin -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer class ObjectTypeClient(ObjectTypeClientOperationsMixin): # pylint: disable=client-accepts-api-version-keyword diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ObjectTypeVersionTolerant/objecttypeversiontolerant/_operations/_operations.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ObjectTypeVersionTolerant/objecttypeversiontolerant/_operations/_operations.py index e0e0ff9d31a..fcca36c6b93 100644 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ObjectTypeVersionTolerant/objecttypeversiontolerant/_operations/_operations.py +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ObjectTypeVersionTolerant/objecttypeversiontolerant/_operations/_operations.py @@ -8,6 +8,7 @@ from collections.abc import MutableMapping from typing import Any, Callable, Dict, Optional, TypeVar, cast +from azure.core import PipelineClient from azure.core.exceptions import ( ClientAuthenticationError, HttpResponseError, @@ -21,8 +22,9 @@ from azure.core.tracing.decorator import distributed_trace from azure.core.utils import case_insensitive_dict -from .._serialization import Serializer -from .._vendor import ObjectTypeClientMixinABC +from .._configuration import ObjectTypeClientConfiguration +from .._utils.serialization import Serializer +from .._utils.utils import ClientMixinABC JSON = MutableMapping[str, Any] T = TypeVar("T") @@ -63,7 +65,7 @@ def build_object_type_put_request(*, json: JSON, **kwargs: Any) -> HttpRequest: return HttpRequest(method="PUT", url=_url, headers=_headers, json=json, **kwargs) -class ObjectTypeClientOperationsMixin(ObjectTypeClientMixinABC): +class ObjectTypeClientOperationsMixin(ClientMixinABC[PipelineClient, ObjectTypeClientConfiguration]): @distributed_trace def get(self, **kwargs: Any) -> JSON: diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ObjectTypeVersionTolerant/objecttypeversiontolerant/_utils/__init__.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ObjectTypeVersionTolerant/objecttypeversiontolerant/_utils/__init__.py new file mode 100644 index 00000000000..0af9b28f660 --- /dev/null +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ObjectTypeVersionTolerant/objecttypeversiontolerant/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ObjectTypeVersionTolerant/objecttypeversiontolerant/_utils/serialization.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ObjectTypeVersionTolerant/objecttypeversiontolerant/_utils/serialization.py new file mode 100644 index 00000000000..f5187701d7b --- /dev/null +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ObjectTypeVersionTolerant/objecttypeversiontolerant/_utils/serialization.py @@ -0,0 +1,2032 @@ +# pylint: disable=line-too-long,useless-suppression,too-many-lines +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +# pyright: reportUnnecessaryTypeIgnoreComment=false + +from base64 import b64decode, b64encode +import calendar +import datetime +import decimal +import email +from enum import Enum +import json +import logging +import re +import sys +import codecs +from typing import ( + Dict, + Any, + cast, + Optional, + Union, + AnyStr, + IO, + Mapping, + Callable, + MutableMapping, + List, +) + +try: + from urllib import quote # type: ignore +except ImportError: + from urllib.parse import quote +import xml.etree.ElementTree as ET + +import isodate # type: ignore +from typing_extensions import Self + +from azure.core.exceptions import DeserializationError, SerializationError +from azure.core.serialization import NULL as CoreNull + +_BOM = codecs.BOM_UTF8.decode(encoding="utf-8") + +JSON = MutableMapping[str, Any] + + +class RawDeserializer: + + # Accept "text" because we're open minded people... + JSON_REGEXP = re.compile(r"^(application|text)/([a-z+.]+\+)?json$") + + # Name used in context + CONTEXT_NAME = "deserialized_data" + + @classmethod + def deserialize_from_text(cls, data: Optional[Union[AnyStr, IO]], content_type: Optional[str] = None) -> Any: + """Decode data according to content-type. + + Accept a stream of data as well, but will be load at once in memory for now. + + If no content-type, will return the string version (not bytes, not stream) + + :param data: Input, could be bytes or stream (will be decoded with UTF8) or text + :type data: str or bytes or IO + :param str content_type: The content type. + :return: The deserialized data. + :rtype: object + """ + if hasattr(data, "read"): + # Assume a stream + data = cast(IO, data).read() + + if isinstance(data, bytes): + data_as_str = data.decode(encoding="utf-8-sig") + else: + # Explain to mypy the correct type. + data_as_str = cast(str, data) + + # Remove Byte Order Mark if present in string + data_as_str = data_as_str.lstrip(_BOM) + + if content_type is None: + return data + + if cls.JSON_REGEXP.match(content_type): + try: + return json.loads(data_as_str) + except ValueError as err: + raise DeserializationError("JSON is invalid: {}".format(err), err) from err + elif "xml" in (content_type or []): + try: + + try: + if isinstance(data, unicode): # type: ignore + # If I'm Python 2.7 and unicode XML will scream if I try a "fromstring" on unicode string + data_as_str = data_as_str.encode(encoding="utf-8") # type: ignore + except NameError: + pass + + return ET.fromstring(data_as_str) # nosec + except ET.ParseError as err: + # It might be because the server has an issue, and returned JSON with + # content-type XML.... + # So let's try a JSON load, and if it's still broken + # let's flow the initial exception + def _json_attemp(data): + try: + return True, json.loads(data) + except ValueError: + return False, None # Don't care about this one + + success, json_result = _json_attemp(data) + if success: + return json_result + # If i'm here, it's not JSON, it's not XML, let's scream + # and raise the last context in this block (the XML exception) + # The function hack is because Py2.7 messes up with exception + # context otherwise. + _LOGGER.critical("Wasn't XML not JSON, failing") + raise DeserializationError("XML is invalid") from err + elif content_type.startswith("text/"): + return data_as_str + raise DeserializationError("Cannot deserialize content-type: {}".format(content_type)) + + @classmethod + def deserialize_from_http_generics(cls, body_bytes: Optional[Union[AnyStr, IO]], headers: Mapping) -> Any: + """Deserialize from HTTP response. + + Use bytes and headers to NOT use any requests/aiohttp or whatever + specific implementation. + Headers will tested for "content-type" + + :param bytes body_bytes: The body of the response. + :param dict headers: The headers of the response. + :returns: The deserialized data. + :rtype: object + """ + # Try to use content-type from headers if available + content_type = None + if "content-type" in headers: + content_type = headers["content-type"].split(";")[0].strip().lower() + # Ouch, this server did not declare what it sent... + # Let's guess it's JSON... + # Also, since Autorest was considering that an empty body was a valid JSON, + # need that test as well.... + else: + content_type = "application/json" + + if body_bytes: + return cls.deserialize_from_text(body_bytes, content_type) + return None + + +_LOGGER = logging.getLogger(__name__) + +try: + _long_type = long # type: ignore +except NameError: + _long_type = int + +TZ_UTC = datetime.timezone.utc + +_FLATTEN = re.compile(r"(? None: + self.additional_properties: Optional[Dict[str, Any]] = {} + for k in kwargs: # pylint: disable=consider-using-dict-items + if k not in self._attribute_map: + _LOGGER.warning("%s is not a known attribute of class %s and will be ignored", k, self.__class__) + elif k in self._validation and self._validation[k].get("readonly", False): + _LOGGER.warning("Readonly attribute %s will be ignored in class %s", k, self.__class__) + else: + setattr(self, k, kwargs[k]) + + def __eq__(self, other: Any) -> bool: + """Compare objects by comparing all attributes. + + :param object other: The object to compare + :returns: True if objects are equal + :rtype: bool + """ + if isinstance(other, self.__class__): + return self.__dict__ == other.__dict__ + return False + + def __ne__(self, other: Any) -> bool: + """Compare objects by comparing all attributes. + + :param object other: The object to compare + :returns: True if objects are not equal + :rtype: bool + """ + return not self.__eq__(other) + + def __str__(self) -> str: + return str(self.__dict__) + + @classmethod + def enable_additional_properties_sending(cls) -> None: + cls._attribute_map["additional_properties"] = {"key": "", "type": "{object}"} + + @classmethod + def is_xml_model(cls) -> bool: + try: + cls._xml_map # type: ignore + except AttributeError: + return False + return True + + @classmethod + def _create_xml_node(cls): + """Create XML node. + + :returns: The XML node + :rtype: xml.etree.ElementTree.Element + """ + try: + xml_map = cls._xml_map # type: ignore + except AttributeError: + xml_map = {} + + return _create_xml_node(xml_map.get("name", cls.__name__), xml_map.get("prefix", None), xml_map.get("ns", None)) + + def serialize(self, keep_readonly: bool = False, **kwargs: Any) -> JSON: + """Return the JSON that would be sent to server from this model. + + This is an alias to `as_dict(full_restapi_key_transformer, keep_readonly=False)`. + + If you want XML serialization, you can pass the kwargs is_xml=True. + + :param bool keep_readonly: If you want to serialize the readonly attributes + :returns: A dict JSON compatible object + :rtype: dict + """ + serializer = Serializer(self._infer_class_models()) + return serializer._serialize( # type: ignore # pylint: disable=protected-access + self, keep_readonly=keep_readonly, **kwargs + ) + + def as_dict( + self, + keep_readonly: bool = True, + key_transformer: Callable[[str, Dict[str, Any], Any], Any] = attribute_transformer, + **kwargs: Any + ) -> JSON: + """Return a dict that can be serialized using json.dump. + + Advanced usage might optionally use a callback as parameter: + + .. code::python + + def my_key_transformer(key, attr_desc, value): + return key + + Key is the attribute name used in Python. Attr_desc + is a dict of metadata. Currently contains 'type' with the + msrest type and 'key' with the RestAPI encoded key. + Value is the current value in this object. + + The string returned will be used to serialize the key. + If the return type is a list, this is considered hierarchical + result dict. + + See the three examples in this file: + + - attribute_transformer + - full_restapi_key_transformer + - last_restapi_key_transformer + + If you want XML serialization, you can pass the kwargs is_xml=True. + + :param bool keep_readonly: If you want to serialize the readonly attributes + :param function key_transformer: A key transformer function. + :returns: A dict JSON compatible object + :rtype: dict + """ + serializer = Serializer(self._infer_class_models()) + return serializer._serialize( # type: ignore # pylint: disable=protected-access + self, key_transformer=key_transformer, keep_readonly=keep_readonly, **kwargs + ) + + @classmethod + def _infer_class_models(cls): + try: + str_models = cls.__module__.rsplit(".", 1)[0] + models = sys.modules[str_models] + client_models = {k: v for k, v in models.__dict__.items() if isinstance(v, type)} + if cls.__name__ not in client_models: + raise ValueError("Not Autorest generated code") + except Exception: # pylint: disable=broad-exception-caught + # Assume it's not Autorest generated (tests?). Add ourselves as dependencies. + client_models = {cls.__name__: cls} + return client_models + + @classmethod + def deserialize(cls, data: Any, content_type: Optional[str] = None) -> Self: + """Parse a str using the RestAPI syntax and return a model. + + :param str data: A str using RestAPI structure. JSON by default. + :param str content_type: JSON by default, set application/xml if XML. + :returns: An instance of this model + :raises DeserializationError: if something went wrong + :rtype: Self + """ + deserializer = Deserializer(cls._infer_class_models()) + return deserializer(cls.__name__, data, content_type=content_type) # type: ignore + + @classmethod + def from_dict( + cls, + data: Any, + key_extractors: Optional[Callable[[str, Dict[str, Any], Any], Any]] = None, + content_type: Optional[str] = None, + ) -> Self: + """Parse a dict using given key extractor return a model. + + By default consider key + extractors (rest_key_case_insensitive_extractor, attribute_key_case_insensitive_extractor + and last_rest_key_case_insensitive_extractor) + + :param dict data: A dict using RestAPI structure + :param function key_extractors: A key extractor function. + :param str content_type: JSON by default, set application/xml if XML. + :returns: An instance of this model + :raises DeserializationError: if something went wrong + :rtype: Self + """ + deserializer = Deserializer(cls._infer_class_models()) + deserializer.key_extractors = ( # type: ignore + [ # type: ignore + attribute_key_case_insensitive_extractor, + rest_key_case_insensitive_extractor, + last_rest_key_case_insensitive_extractor, + ] + if key_extractors is None + else key_extractors + ) + return deserializer(cls.__name__, data, content_type=content_type) # type: ignore + + @classmethod + def _flatten_subtype(cls, key, objects): + if "_subtype_map" not in cls.__dict__: + return {} + result = dict(cls._subtype_map[key]) + for valuetype in cls._subtype_map[key].values(): + result.update(objects[valuetype]._flatten_subtype(key, objects)) # pylint: disable=protected-access + return result + + @classmethod + def _classify(cls, response, objects): + """Check the class _subtype_map for any child classes. + We want to ignore any inherited _subtype_maps. + + :param dict response: The initial data + :param dict objects: The class objects + :returns: The class to be used + :rtype: class + """ + for subtype_key in cls.__dict__.get("_subtype_map", {}).keys(): + subtype_value = None + + if not isinstance(response, ET.Element): + rest_api_response_key = cls._get_rest_key_parts(subtype_key)[-1] + subtype_value = response.get(rest_api_response_key, None) or response.get(subtype_key, None) + else: + subtype_value = xml_key_extractor(subtype_key, cls._attribute_map[subtype_key], response) + if subtype_value: + # Try to match base class. Can be class name only + # (bug to fix in Autorest to support x-ms-discriminator-name) + if cls.__name__ == subtype_value: + return cls + flatten_mapping_type = cls._flatten_subtype(subtype_key, objects) + try: + return objects[flatten_mapping_type[subtype_value]] # type: ignore + except KeyError: + _LOGGER.warning( + "Subtype value %s has no mapping, use base class %s.", + subtype_value, + cls.__name__, + ) + break + else: + _LOGGER.warning("Discriminator %s is absent or null, use base class %s.", subtype_key, cls.__name__) + break + return cls + + @classmethod + def _get_rest_key_parts(cls, attr_key): + """Get the RestAPI key of this attr, split it and decode part + :param str attr_key: Attribute key must be in attribute_map. + :returns: A list of RestAPI part + :rtype: list + """ + rest_split_key = _FLATTEN.split(cls._attribute_map[attr_key]["key"]) + return [_decode_attribute_map_key(key_part) for key_part in rest_split_key] + + +def _decode_attribute_map_key(key): + """This decode a key in an _attribute_map to the actual key we want to look at + inside the received data. + + :param str key: A key string from the generated code + :returns: The decoded key + :rtype: str + """ + return key.replace("\\.", ".") + + +class Serializer: # pylint: disable=too-many-public-methods + """Request object model serializer.""" + + basic_types = {str: "str", int: "int", bool: "bool", float: "float"} + + _xml_basic_types_serializers = {"bool": lambda x: str(x).lower()} + days = {0: "Mon", 1: "Tue", 2: "Wed", 3: "Thu", 4: "Fri", 5: "Sat", 6: "Sun"} + months = { + 1: "Jan", + 2: "Feb", + 3: "Mar", + 4: "Apr", + 5: "May", + 6: "Jun", + 7: "Jul", + 8: "Aug", + 9: "Sep", + 10: "Oct", + 11: "Nov", + 12: "Dec", + } + validation = { + "min_length": lambda x, y: len(x) < y, + "max_length": lambda x, y: len(x) > y, + "minimum": lambda x, y: x < y, + "maximum": lambda x, y: x > y, + "minimum_ex": lambda x, y: x <= y, + "maximum_ex": lambda x, y: x >= y, + "min_items": lambda x, y: len(x) < y, + "max_items": lambda x, y: len(x) > y, + "pattern": lambda x, y: not re.match(y, x, re.UNICODE), + "unique": lambda x, y: len(x) != len(set(x)), + "multiple": lambda x, y: x % y != 0, + } + + def __init__(self, classes: Optional[Mapping[str, type]] = None) -> None: + self.serialize_type = { + "iso-8601": Serializer.serialize_iso, + "rfc-1123": Serializer.serialize_rfc, + "unix-time": Serializer.serialize_unix, + "duration": Serializer.serialize_duration, + "date": Serializer.serialize_date, + "time": Serializer.serialize_time, + "decimal": Serializer.serialize_decimal, + "long": Serializer.serialize_long, + "bytearray": Serializer.serialize_bytearray, + "base64": Serializer.serialize_base64, + "object": self.serialize_object, + "[]": self.serialize_iter, + "{}": self.serialize_dict, + } + self.dependencies: Dict[str, type] = dict(classes) if classes else {} + self.key_transformer = full_restapi_key_transformer + self.client_side_validation = True + + def _serialize( # pylint: disable=too-many-nested-blocks, too-many-branches, too-many-statements, too-many-locals + self, target_obj, data_type=None, **kwargs + ): + """Serialize data into a string according to type. + + :param object target_obj: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str, dict + :raises SerializationError: if serialization fails. + :returns: The serialized data. + """ + key_transformer = kwargs.get("key_transformer", self.key_transformer) + keep_readonly = kwargs.get("keep_readonly", False) + if target_obj is None: + return None + + attr_name = None + class_name = target_obj.__class__.__name__ + + if data_type: + return self.serialize_data(target_obj, data_type, **kwargs) + + if not hasattr(target_obj, "_attribute_map"): + data_type = type(target_obj).__name__ + if data_type in self.basic_types.values(): + return self.serialize_data(target_obj, data_type, **kwargs) + + # Force "is_xml" kwargs if we detect a XML model + try: + is_xml_model_serialization = kwargs["is_xml"] + except KeyError: + is_xml_model_serialization = kwargs.setdefault("is_xml", target_obj.is_xml_model()) + + serialized = {} + if is_xml_model_serialization: + serialized = target_obj._create_xml_node() # pylint: disable=protected-access + try: + attributes = target_obj._attribute_map # pylint: disable=protected-access + for attr, attr_desc in attributes.items(): + attr_name = attr + if not keep_readonly and target_obj._validation.get( # pylint: disable=protected-access + attr_name, {} + ).get("readonly", False): + continue + + if attr_name == "additional_properties" and attr_desc["key"] == "": + if target_obj.additional_properties is not None: + serialized.update(target_obj.additional_properties) + continue + try: + + orig_attr = getattr(target_obj, attr) + if is_xml_model_serialization: + pass # Don't provide "transformer" for XML for now. Keep "orig_attr" + else: # JSON + keys, orig_attr = key_transformer(attr, attr_desc.copy(), orig_attr) + keys = keys if isinstance(keys, list) else [keys] + + kwargs["serialization_ctxt"] = attr_desc + new_attr = self.serialize_data(orig_attr, attr_desc["type"], **kwargs) + + if is_xml_model_serialization: + xml_desc = attr_desc.get("xml", {}) + xml_name = xml_desc.get("name", attr_desc["key"]) + xml_prefix = xml_desc.get("prefix", None) + xml_ns = xml_desc.get("ns", None) + if xml_desc.get("attr", False): + if xml_ns: + ET.register_namespace(xml_prefix, xml_ns) + xml_name = "{{{}}}{}".format(xml_ns, xml_name) + serialized.set(xml_name, new_attr) # type: ignore + continue + if xml_desc.get("text", False): + serialized.text = new_attr # type: ignore + continue + if isinstance(new_attr, list): + serialized.extend(new_attr) # type: ignore + elif isinstance(new_attr, ET.Element): + # If the down XML has no XML/Name, + # we MUST replace the tag with the local tag. But keeping the namespaces. + if "name" not in getattr(orig_attr, "_xml_map", {}): + splitted_tag = new_attr.tag.split("}") + if len(splitted_tag) == 2: # Namespace + new_attr.tag = "}".join([splitted_tag[0], xml_name]) + else: + new_attr.tag = xml_name + serialized.append(new_attr) # type: ignore + else: # That's a basic type + # Integrate namespace if necessary + local_node = _create_xml_node(xml_name, xml_prefix, xml_ns) + local_node.text = str(new_attr) + serialized.append(local_node) # type: ignore + else: # JSON + for k in reversed(keys): # type: ignore + new_attr = {k: new_attr} + + _new_attr = new_attr + _serialized = serialized + for k in keys: # type: ignore + if k not in _serialized: + _serialized.update(_new_attr) # type: ignore + _new_attr = _new_attr[k] # type: ignore + _serialized = _serialized[k] + except ValueError as err: + if isinstance(err, SerializationError): + raise + + except (AttributeError, KeyError, TypeError) as err: + msg = "Attribute {} in object {} cannot be serialized.\n{}".format(attr_name, class_name, str(target_obj)) + raise SerializationError(msg) from err + return serialized + + def body(self, data, data_type, **kwargs): + """Serialize data intended for a request body. + + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: dict + :raises SerializationError: if serialization fails. + :raises ValueError: if data is None + :returns: The serialized request body + """ + + # Just in case this is a dict + internal_data_type_str = data_type.strip("[]{}") + internal_data_type = self.dependencies.get(internal_data_type_str, None) + try: + is_xml_model_serialization = kwargs["is_xml"] + except KeyError: + if internal_data_type and issubclass(internal_data_type, Model): + is_xml_model_serialization = kwargs.setdefault("is_xml", internal_data_type.is_xml_model()) + else: + is_xml_model_serialization = False + if internal_data_type and not isinstance(internal_data_type, Enum): + try: + deserializer = Deserializer(self.dependencies) + # Since it's on serialization, it's almost sure that format is not JSON REST + # We're not able to deal with additional properties for now. + deserializer.additional_properties_detection = False + if is_xml_model_serialization: + deserializer.key_extractors = [ # type: ignore + attribute_key_case_insensitive_extractor, + ] + else: + deserializer.key_extractors = [ + rest_key_case_insensitive_extractor, + attribute_key_case_insensitive_extractor, + last_rest_key_case_insensitive_extractor, + ] + data = deserializer._deserialize(data_type, data) # pylint: disable=protected-access + except DeserializationError as err: + raise SerializationError("Unable to build a model: " + str(err)) from err + + return self._serialize(data, data_type, **kwargs) + + def url(self, name, data, data_type, **kwargs): + """Serialize data intended for a URL path. + + :param str name: The name of the URL path parameter. + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str + :returns: The serialized URL path + :raises TypeError: if serialization fails. + :raises ValueError: if data is None + """ + try: + output = self.serialize_data(data, data_type, **kwargs) + if data_type == "bool": + output = json.dumps(output) + + if kwargs.get("skip_quote") is True: + output = str(output) + output = output.replace("{", quote("{")).replace("}", quote("}")) + else: + output = quote(str(output), safe="") + except SerializationError as exc: + raise TypeError("{} must be type {}.".format(name, data_type)) from exc + return output + + def query(self, name, data, data_type, **kwargs): + """Serialize data intended for a URL query. + + :param str name: The name of the query parameter. + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str, list + :raises TypeError: if serialization fails. + :raises ValueError: if data is None + :returns: The serialized query parameter + """ + try: + # Treat the list aside, since we don't want to encode the div separator + if data_type.startswith("["): + internal_data_type = data_type[1:-1] + do_quote = not kwargs.get("skip_quote", False) + return self.serialize_iter(data, internal_data_type, do_quote=do_quote, **kwargs) + + # Not a list, regular serialization + output = self.serialize_data(data, data_type, **kwargs) + if data_type == "bool": + output = json.dumps(output) + if kwargs.get("skip_quote") is True: + output = str(output) + else: + output = quote(str(output), safe="") + except SerializationError as exc: + raise TypeError("{} must be type {}.".format(name, data_type)) from exc + return str(output) + + def header(self, name, data, data_type, **kwargs): + """Serialize data intended for a request header. + + :param str name: The name of the header. + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str + :raises TypeError: if serialization fails. + :raises ValueError: if data is None + :returns: The serialized header + """ + try: + if data_type in ["[str]"]: + data = ["" if d is None else d for d in data] + + output = self.serialize_data(data, data_type, **kwargs) + if data_type == "bool": + output = json.dumps(output) + except SerializationError as exc: + raise TypeError("{} must be type {}.".format(name, data_type)) from exc + return str(output) + + def serialize_data(self, data, data_type, **kwargs): + """Serialize generic data according to supplied data type. + + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :raises AttributeError: if required data is None. + :raises ValueError: if data is None + :raises SerializationError: if serialization fails. + :returns: The serialized data. + :rtype: str, int, float, bool, dict, list + """ + if data is None: + raise ValueError("No value for given attribute") + + try: + if data is CoreNull: + return None + if data_type in self.basic_types.values(): + return self.serialize_basic(data, data_type, **kwargs) + + if data_type in self.serialize_type: + return self.serialize_type[data_type](data, **kwargs) + + # If dependencies is empty, try with current data class + # It has to be a subclass of Enum anyway + enum_type = self.dependencies.get(data_type, data.__class__) + if issubclass(enum_type, Enum): + return Serializer.serialize_enum(data, enum_obj=enum_type) + + iter_type = data_type[0] + data_type[-1] + if iter_type in self.serialize_type: + return self.serialize_type[iter_type](data, data_type[1:-1], **kwargs) + + except (ValueError, TypeError) as err: + msg = "Unable to serialize value: {!r} as type: {!r}." + raise SerializationError(msg.format(data, data_type)) from err + return self._serialize(data, **kwargs) + + @classmethod + def _get_custom_serializers(cls, data_type, **kwargs): # pylint: disable=inconsistent-return-statements + custom_serializer = kwargs.get("basic_types_serializers", {}).get(data_type) + if custom_serializer: + return custom_serializer + if kwargs.get("is_xml", False): + return cls._xml_basic_types_serializers.get(data_type) + + @classmethod + def serialize_basic(cls, data, data_type, **kwargs): + """Serialize basic builting data type. + Serializes objects to str, int, float or bool. + + Possible kwargs: + - basic_types_serializers dict[str, callable] : If set, use the callable as serializer + - is_xml bool : If set, use xml_basic_types_serializers + + :param obj data: Object to be serialized. + :param str data_type: Type of object in the iterable. + :rtype: str, int, float, bool + :return: serialized object + """ + custom_serializer = cls._get_custom_serializers(data_type, **kwargs) + if custom_serializer: + return custom_serializer(data) + if data_type == "str": + return cls.serialize_unicode(data) + return eval(data_type)(data) # nosec # pylint: disable=eval-used + + @classmethod + def serialize_unicode(cls, data): + """Special handling for serializing unicode strings in Py2. + Encode to UTF-8 if unicode, otherwise handle as a str. + + :param str data: Object to be serialized. + :rtype: str + :return: serialized object + """ + try: # If I received an enum, return its value + return data.value + except AttributeError: + pass + + try: + if isinstance(data, unicode): # type: ignore + # Don't change it, JSON and XML ElementTree are totally able + # to serialize correctly u'' strings + return data + except NameError: + return str(data) + return str(data) + + def serialize_iter(self, data, iter_type, div=None, **kwargs): + """Serialize iterable. + + Supported kwargs: + - serialization_ctxt dict : The current entry of _attribute_map, or same format. + serialization_ctxt['type'] should be same as data_type. + - is_xml bool : If set, serialize as XML + + :param list data: Object to be serialized. + :param str iter_type: Type of object in the iterable. + :param str div: If set, this str will be used to combine the elements + in the iterable into a combined string. Default is 'None'. + Defaults to False. + :rtype: list, str + :return: serialized iterable + """ + if isinstance(data, str): + raise SerializationError("Refuse str type as a valid iter type.") + + serialization_ctxt = kwargs.get("serialization_ctxt", {}) + is_xml = kwargs.get("is_xml", False) + + serialized = [] + for d in data: + try: + serialized.append(self.serialize_data(d, iter_type, **kwargs)) + except ValueError as err: + if isinstance(err, SerializationError): + raise + serialized.append(None) + + if kwargs.get("do_quote", False): + serialized = ["" if s is None else quote(str(s), safe="") for s in serialized] + + if div: + serialized = ["" if s is None else str(s) for s in serialized] + serialized = div.join(serialized) + + if "xml" in serialization_ctxt or is_xml: + # XML serialization is more complicated + xml_desc = serialization_ctxt.get("xml", {}) + xml_name = xml_desc.get("name") + if not xml_name: + xml_name = serialization_ctxt["key"] + + # Create a wrap node if necessary (use the fact that Element and list have "append") + is_wrapped = xml_desc.get("wrapped", False) + node_name = xml_desc.get("itemsName", xml_name) + if is_wrapped: + final_result = _create_xml_node(xml_name, xml_desc.get("prefix", None), xml_desc.get("ns", None)) + else: + final_result = [] + # All list elements to "local_node" + for el in serialized: + if isinstance(el, ET.Element): + el_node = el + else: + el_node = _create_xml_node(node_name, xml_desc.get("prefix", None), xml_desc.get("ns", None)) + if el is not None: # Otherwise it writes "None" :-p + el_node.text = str(el) + final_result.append(el_node) + return final_result + return serialized + + def serialize_dict(self, attr, dict_type, **kwargs): + """Serialize a dictionary of objects. + + :param dict attr: Object to be serialized. + :param str dict_type: Type of object in the dictionary. + :rtype: dict + :return: serialized dictionary + """ + serialization_ctxt = kwargs.get("serialization_ctxt", {}) + serialized = {} + for key, value in attr.items(): + try: + serialized[self.serialize_unicode(key)] = self.serialize_data(value, dict_type, **kwargs) + except ValueError as err: + if isinstance(err, SerializationError): + raise + serialized[self.serialize_unicode(key)] = None + + if "xml" in serialization_ctxt: + # XML serialization is more complicated + xml_desc = serialization_ctxt["xml"] + xml_name = xml_desc["name"] + + final_result = _create_xml_node(xml_name, xml_desc.get("prefix", None), xml_desc.get("ns", None)) + for key, value in serialized.items(): + ET.SubElement(final_result, key).text = value + return final_result + + return serialized + + def serialize_object(self, attr, **kwargs): # pylint: disable=too-many-return-statements + """Serialize a generic object. + This will be handled as a dictionary. If object passed in is not + a basic type (str, int, float, dict, list) it will simply be + cast to str. + + :param dict attr: Object to be serialized. + :rtype: dict or str + :return: serialized object + """ + if attr is None: + return None + if isinstance(attr, ET.Element): + return attr + obj_type = type(attr) + if obj_type in self.basic_types: + return self.serialize_basic(attr, self.basic_types[obj_type], **kwargs) + if obj_type is _long_type: + return self.serialize_long(attr) + if obj_type is str: + return self.serialize_unicode(attr) + if obj_type is datetime.datetime: + return self.serialize_iso(attr) + if obj_type is datetime.date: + return self.serialize_date(attr) + if obj_type is datetime.time: + return self.serialize_time(attr) + if obj_type is datetime.timedelta: + return self.serialize_duration(attr) + if obj_type is decimal.Decimal: + return self.serialize_decimal(attr) + + # If it's a model or I know this dependency, serialize as a Model + if obj_type in self.dependencies.values() or isinstance(attr, Model): + return self._serialize(attr) + + if obj_type == dict: + serialized = {} + for key, value in attr.items(): + try: + serialized[self.serialize_unicode(key)] = self.serialize_object(value, **kwargs) + except ValueError: + serialized[self.serialize_unicode(key)] = None + return serialized + + if obj_type == list: + serialized = [] + for obj in attr: + try: + serialized.append(self.serialize_object(obj, **kwargs)) + except ValueError: + pass + return serialized + return str(attr) + + @staticmethod + def serialize_enum(attr, enum_obj=None): + try: + result = attr.value + except AttributeError: + result = attr + try: + enum_obj(result) # type: ignore + return result + except ValueError as exc: + for enum_value in enum_obj: # type: ignore + if enum_value.value.lower() == str(attr).lower(): + return enum_value.value + error = "{!r} is not valid value for enum {!r}" + raise SerializationError(error.format(attr, enum_obj)) from exc + + @staticmethod + def serialize_bytearray(attr, **kwargs): # pylint: disable=unused-argument + """Serialize bytearray into base-64 string. + + :param str attr: Object to be serialized. + :rtype: str + :return: serialized base64 + """ + return b64encode(attr).decode() + + @staticmethod + def serialize_base64(attr, **kwargs): # pylint: disable=unused-argument + """Serialize str into base-64 string. + + :param str attr: Object to be serialized. + :rtype: str + :return: serialized base64 + """ + encoded = b64encode(attr).decode("ascii") + return encoded.strip("=").replace("+", "-").replace("/", "_") + + @staticmethod + def serialize_decimal(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Decimal object to float. + + :param decimal attr: Object to be serialized. + :rtype: float + :return: serialized decimal + """ + return float(attr) + + @staticmethod + def serialize_long(attr, **kwargs): # pylint: disable=unused-argument + """Serialize long (Py2) or int (Py3). + + :param int attr: Object to be serialized. + :rtype: int/long + :return: serialized long + """ + return _long_type(attr) + + @staticmethod + def serialize_date(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Date object into ISO-8601 formatted string. + + :param Date attr: Object to be serialized. + :rtype: str + :return: serialized date + """ + if isinstance(attr, str): + attr = isodate.parse_date(attr) + t = "{:04}-{:02}-{:02}".format(attr.year, attr.month, attr.day) + return t + + @staticmethod + def serialize_time(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Time object into ISO-8601 formatted string. + + :param datetime.time attr: Object to be serialized. + :rtype: str + :return: serialized time + """ + if isinstance(attr, str): + attr = isodate.parse_time(attr) + t = "{:02}:{:02}:{:02}".format(attr.hour, attr.minute, attr.second) + if attr.microsecond: + t += ".{:02}".format(attr.microsecond) + return t + + @staticmethod + def serialize_duration(attr, **kwargs): # pylint: disable=unused-argument + """Serialize TimeDelta object into ISO-8601 formatted string. + + :param TimeDelta attr: Object to be serialized. + :rtype: str + :return: serialized duration + """ + if isinstance(attr, str): + attr = isodate.parse_duration(attr) + return isodate.duration_isoformat(attr) + + @staticmethod + def serialize_rfc(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Datetime object into RFC-1123 formatted string. + + :param Datetime attr: Object to be serialized. + :rtype: str + :raises TypeError: if format invalid. + :return: serialized rfc + """ + try: + if not attr.tzinfo: + _LOGGER.warning("Datetime with no tzinfo will be considered UTC.") + utc = attr.utctimetuple() + except AttributeError as exc: + raise TypeError("RFC1123 object must be valid Datetime object.") from exc + + return "{}, {:02} {} {:04} {:02}:{:02}:{:02} GMT".format( + Serializer.days[utc.tm_wday], + utc.tm_mday, + Serializer.months[utc.tm_mon], + utc.tm_year, + utc.tm_hour, + utc.tm_min, + utc.tm_sec, + ) + + @staticmethod + def serialize_iso(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Datetime object into ISO-8601 formatted string. + + :param Datetime attr: Object to be serialized. + :rtype: str + :raises SerializationError: if format invalid. + :return: serialized iso + """ + if isinstance(attr, str): + attr = isodate.parse_datetime(attr) + try: + if not attr.tzinfo: + _LOGGER.warning("Datetime with no tzinfo will be considered UTC.") + utc = attr.utctimetuple() + if utc.tm_year > 9999 or utc.tm_year < 1: + raise OverflowError("Hit max or min date") + + microseconds = str(attr.microsecond).rjust(6, "0").rstrip("0").ljust(3, "0") + if microseconds: + microseconds = "." + microseconds + date = "{:04}-{:02}-{:02}T{:02}:{:02}:{:02}".format( + utc.tm_year, utc.tm_mon, utc.tm_mday, utc.tm_hour, utc.tm_min, utc.tm_sec + ) + return date + microseconds + "Z" + except (ValueError, OverflowError) as err: + msg = "Unable to serialize datetime object." + raise SerializationError(msg) from err + except AttributeError as err: + msg = "ISO-8601 object must be valid Datetime object." + raise TypeError(msg) from err + + @staticmethod + def serialize_unix(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Datetime object into IntTime format. + This is represented as seconds. + + :param Datetime attr: Object to be serialized. + :rtype: int + :raises SerializationError: if format invalid + :return: serialied unix + """ + if isinstance(attr, int): + return attr + try: + if not attr.tzinfo: + _LOGGER.warning("Datetime with no tzinfo will be considered UTC.") + return int(calendar.timegm(attr.utctimetuple())) + except AttributeError as exc: + raise TypeError("Unix time object must be valid Datetime object.") from exc + + +def rest_key_extractor(attr, attr_desc, data): # pylint: disable=unused-argument + key = attr_desc["key"] + working_data = data + + while "." in key: + # Need the cast, as for some reasons "split" is typed as list[str | Any] + dict_keys = cast(List[str], _FLATTEN.split(key)) + if len(dict_keys) == 1: + key = _decode_attribute_map_key(dict_keys[0]) + break + working_key = _decode_attribute_map_key(dict_keys[0]) + working_data = working_data.get(working_key, data) + if working_data is None: + # If at any point while following flatten JSON path see None, it means + # that all properties under are None as well + return None + key = ".".join(dict_keys[1:]) + + return working_data.get(key) + + +def rest_key_case_insensitive_extractor( # pylint: disable=unused-argument, inconsistent-return-statements + attr, attr_desc, data +): + key = attr_desc["key"] + working_data = data + + while "." in key: + dict_keys = _FLATTEN.split(key) + if len(dict_keys) == 1: + key = _decode_attribute_map_key(dict_keys[0]) + break + working_key = _decode_attribute_map_key(dict_keys[0]) + working_data = attribute_key_case_insensitive_extractor(working_key, None, working_data) + if working_data is None: + # If at any point while following flatten JSON path see None, it means + # that all properties under are None as well + return None + key = ".".join(dict_keys[1:]) + + if working_data: + return attribute_key_case_insensitive_extractor(key, None, working_data) + + +def last_rest_key_extractor(attr, attr_desc, data): # pylint: disable=unused-argument + """Extract the attribute in "data" based on the last part of the JSON path key. + + :param str attr: The attribute to extract + :param dict attr_desc: The attribute description + :param dict data: The data to extract from + :rtype: object + :returns: The extracted attribute + """ + key = attr_desc["key"] + dict_keys = _FLATTEN.split(key) + return attribute_key_extractor(dict_keys[-1], None, data) + + +def last_rest_key_case_insensitive_extractor(attr, attr_desc, data): # pylint: disable=unused-argument + """Extract the attribute in "data" based on the last part of the JSON path key. + + This is the case insensitive version of "last_rest_key_extractor" + :param str attr: The attribute to extract + :param dict attr_desc: The attribute description + :param dict data: The data to extract from + :rtype: object + :returns: The extracted attribute + """ + key = attr_desc["key"] + dict_keys = _FLATTEN.split(key) + return attribute_key_case_insensitive_extractor(dict_keys[-1], None, data) + + +def attribute_key_extractor(attr, _, data): + return data.get(attr) + + +def attribute_key_case_insensitive_extractor(attr, _, data): + found_key = None + lower_attr = attr.lower() + for key in data: + if lower_attr == key.lower(): + found_key = key + break + + return data.get(found_key) + + +def _extract_name_from_internal_type(internal_type): + """Given an internal type XML description, extract correct XML name with namespace. + + :param dict internal_type: An model type + :rtype: tuple + :returns: A tuple XML name + namespace dict + """ + internal_type_xml_map = getattr(internal_type, "_xml_map", {}) + xml_name = internal_type_xml_map.get("name", internal_type.__name__) + xml_ns = internal_type_xml_map.get("ns", None) + if xml_ns: + xml_name = "{{{}}}{}".format(xml_ns, xml_name) + return xml_name + + +def xml_key_extractor(attr, attr_desc, data): # pylint: disable=unused-argument,too-many-return-statements + if isinstance(data, dict): + return None + + # Test if this model is XML ready first + if not isinstance(data, ET.Element): + return None + + xml_desc = attr_desc.get("xml", {}) + xml_name = xml_desc.get("name", attr_desc["key"]) + + # Look for a children + is_iter_type = attr_desc["type"].startswith("[") + is_wrapped = xml_desc.get("wrapped", False) + internal_type = attr_desc.get("internalType", None) + internal_type_xml_map = getattr(internal_type, "_xml_map", {}) + + # Integrate namespace if necessary + xml_ns = xml_desc.get("ns", internal_type_xml_map.get("ns", None)) + if xml_ns: + xml_name = "{{{}}}{}".format(xml_ns, xml_name) + + # If it's an attribute, that's simple + if xml_desc.get("attr", False): + return data.get(xml_name) + + # If it's x-ms-text, that's simple too + if xml_desc.get("text", False): + return data.text + + # Scenario where I take the local name: + # - Wrapped node + # - Internal type is an enum (considered basic types) + # - Internal type has no XML/Name node + if is_wrapped or (internal_type and (issubclass(internal_type, Enum) or "name" not in internal_type_xml_map)): + children = data.findall(xml_name) + # If internal type has a local name and it's not a list, I use that name + elif not is_iter_type and internal_type and "name" in internal_type_xml_map: + xml_name = _extract_name_from_internal_type(internal_type) + children = data.findall(xml_name) + # That's an array + else: + if internal_type: # Complex type, ignore itemsName and use the complex type name + items_name = _extract_name_from_internal_type(internal_type) + else: + items_name = xml_desc.get("itemsName", xml_name) + children = data.findall(items_name) + + if len(children) == 0: + if is_iter_type: + if is_wrapped: + return None # is_wrapped no node, we want None + return [] # not wrapped, assume empty list + return None # Assume it's not there, maybe an optional node. + + # If is_iter_type and not wrapped, return all found children + if is_iter_type: + if not is_wrapped: + return children + # Iter and wrapped, should have found one node only (the wrap one) + if len(children) != 1: + raise DeserializationError( + "Tried to deserialize an array not wrapped, and found several nodes '{}'. Maybe you should declare this array as wrapped?".format( + xml_name + ) + ) + return list(children[0]) # Might be empty list and that's ok. + + # Here it's not a itertype, we should have found one element only or empty + if len(children) > 1: + raise DeserializationError("Find several XML '{}' where it was not expected".format(xml_name)) + return children[0] + + +class Deserializer: + """Response object model deserializer. + + :param dict classes: Class type dictionary for deserializing complex types. + :ivar list key_extractors: Ordered list of extractors to be used by this deserializer. + """ + + basic_types = {str: "str", int: "int", bool: "bool", float: "float"} + + valid_date = re.compile(r"\d{4}[-]\d{2}[-]\d{2}T\d{2}:\d{2}:\d{2}\.?\d*Z?[-+]?[\d{2}]?:?[\d{2}]?") + + def __init__(self, classes: Optional[Mapping[str, type]] = None) -> None: + self.deserialize_type = { + "iso-8601": Deserializer.deserialize_iso, + "rfc-1123": Deserializer.deserialize_rfc, + "unix-time": Deserializer.deserialize_unix, + "duration": Deserializer.deserialize_duration, + "date": Deserializer.deserialize_date, + "time": Deserializer.deserialize_time, + "decimal": Deserializer.deserialize_decimal, + "long": Deserializer.deserialize_long, + "bytearray": Deserializer.deserialize_bytearray, + "base64": Deserializer.deserialize_base64, + "object": self.deserialize_object, + "[]": self.deserialize_iter, + "{}": self.deserialize_dict, + } + self.deserialize_expected_types = { + "duration": (isodate.Duration, datetime.timedelta), + "iso-8601": (datetime.datetime), + } + self.dependencies: Dict[str, type] = dict(classes) if classes else {} + self.key_extractors = [rest_key_extractor, xml_key_extractor] + # Additional properties only works if the "rest_key_extractor" is used to + # extract the keys. Making it to work whatever the key extractor is too much + # complicated, with no real scenario for now. + # So adding a flag to disable additional properties detection. This flag should be + # used if your expect the deserialization to NOT come from a JSON REST syntax. + # Otherwise, result are unexpected + self.additional_properties_detection = True + + def __call__(self, target_obj, response_data, content_type=None): + """Call the deserializer to process a REST response. + + :param str target_obj: Target data type to deserialize to. + :param requests.Response response_data: REST response object. + :param str content_type: Swagger "produces" if available. + :raises DeserializationError: if deserialization fails. + :return: Deserialized object. + :rtype: object + """ + data = self._unpack_content(response_data, content_type) + return self._deserialize(target_obj, data) + + def _deserialize(self, target_obj, data): # pylint: disable=inconsistent-return-statements + """Call the deserializer on a model. + + Data needs to be already deserialized as JSON or XML ElementTree + + :param str target_obj: Target data type to deserialize to. + :param object data: Object to deserialize. + :raises DeserializationError: if deserialization fails. + :return: Deserialized object. + :rtype: object + """ + # This is already a model, go recursive just in case + if hasattr(data, "_attribute_map"): + constants = [name for name, config in getattr(data, "_validation", {}).items() if config.get("constant")] + try: + for attr, mapconfig in data._attribute_map.items(): # pylint: disable=protected-access + if attr in constants: + continue + value = getattr(data, attr) + if value is None: + continue + local_type = mapconfig["type"] + internal_data_type = local_type.strip("[]{}") + if internal_data_type not in self.dependencies or isinstance(internal_data_type, Enum): + continue + setattr(data, attr, self._deserialize(local_type, value)) + return data + except AttributeError: + return + + response, class_name = self._classify_target(target_obj, data) + + if isinstance(response, str): + return self.deserialize_data(data, response) + if isinstance(response, type) and issubclass(response, Enum): + return self.deserialize_enum(data, response) + + if data is None or data is CoreNull: + return data + try: + attributes = response._attribute_map # type: ignore # pylint: disable=protected-access + d_attrs = {} + for attr, attr_desc in attributes.items(): + # Check empty string. If it's not empty, someone has a real "additionalProperties"... + if attr == "additional_properties" and attr_desc["key"] == "": + continue + raw_value = None + # Enhance attr_desc with some dynamic data + attr_desc = attr_desc.copy() # Do a copy, do not change the real one + internal_data_type = attr_desc["type"].strip("[]{}") + if internal_data_type in self.dependencies: + attr_desc["internalType"] = self.dependencies[internal_data_type] + + for key_extractor in self.key_extractors: + found_value = key_extractor(attr, attr_desc, data) + if found_value is not None: + if raw_value is not None and raw_value != found_value: + msg = ( + "Ignoring extracted value '%s' from %s for key '%s'" + " (duplicate extraction, follow extractors order)" + ) + _LOGGER.warning(msg, found_value, key_extractor, attr) + continue + raw_value = found_value + + value = self.deserialize_data(raw_value, attr_desc["type"]) + d_attrs[attr] = value + except (AttributeError, TypeError, KeyError) as err: + msg = "Unable to deserialize to object: " + class_name # type: ignore + raise DeserializationError(msg) from err + additional_properties = self._build_additional_properties(attributes, data) + return self._instantiate_model(response, d_attrs, additional_properties) + + def _build_additional_properties(self, attribute_map, data): + if not self.additional_properties_detection: + return None + if "additional_properties" in attribute_map and attribute_map.get("additional_properties", {}).get("key") != "": + # Check empty string. If it's not empty, someone has a real "additionalProperties" + return None + if isinstance(data, ET.Element): + data = {el.tag: el.text for el in data} + + known_keys = { + _decode_attribute_map_key(_FLATTEN.split(desc["key"])[0]) + for desc in attribute_map.values() + if desc["key"] != "" + } + present_keys = set(data.keys()) + missing_keys = present_keys - known_keys + return {key: data[key] for key in missing_keys} + + def _classify_target(self, target, data): + """Check to see whether the deserialization target object can + be classified into a subclass. + Once classification has been determined, initialize object. + + :param str target: The target object type to deserialize to. + :param str/dict data: The response data to deserialize. + :return: The classified target object and its class name. + :rtype: tuple + """ + if target is None: + return None, None + + if isinstance(target, str): + try: + target = self.dependencies[target] + except KeyError: + return target, target + + try: + target = target._classify(data, self.dependencies) # type: ignore # pylint: disable=protected-access + except AttributeError: + pass # Target is not a Model, no classify + return target, target.__class__.__name__ # type: ignore + + def failsafe_deserialize(self, target_obj, data, content_type=None): + """Ignores any errors encountered in deserialization, + and falls back to not deserializing the object. Recommended + for use in error deserialization, as we want to return the + HttpResponseError to users, and not have them deal with + a deserialization error. + + :param str target_obj: The target object type to deserialize to. + :param str/dict data: The response data to deserialize. + :param str content_type: Swagger "produces" if available. + :return: Deserialized object. + :rtype: object + """ + try: + return self(target_obj, data, content_type=content_type) + except: # pylint: disable=bare-except + _LOGGER.debug( + "Ran into a deserialization error. Ignoring since this is failsafe deserialization", exc_info=True + ) + return None + + @staticmethod + def _unpack_content(raw_data, content_type=None): + """Extract the correct structure for deserialization. + + If raw_data is a PipelineResponse, try to extract the result of RawDeserializer. + if we can't, raise. Your Pipeline should have a RawDeserializer. + + If not a pipeline response and raw_data is bytes or string, use content-type + to decode it. If no content-type, try JSON. + + If raw_data is something else, bypass all logic and return it directly. + + :param obj raw_data: Data to be processed. + :param str content_type: How to parse if raw_data is a string/bytes. + :raises JSONDecodeError: If JSON is requested and parsing is impossible. + :raises UnicodeDecodeError: If bytes is not UTF8 + :rtype: object + :return: Unpacked content. + """ + # Assume this is enough to detect a Pipeline Response without importing it + context = getattr(raw_data, "context", {}) + if context: + if RawDeserializer.CONTEXT_NAME in context: + return context[RawDeserializer.CONTEXT_NAME] + raise ValueError("This pipeline didn't have the RawDeserializer policy; can't deserialize") + + # Assume this is enough to recognize universal_http.ClientResponse without importing it + if hasattr(raw_data, "body"): + return RawDeserializer.deserialize_from_http_generics(raw_data.text(), raw_data.headers) + + # Assume this enough to recognize requests.Response without importing it. + if hasattr(raw_data, "_content_consumed"): + return RawDeserializer.deserialize_from_http_generics(raw_data.text, raw_data.headers) + + if isinstance(raw_data, (str, bytes)) or hasattr(raw_data, "read"): + return RawDeserializer.deserialize_from_text(raw_data, content_type) # type: ignore + return raw_data + + def _instantiate_model(self, response, attrs, additional_properties=None): + """Instantiate a response model passing in deserialized args. + + :param Response response: The response model class. + :param dict attrs: The deserialized response attributes. + :param dict additional_properties: Additional properties to be set. + :rtype: Response + :return: The instantiated response model. + """ + if callable(response): + subtype = getattr(response, "_subtype_map", {}) + try: + readonly = [ + k + for k, v in response._validation.items() # pylint: disable=protected-access # type: ignore + if v.get("readonly") + ] + const = [ + k + for k, v in response._validation.items() # pylint: disable=protected-access # type: ignore + if v.get("constant") + ] + kwargs = {k: v for k, v in attrs.items() if k not in subtype and k not in readonly + const} + response_obj = response(**kwargs) + for attr in readonly: + setattr(response_obj, attr, attrs.get(attr)) + if additional_properties: + response_obj.additional_properties = additional_properties # type: ignore + return response_obj + except TypeError as err: + msg = "Unable to deserialize {} into model {}. ".format(kwargs, response) # type: ignore + raise DeserializationError(msg + str(err)) from err + else: + try: + for attr, value in attrs.items(): + setattr(response, attr, value) + return response + except Exception as exp: + msg = "Unable to populate response model. " + msg += "Type: {}, Error: {}".format(type(response), exp) + raise DeserializationError(msg) from exp + + def deserialize_data(self, data, data_type): # pylint: disable=too-many-return-statements + """Process data for deserialization according to data type. + + :param str data: The response string to be deserialized. + :param str data_type: The type to deserialize to. + :raises DeserializationError: if deserialization fails. + :return: Deserialized object. + :rtype: object + """ + if data is None: + return data + + try: + if not data_type: + return data + if data_type in self.basic_types.values(): + return self.deserialize_basic(data, data_type) + if data_type in self.deserialize_type: + if isinstance(data, self.deserialize_expected_types.get(data_type, tuple())): + return data + + is_a_text_parsing_type = lambda x: x not in [ # pylint: disable=unnecessary-lambda-assignment + "object", + "[]", + r"{}", + ] + if isinstance(data, ET.Element) and is_a_text_parsing_type(data_type) and not data.text: + return None + data_val = self.deserialize_type[data_type](data) + return data_val + + iter_type = data_type[0] + data_type[-1] + if iter_type in self.deserialize_type: + return self.deserialize_type[iter_type](data, data_type[1:-1]) + + obj_type = self.dependencies[data_type] + if issubclass(obj_type, Enum): + if isinstance(data, ET.Element): + data = data.text + return self.deserialize_enum(data, obj_type) + + except (ValueError, TypeError, AttributeError) as err: + msg = "Unable to deserialize response data." + msg += " Data: {}, {}".format(data, data_type) + raise DeserializationError(msg) from err + return self._deserialize(obj_type, data) + + def deserialize_iter(self, attr, iter_type): + """Deserialize an iterable. + + :param list attr: Iterable to be deserialized. + :param str iter_type: The type of object in the iterable. + :return: Deserialized iterable. + :rtype: list + """ + if attr is None: + return None + if isinstance(attr, ET.Element): # If I receive an element here, get the children + attr = list(attr) + if not isinstance(attr, (list, set)): + raise DeserializationError("Cannot deserialize as [{}] an object of type {}".format(iter_type, type(attr))) + return [self.deserialize_data(a, iter_type) for a in attr] + + def deserialize_dict(self, attr, dict_type): + """Deserialize a dictionary. + + :param dict/list attr: Dictionary to be deserialized. Also accepts + a list of key, value pairs. + :param str dict_type: The object type of the items in the dictionary. + :return: Deserialized dictionary. + :rtype: dict + """ + if isinstance(attr, list): + return {x["key"]: self.deserialize_data(x["value"], dict_type) for x in attr} + + if isinstance(attr, ET.Element): + # Transform value into {"Key": "value"} + attr = {el.tag: el.text for el in attr} + return {k: self.deserialize_data(v, dict_type) for k, v in attr.items()} + + def deserialize_object(self, attr, **kwargs): # pylint: disable=too-many-return-statements + """Deserialize a generic object. + This will be handled as a dictionary. + + :param dict attr: Dictionary to be deserialized. + :return: Deserialized object. + :rtype: dict + :raises TypeError: if non-builtin datatype encountered. + """ + if attr is None: + return None + if isinstance(attr, ET.Element): + # Do no recurse on XML, just return the tree as-is + return attr + if isinstance(attr, str): + return self.deserialize_basic(attr, "str") + obj_type = type(attr) + if obj_type in self.basic_types: + return self.deserialize_basic(attr, self.basic_types[obj_type]) + if obj_type is _long_type: + return self.deserialize_long(attr) + + if obj_type == dict: + deserialized = {} + for key, value in attr.items(): + try: + deserialized[key] = self.deserialize_object(value, **kwargs) + except ValueError: + deserialized[key] = None + return deserialized + + if obj_type == list: + deserialized = [] + for obj in attr: + try: + deserialized.append(self.deserialize_object(obj, **kwargs)) + except ValueError: + pass + return deserialized + + error = "Cannot deserialize generic object with type: " + raise TypeError(error + str(obj_type)) + + def deserialize_basic(self, attr, data_type): # pylint: disable=too-many-return-statements + """Deserialize basic builtin data type from string. + Will attempt to convert to str, int, float and bool. + This function will also accept '1', '0', 'true' and 'false' as + valid bool values. + + :param str attr: response string to be deserialized. + :param str data_type: deserialization data type. + :return: Deserialized basic type. + :rtype: str, int, float or bool + :raises TypeError: if string format is not valid. + """ + # If we're here, data is supposed to be a basic type. + # If it's still an XML node, take the text + if isinstance(attr, ET.Element): + attr = attr.text + if not attr: + if data_type == "str": + # None or '', node is empty string. + return "" + # None or '', node with a strong type is None. + # Don't try to model "empty bool" or "empty int" + return None + + if data_type == "bool": + if attr in [True, False, 1, 0]: + return bool(attr) + if isinstance(attr, str): + if attr.lower() in ["true", "1"]: + return True + if attr.lower() in ["false", "0"]: + return False + raise TypeError("Invalid boolean value: {}".format(attr)) + + if data_type == "str": + return self.deserialize_unicode(attr) + return eval(data_type)(attr) # nosec # pylint: disable=eval-used + + @staticmethod + def deserialize_unicode(data): + """Preserve unicode objects in Python 2, otherwise return data + as a string. + + :param str data: response string to be deserialized. + :return: Deserialized string. + :rtype: str or unicode + """ + # We might be here because we have an enum modeled as string, + # and we try to deserialize a partial dict with enum inside + if isinstance(data, Enum): + return data + + # Consider this is real string + try: + if isinstance(data, unicode): # type: ignore + return data + except NameError: + return str(data) + return str(data) + + @staticmethod + def deserialize_enum(data, enum_obj): + """Deserialize string into enum object. + + If the string is not a valid enum value it will be returned as-is + and a warning will be logged. + + :param str data: Response string to be deserialized. If this value is + None or invalid it will be returned as-is. + :param Enum enum_obj: Enum object to deserialize to. + :return: Deserialized enum object. + :rtype: Enum + """ + if isinstance(data, enum_obj) or data is None: + return data + if isinstance(data, Enum): + data = data.value + if isinstance(data, int): + # Workaround. We might consider remove it in the future. + try: + return list(enum_obj.__members__.values())[data] + except IndexError as exc: + error = "{!r} is not a valid index for enum {!r}" + raise DeserializationError(error.format(data, enum_obj)) from exc + try: + return enum_obj(str(data)) + except ValueError: + for enum_value in enum_obj: + if enum_value.value.lower() == str(data).lower(): + return enum_value + # We don't fail anymore for unknown value, we deserialize as a string + _LOGGER.warning("Deserializer is not able to find %s as valid enum in %s", data, enum_obj) + return Deserializer.deserialize_unicode(data) + + @staticmethod + def deserialize_bytearray(attr): + """Deserialize string into bytearray. + + :param str attr: response string to be deserialized. + :return: Deserialized bytearray + :rtype: bytearray + :raises TypeError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + return bytearray(b64decode(attr)) # type: ignore + + @staticmethod + def deserialize_base64(attr): + """Deserialize base64 encoded string into string. + + :param str attr: response string to be deserialized. + :return: Deserialized base64 string + :rtype: bytearray + :raises TypeError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + padding = "=" * (3 - (len(attr) + 3) % 4) # type: ignore + attr = attr + padding # type: ignore + encoded = attr.replace("-", "+").replace("_", "/") + return b64decode(encoded) + + @staticmethod + def deserialize_decimal(attr): + """Deserialize string into Decimal object. + + :param str attr: response string to be deserialized. + :return: Deserialized decimal + :raises DeserializationError: if string format invalid. + :rtype: decimal + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + return decimal.Decimal(str(attr)) # type: ignore + except decimal.DecimalException as err: + msg = "Invalid decimal {}".format(attr) + raise DeserializationError(msg) from err + + @staticmethod + def deserialize_long(attr): + """Deserialize string into long (Py2) or int (Py3). + + :param str attr: response string to be deserialized. + :return: Deserialized int + :rtype: long or int + :raises ValueError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + return _long_type(attr) # type: ignore + + @staticmethod + def deserialize_duration(attr): + """Deserialize ISO-8601 formatted string into TimeDelta object. + + :param str attr: response string to be deserialized. + :return: Deserialized duration + :rtype: TimeDelta + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + duration = isodate.parse_duration(attr) + except (ValueError, OverflowError, AttributeError) as err: + msg = "Cannot deserialize duration object." + raise DeserializationError(msg) from err + return duration + + @staticmethod + def deserialize_date(attr): + """Deserialize ISO-8601 formatted string into Date object. + + :param str attr: response string to be deserialized. + :return: Deserialized date + :rtype: Date + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + if re.search(r"[^\W\d_]", attr, re.I + re.U): # type: ignore + raise DeserializationError("Date must have only digits and -. Received: %s" % attr) + # This must NOT use defaultmonth/defaultday. Using None ensure this raises an exception. + return isodate.parse_date(attr, defaultmonth=0, defaultday=0) + + @staticmethod + def deserialize_time(attr): + """Deserialize ISO-8601 formatted string into time object. + + :param str attr: response string to be deserialized. + :return: Deserialized time + :rtype: datetime.time + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + if re.search(r"[^\W\d_]", attr, re.I + re.U): # type: ignore + raise DeserializationError("Date must have only digits and -. Received: %s" % attr) + return isodate.parse_time(attr) + + @staticmethod + def deserialize_rfc(attr): + """Deserialize RFC-1123 formatted string into Datetime object. + + :param str attr: response string to be deserialized. + :return: Deserialized RFC datetime + :rtype: Datetime + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + parsed_date = email.utils.parsedate_tz(attr) # type: ignore + date_obj = datetime.datetime( + *parsed_date[:6], tzinfo=datetime.timezone(datetime.timedelta(minutes=(parsed_date[9] or 0) / 60)) + ) + if not date_obj.tzinfo: + date_obj = date_obj.astimezone(tz=TZ_UTC) + except ValueError as err: + msg = "Cannot deserialize to rfc datetime object." + raise DeserializationError(msg) from err + return date_obj + + @staticmethod + def deserialize_iso(attr): + """Deserialize ISO-8601 formatted string into Datetime object. + + :param str attr: response string to be deserialized. + :return: Deserialized ISO datetime + :rtype: Datetime + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + attr = attr.upper() # type: ignore + match = Deserializer.valid_date.match(attr) + if not match: + raise ValueError("Invalid datetime string: " + attr) + + check_decimal = attr.split(".") + if len(check_decimal) > 1: + decimal_str = "" + for digit in check_decimal[1]: + if digit.isdigit(): + decimal_str += digit + else: + break + if len(decimal_str) > 6: + attr = attr.replace(decimal_str, decimal_str[0:6]) + + date_obj = isodate.parse_datetime(attr) + test_utc = date_obj.utctimetuple() + if test_utc.tm_year > 9999 or test_utc.tm_year < 1: + raise OverflowError("Hit max or min date") + except (ValueError, OverflowError, AttributeError) as err: + msg = "Cannot deserialize datetime object." + raise DeserializationError(msg) from err + return date_obj + + @staticmethod + def deserialize_unix(attr): + """Serialize Datetime object into IntTime format. + This is represented as seconds. + + :param int attr: Object to be serialized. + :return: Deserialized datetime + :rtype: Datetime + :raises DeserializationError: if format invalid + """ + if isinstance(attr, ET.Element): + attr = int(attr.text) # type: ignore + try: + attr = int(attr) + date_obj = datetime.datetime.fromtimestamp(attr, TZ_UTC) + except ValueError as err: + msg = "Cannot deserialize to unix datetime object." + raise DeserializationError(msg) from err + return date_obj diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ObjectTypeVersionTolerant/objecttypeversiontolerant/_utils/utils.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ObjectTypeVersionTolerant/objecttypeversiontolerant/_utils/utils.py new file mode 100644 index 00000000000..39b612f39a9 --- /dev/null +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ObjectTypeVersionTolerant/objecttypeversiontolerant/_utils/utils.py @@ -0,0 +1,25 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from abc import ABC +from typing import Generic, TYPE_CHECKING, TypeVar + +if TYPE_CHECKING: + from .serialization import Deserializer, Serializer + + +TClient = TypeVar("TClient") +TConfig = TypeVar("TConfig") + + +class ClientMixinABC(ABC, Generic[TClient, TConfig]): + """DO NOT use this class. It is for internal typing use only.""" + + _client: TClient + _config: TConfig + _serialize: "Serializer" + _deserialize: "Deserializer" diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ObjectTypeVersionTolerant/objecttypeversiontolerant/_vendor.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ObjectTypeVersionTolerant/objecttypeversiontolerant/_vendor.py deleted file mode 100644 index e42ff8bdaa8..00000000000 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ObjectTypeVersionTolerant/objecttypeversiontolerant/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) AutoRest Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import ObjectTypeClientConfiguration - -if TYPE_CHECKING: - from azure.core import PipelineClient - - from ._serialization import Deserializer, Serializer - - -class ObjectTypeClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "PipelineClient" - _config: ObjectTypeClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ObjectTypeVersionTolerant/objecttypeversiontolerant/aio/_client.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ObjectTypeVersionTolerant/objecttypeversiontolerant/aio/_client.py index 10fd69da942..60cdb27115d 100644 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ObjectTypeVersionTolerant/objecttypeversiontolerant/aio/_client.py +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ObjectTypeVersionTolerant/objecttypeversiontolerant/aio/_client.py @@ -14,7 +14,7 @@ from azure.core.pipeline import policies from azure.core.rest import AsyncHttpResponse, HttpRequest -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import ObjectTypeClientConfiguration from ._operations import ObjectTypeClientOperationsMixin diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ObjectTypeVersionTolerant/objecttypeversiontolerant/aio/_operations/_operations.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ObjectTypeVersionTolerant/objecttypeversiontolerant/aio/_operations/_operations.py index 16d74bf5bd9..cef4310bd73 100644 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ObjectTypeVersionTolerant/objecttypeversiontolerant/aio/_operations/_operations.py +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ObjectTypeVersionTolerant/objecttypeversiontolerant/aio/_operations/_operations.py @@ -9,6 +9,7 @@ from collections.abc import MutableMapping from typing import Any, Callable, Dict, Optional, TypeVar, cast +from azure.core import AsyncPipelineClient from azure.core.exceptions import ( ClientAuthenticationError, HttpResponseError, @@ -23,14 +24,15 @@ from azure.core.utils import case_insensitive_dict from ..._operations._operations import build_object_type_get_request, build_object_type_put_request -from .._vendor import ObjectTypeClientMixinABC +from ..._utils.utils import ClientMixinABC +from .._configuration import ObjectTypeClientConfiguration JSON = MutableMapping[str, Any] T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, AsyncHttpResponse], T, Dict[str, Any]], Any]] -class ObjectTypeClientOperationsMixin(ObjectTypeClientMixinABC): +class ObjectTypeClientOperationsMixin(ClientMixinABC[AsyncPipelineClient, ObjectTypeClientConfiguration]): @distributed_trace_async async def get(self, **kwargs: Any) -> JSON: diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ObjectTypeVersionTolerant/objecttypeversiontolerant/aio/_vendor.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ObjectTypeVersionTolerant/objecttypeversiontolerant/aio/_vendor.py deleted file mode 100644 index 7773f545cb3..00000000000 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ObjectTypeVersionTolerant/objecttypeversiontolerant/aio/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) AutoRest Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import ObjectTypeClientConfiguration - -if TYPE_CHECKING: - from azure.core import AsyncPipelineClient - - from .._serialization import Deserializer, Serializer - - -class ObjectTypeClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "AsyncPipelineClient" - _config: ObjectTypeClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ParameterFlatteningVersionTolerant/parameterflatteningversiontolerant/_client.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ParameterFlatteningVersionTolerant/parameterflatteningversiontolerant/_client.py index d0f99102694..0cfbc79a9ed 100644 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ParameterFlatteningVersionTolerant/parameterflatteningversiontolerant/_client.py +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ParameterFlatteningVersionTolerant/parameterflatteningversiontolerant/_client.py @@ -15,7 +15,7 @@ from azure.core.rest import HttpRequest, HttpResponse from ._configuration import AutoRestParameterFlatteningConfiguration -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer from .operations import AvailabilitySetsOperations diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ParameterFlatteningVersionTolerant/parameterflatteningversiontolerant/_utils/__init__.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ParameterFlatteningVersionTolerant/parameterflatteningversiontolerant/_utils/__init__.py new file mode 100644 index 00000000000..0af9b28f660 --- /dev/null +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ParameterFlatteningVersionTolerant/parameterflatteningversiontolerant/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ParameterFlatteningVersionTolerant/parameterflatteningversiontolerant/_utils/serialization.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ParameterFlatteningVersionTolerant/parameterflatteningversiontolerant/_utils/serialization.py new file mode 100644 index 00000000000..f5187701d7b --- /dev/null +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ParameterFlatteningVersionTolerant/parameterflatteningversiontolerant/_utils/serialization.py @@ -0,0 +1,2032 @@ +# pylint: disable=line-too-long,useless-suppression,too-many-lines +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +# pyright: reportUnnecessaryTypeIgnoreComment=false + +from base64 import b64decode, b64encode +import calendar +import datetime +import decimal +import email +from enum import Enum +import json +import logging +import re +import sys +import codecs +from typing import ( + Dict, + Any, + cast, + Optional, + Union, + AnyStr, + IO, + Mapping, + Callable, + MutableMapping, + List, +) + +try: + from urllib import quote # type: ignore +except ImportError: + from urllib.parse import quote +import xml.etree.ElementTree as ET + +import isodate # type: ignore +from typing_extensions import Self + +from azure.core.exceptions import DeserializationError, SerializationError +from azure.core.serialization import NULL as CoreNull + +_BOM = codecs.BOM_UTF8.decode(encoding="utf-8") + +JSON = MutableMapping[str, Any] + + +class RawDeserializer: + + # Accept "text" because we're open minded people... + JSON_REGEXP = re.compile(r"^(application|text)/([a-z+.]+\+)?json$") + + # Name used in context + CONTEXT_NAME = "deserialized_data" + + @classmethod + def deserialize_from_text(cls, data: Optional[Union[AnyStr, IO]], content_type: Optional[str] = None) -> Any: + """Decode data according to content-type. + + Accept a stream of data as well, but will be load at once in memory for now. + + If no content-type, will return the string version (not bytes, not stream) + + :param data: Input, could be bytes or stream (will be decoded with UTF8) or text + :type data: str or bytes or IO + :param str content_type: The content type. + :return: The deserialized data. + :rtype: object + """ + if hasattr(data, "read"): + # Assume a stream + data = cast(IO, data).read() + + if isinstance(data, bytes): + data_as_str = data.decode(encoding="utf-8-sig") + else: + # Explain to mypy the correct type. + data_as_str = cast(str, data) + + # Remove Byte Order Mark if present in string + data_as_str = data_as_str.lstrip(_BOM) + + if content_type is None: + return data + + if cls.JSON_REGEXP.match(content_type): + try: + return json.loads(data_as_str) + except ValueError as err: + raise DeserializationError("JSON is invalid: {}".format(err), err) from err + elif "xml" in (content_type or []): + try: + + try: + if isinstance(data, unicode): # type: ignore + # If I'm Python 2.7 and unicode XML will scream if I try a "fromstring" on unicode string + data_as_str = data_as_str.encode(encoding="utf-8") # type: ignore + except NameError: + pass + + return ET.fromstring(data_as_str) # nosec + except ET.ParseError as err: + # It might be because the server has an issue, and returned JSON with + # content-type XML.... + # So let's try a JSON load, and if it's still broken + # let's flow the initial exception + def _json_attemp(data): + try: + return True, json.loads(data) + except ValueError: + return False, None # Don't care about this one + + success, json_result = _json_attemp(data) + if success: + return json_result + # If i'm here, it's not JSON, it's not XML, let's scream + # and raise the last context in this block (the XML exception) + # The function hack is because Py2.7 messes up with exception + # context otherwise. + _LOGGER.critical("Wasn't XML not JSON, failing") + raise DeserializationError("XML is invalid") from err + elif content_type.startswith("text/"): + return data_as_str + raise DeserializationError("Cannot deserialize content-type: {}".format(content_type)) + + @classmethod + def deserialize_from_http_generics(cls, body_bytes: Optional[Union[AnyStr, IO]], headers: Mapping) -> Any: + """Deserialize from HTTP response. + + Use bytes and headers to NOT use any requests/aiohttp or whatever + specific implementation. + Headers will tested for "content-type" + + :param bytes body_bytes: The body of the response. + :param dict headers: The headers of the response. + :returns: The deserialized data. + :rtype: object + """ + # Try to use content-type from headers if available + content_type = None + if "content-type" in headers: + content_type = headers["content-type"].split(";")[0].strip().lower() + # Ouch, this server did not declare what it sent... + # Let's guess it's JSON... + # Also, since Autorest was considering that an empty body was a valid JSON, + # need that test as well.... + else: + content_type = "application/json" + + if body_bytes: + return cls.deserialize_from_text(body_bytes, content_type) + return None + + +_LOGGER = logging.getLogger(__name__) + +try: + _long_type = long # type: ignore +except NameError: + _long_type = int + +TZ_UTC = datetime.timezone.utc + +_FLATTEN = re.compile(r"(? None: + self.additional_properties: Optional[Dict[str, Any]] = {} + for k in kwargs: # pylint: disable=consider-using-dict-items + if k not in self._attribute_map: + _LOGGER.warning("%s is not a known attribute of class %s and will be ignored", k, self.__class__) + elif k in self._validation and self._validation[k].get("readonly", False): + _LOGGER.warning("Readonly attribute %s will be ignored in class %s", k, self.__class__) + else: + setattr(self, k, kwargs[k]) + + def __eq__(self, other: Any) -> bool: + """Compare objects by comparing all attributes. + + :param object other: The object to compare + :returns: True if objects are equal + :rtype: bool + """ + if isinstance(other, self.__class__): + return self.__dict__ == other.__dict__ + return False + + def __ne__(self, other: Any) -> bool: + """Compare objects by comparing all attributes. + + :param object other: The object to compare + :returns: True if objects are not equal + :rtype: bool + """ + return not self.__eq__(other) + + def __str__(self) -> str: + return str(self.__dict__) + + @classmethod + def enable_additional_properties_sending(cls) -> None: + cls._attribute_map["additional_properties"] = {"key": "", "type": "{object}"} + + @classmethod + def is_xml_model(cls) -> bool: + try: + cls._xml_map # type: ignore + except AttributeError: + return False + return True + + @classmethod + def _create_xml_node(cls): + """Create XML node. + + :returns: The XML node + :rtype: xml.etree.ElementTree.Element + """ + try: + xml_map = cls._xml_map # type: ignore + except AttributeError: + xml_map = {} + + return _create_xml_node(xml_map.get("name", cls.__name__), xml_map.get("prefix", None), xml_map.get("ns", None)) + + def serialize(self, keep_readonly: bool = False, **kwargs: Any) -> JSON: + """Return the JSON that would be sent to server from this model. + + This is an alias to `as_dict(full_restapi_key_transformer, keep_readonly=False)`. + + If you want XML serialization, you can pass the kwargs is_xml=True. + + :param bool keep_readonly: If you want to serialize the readonly attributes + :returns: A dict JSON compatible object + :rtype: dict + """ + serializer = Serializer(self._infer_class_models()) + return serializer._serialize( # type: ignore # pylint: disable=protected-access + self, keep_readonly=keep_readonly, **kwargs + ) + + def as_dict( + self, + keep_readonly: bool = True, + key_transformer: Callable[[str, Dict[str, Any], Any], Any] = attribute_transformer, + **kwargs: Any + ) -> JSON: + """Return a dict that can be serialized using json.dump. + + Advanced usage might optionally use a callback as parameter: + + .. code::python + + def my_key_transformer(key, attr_desc, value): + return key + + Key is the attribute name used in Python. Attr_desc + is a dict of metadata. Currently contains 'type' with the + msrest type and 'key' with the RestAPI encoded key. + Value is the current value in this object. + + The string returned will be used to serialize the key. + If the return type is a list, this is considered hierarchical + result dict. + + See the three examples in this file: + + - attribute_transformer + - full_restapi_key_transformer + - last_restapi_key_transformer + + If you want XML serialization, you can pass the kwargs is_xml=True. + + :param bool keep_readonly: If you want to serialize the readonly attributes + :param function key_transformer: A key transformer function. + :returns: A dict JSON compatible object + :rtype: dict + """ + serializer = Serializer(self._infer_class_models()) + return serializer._serialize( # type: ignore # pylint: disable=protected-access + self, key_transformer=key_transformer, keep_readonly=keep_readonly, **kwargs + ) + + @classmethod + def _infer_class_models(cls): + try: + str_models = cls.__module__.rsplit(".", 1)[0] + models = sys.modules[str_models] + client_models = {k: v for k, v in models.__dict__.items() if isinstance(v, type)} + if cls.__name__ not in client_models: + raise ValueError("Not Autorest generated code") + except Exception: # pylint: disable=broad-exception-caught + # Assume it's not Autorest generated (tests?). Add ourselves as dependencies. + client_models = {cls.__name__: cls} + return client_models + + @classmethod + def deserialize(cls, data: Any, content_type: Optional[str] = None) -> Self: + """Parse a str using the RestAPI syntax and return a model. + + :param str data: A str using RestAPI structure. JSON by default. + :param str content_type: JSON by default, set application/xml if XML. + :returns: An instance of this model + :raises DeserializationError: if something went wrong + :rtype: Self + """ + deserializer = Deserializer(cls._infer_class_models()) + return deserializer(cls.__name__, data, content_type=content_type) # type: ignore + + @classmethod + def from_dict( + cls, + data: Any, + key_extractors: Optional[Callable[[str, Dict[str, Any], Any], Any]] = None, + content_type: Optional[str] = None, + ) -> Self: + """Parse a dict using given key extractor return a model. + + By default consider key + extractors (rest_key_case_insensitive_extractor, attribute_key_case_insensitive_extractor + and last_rest_key_case_insensitive_extractor) + + :param dict data: A dict using RestAPI structure + :param function key_extractors: A key extractor function. + :param str content_type: JSON by default, set application/xml if XML. + :returns: An instance of this model + :raises DeserializationError: if something went wrong + :rtype: Self + """ + deserializer = Deserializer(cls._infer_class_models()) + deserializer.key_extractors = ( # type: ignore + [ # type: ignore + attribute_key_case_insensitive_extractor, + rest_key_case_insensitive_extractor, + last_rest_key_case_insensitive_extractor, + ] + if key_extractors is None + else key_extractors + ) + return deserializer(cls.__name__, data, content_type=content_type) # type: ignore + + @classmethod + def _flatten_subtype(cls, key, objects): + if "_subtype_map" not in cls.__dict__: + return {} + result = dict(cls._subtype_map[key]) + for valuetype in cls._subtype_map[key].values(): + result.update(objects[valuetype]._flatten_subtype(key, objects)) # pylint: disable=protected-access + return result + + @classmethod + def _classify(cls, response, objects): + """Check the class _subtype_map for any child classes. + We want to ignore any inherited _subtype_maps. + + :param dict response: The initial data + :param dict objects: The class objects + :returns: The class to be used + :rtype: class + """ + for subtype_key in cls.__dict__.get("_subtype_map", {}).keys(): + subtype_value = None + + if not isinstance(response, ET.Element): + rest_api_response_key = cls._get_rest_key_parts(subtype_key)[-1] + subtype_value = response.get(rest_api_response_key, None) or response.get(subtype_key, None) + else: + subtype_value = xml_key_extractor(subtype_key, cls._attribute_map[subtype_key], response) + if subtype_value: + # Try to match base class. Can be class name only + # (bug to fix in Autorest to support x-ms-discriminator-name) + if cls.__name__ == subtype_value: + return cls + flatten_mapping_type = cls._flatten_subtype(subtype_key, objects) + try: + return objects[flatten_mapping_type[subtype_value]] # type: ignore + except KeyError: + _LOGGER.warning( + "Subtype value %s has no mapping, use base class %s.", + subtype_value, + cls.__name__, + ) + break + else: + _LOGGER.warning("Discriminator %s is absent or null, use base class %s.", subtype_key, cls.__name__) + break + return cls + + @classmethod + def _get_rest_key_parts(cls, attr_key): + """Get the RestAPI key of this attr, split it and decode part + :param str attr_key: Attribute key must be in attribute_map. + :returns: A list of RestAPI part + :rtype: list + """ + rest_split_key = _FLATTEN.split(cls._attribute_map[attr_key]["key"]) + return [_decode_attribute_map_key(key_part) for key_part in rest_split_key] + + +def _decode_attribute_map_key(key): + """This decode a key in an _attribute_map to the actual key we want to look at + inside the received data. + + :param str key: A key string from the generated code + :returns: The decoded key + :rtype: str + """ + return key.replace("\\.", ".") + + +class Serializer: # pylint: disable=too-many-public-methods + """Request object model serializer.""" + + basic_types = {str: "str", int: "int", bool: "bool", float: "float"} + + _xml_basic_types_serializers = {"bool": lambda x: str(x).lower()} + days = {0: "Mon", 1: "Tue", 2: "Wed", 3: "Thu", 4: "Fri", 5: "Sat", 6: "Sun"} + months = { + 1: "Jan", + 2: "Feb", + 3: "Mar", + 4: "Apr", + 5: "May", + 6: "Jun", + 7: "Jul", + 8: "Aug", + 9: "Sep", + 10: "Oct", + 11: "Nov", + 12: "Dec", + } + validation = { + "min_length": lambda x, y: len(x) < y, + "max_length": lambda x, y: len(x) > y, + "minimum": lambda x, y: x < y, + "maximum": lambda x, y: x > y, + "minimum_ex": lambda x, y: x <= y, + "maximum_ex": lambda x, y: x >= y, + "min_items": lambda x, y: len(x) < y, + "max_items": lambda x, y: len(x) > y, + "pattern": lambda x, y: not re.match(y, x, re.UNICODE), + "unique": lambda x, y: len(x) != len(set(x)), + "multiple": lambda x, y: x % y != 0, + } + + def __init__(self, classes: Optional[Mapping[str, type]] = None) -> None: + self.serialize_type = { + "iso-8601": Serializer.serialize_iso, + "rfc-1123": Serializer.serialize_rfc, + "unix-time": Serializer.serialize_unix, + "duration": Serializer.serialize_duration, + "date": Serializer.serialize_date, + "time": Serializer.serialize_time, + "decimal": Serializer.serialize_decimal, + "long": Serializer.serialize_long, + "bytearray": Serializer.serialize_bytearray, + "base64": Serializer.serialize_base64, + "object": self.serialize_object, + "[]": self.serialize_iter, + "{}": self.serialize_dict, + } + self.dependencies: Dict[str, type] = dict(classes) if classes else {} + self.key_transformer = full_restapi_key_transformer + self.client_side_validation = True + + def _serialize( # pylint: disable=too-many-nested-blocks, too-many-branches, too-many-statements, too-many-locals + self, target_obj, data_type=None, **kwargs + ): + """Serialize data into a string according to type. + + :param object target_obj: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str, dict + :raises SerializationError: if serialization fails. + :returns: The serialized data. + """ + key_transformer = kwargs.get("key_transformer", self.key_transformer) + keep_readonly = kwargs.get("keep_readonly", False) + if target_obj is None: + return None + + attr_name = None + class_name = target_obj.__class__.__name__ + + if data_type: + return self.serialize_data(target_obj, data_type, **kwargs) + + if not hasattr(target_obj, "_attribute_map"): + data_type = type(target_obj).__name__ + if data_type in self.basic_types.values(): + return self.serialize_data(target_obj, data_type, **kwargs) + + # Force "is_xml" kwargs if we detect a XML model + try: + is_xml_model_serialization = kwargs["is_xml"] + except KeyError: + is_xml_model_serialization = kwargs.setdefault("is_xml", target_obj.is_xml_model()) + + serialized = {} + if is_xml_model_serialization: + serialized = target_obj._create_xml_node() # pylint: disable=protected-access + try: + attributes = target_obj._attribute_map # pylint: disable=protected-access + for attr, attr_desc in attributes.items(): + attr_name = attr + if not keep_readonly and target_obj._validation.get( # pylint: disable=protected-access + attr_name, {} + ).get("readonly", False): + continue + + if attr_name == "additional_properties" and attr_desc["key"] == "": + if target_obj.additional_properties is not None: + serialized.update(target_obj.additional_properties) + continue + try: + + orig_attr = getattr(target_obj, attr) + if is_xml_model_serialization: + pass # Don't provide "transformer" for XML for now. Keep "orig_attr" + else: # JSON + keys, orig_attr = key_transformer(attr, attr_desc.copy(), orig_attr) + keys = keys if isinstance(keys, list) else [keys] + + kwargs["serialization_ctxt"] = attr_desc + new_attr = self.serialize_data(orig_attr, attr_desc["type"], **kwargs) + + if is_xml_model_serialization: + xml_desc = attr_desc.get("xml", {}) + xml_name = xml_desc.get("name", attr_desc["key"]) + xml_prefix = xml_desc.get("prefix", None) + xml_ns = xml_desc.get("ns", None) + if xml_desc.get("attr", False): + if xml_ns: + ET.register_namespace(xml_prefix, xml_ns) + xml_name = "{{{}}}{}".format(xml_ns, xml_name) + serialized.set(xml_name, new_attr) # type: ignore + continue + if xml_desc.get("text", False): + serialized.text = new_attr # type: ignore + continue + if isinstance(new_attr, list): + serialized.extend(new_attr) # type: ignore + elif isinstance(new_attr, ET.Element): + # If the down XML has no XML/Name, + # we MUST replace the tag with the local tag. But keeping the namespaces. + if "name" not in getattr(orig_attr, "_xml_map", {}): + splitted_tag = new_attr.tag.split("}") + if len(splitted_tag) == 2: # Namespace + new_attr.tag = "}".join([splitted_tag[0], xml_name]) + else: + new_attr.tag = xml_name + serialized.append(new_attr) # type: ignore + else: # That's a basic type + # Integrate namespace if necessary + local_node = _create_xml_node(xml_name, xml_prefix, xml_ns) + local_node.text = str(new_attr) + serialized.append(local_node) # type: ignore + else: # JSON + for k in reversed(keys): # type: ignore + new_attr = {k: new_attr} + + _new_attr = new_attr + _serialized = serialized + for k in keys: # type: ignore + if k not in _serialized: + _serialized.update(_new_attr) # type: ignore + _new_attr = _new_attr[k] # type: ignore + _serialized = _serialized[k] + except ValueError as err: + if isinstance(err, SerializationError): + raise + + except (AttributeError, KeyError, TypeError) as err: + msg = "Attribute {} in object {} cannot be serialized.\n{}".format(attr_name, class_name, str(target_obj)) + raise SerializationError(msg) from err + return serialized + + def body(self, data, data_type, **kwargs): + """Serialize data intended for a request body. + + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: dict + :raises SerializationError: if serialization fails. + :raises ValueError: if data is None + :returns: The serialized request body + """ + + # Just in case this is a dict + internal_data_type_str = data_type.strip("[]{}") + internal_data_type = self.dependencies.get(internal_data_type_str, None) + try: + is_xml_model_serialization = kwargs["is_xml"] + except KeyError: + if internal_data_type and issubclass(internal_data_type, Model): + is_xml_model_serialization = kwargs.setdefault("is_xml", internal_data_type.is_xml_model()) + else: + is_xml_model_serialization = False + if internal_data_type and not isinstance(internal_data_type, Enum): + try: + deserializer = Deserializer(self.dependencies) + # Since it's on serialization, it's almost sure that format is not JSON REST + # We're not able to deal with additional properties for now. + deserializer.additional_properties_detection = False + if is_xml_model_serialization: + deserializer.key_extractors = [ # type: ignore + attribute_key_case_insensitive_extractor, + ] + else: + deserializer.key_extractors = [ + rest_key_case_insensitive_extractor, + attribute_key_case_insensitive_extractor, + last_rest_key_case_insensitive_extractor, + ] + data = deserializer._deserialize(data_type, data) # pylint: disable=protected-access + except DeserializationError as err: + raise SerializationError("Unable to build a model: " + str(err)) from err + + return self._serialize(data, data_type, **kwargs) + + def url(self, name, data, data_type, **kwargs): + """Serialize data intended for a URL path. + + :param str name: The name of the URL path parameter. + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str + :returns: The serialized URL path + :raises TypeError: if serialization fails. + :raises ValueError: if data is None + """ + try: + output = self.serialize_data(data, data_type, **kwargs) + if data_type == "bool": + output = json.dumps(output) + + if kwargs.get("skip_quote") is True: + output = str(output) + output = output.replace("{", quote("{")).replace("}", quote("}")) + else: + output = quote(str(output), safe="") + except SerializationError as exc: + raise TypeError("{} must be type {}.".format(name, data_type)) from exc + return output + + def query(self, name, data, data_type, **kwargs): + """Serialize data intended for a URL query. + + :param str name: The name of the query parameter. + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str, list + :raises TypeError: if serialization fails. + :raises ValueError: if data is None + :returns: The serialized query parameter + """ + try: + # Treat the list aside, since we don't want to encode the div separator + if data_type.startswith("["): + internal_data_type = data_type[1:-1] + do_quote = not kwargs.get("skip_quote", False) + return self.serialize_iter(data, internal_data_type, do_quote=do_quote, **kwargs) + + # Not a list, regular serialization + output = self.serialize_data(data, data_type, **kwargs) + if data_type == "bool": + output = json.dumps(output) + if kwargs.get("skip_quote") is True: + output = str(output) + else: + output = quote(str(output), safe="") + except SerializationError as exc: + raise TypeError("{} must be type {}.".format(name, data_type)) from exc + return str(output) + + def header(self, name, data, data_type, **kwargs): + """Serialize data intended for a request header. + + :param str name: The name of the header. + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str + :raises TypeError: if serialization fails. + :raises ValueError: if data is None + :returns: The serialized header + """ + try: + if data_type in ["[str]"]: + data = ["" if d is None else d for d in data] + + output = self.serialize_data(data, data_type, **kwargs) + if data_type == "bool": + output = json.dumps(output) + except SerializationError as exc: + raise TypeError("{} must be type {}.".format(name, data_type)) from exc + return str(output) + + def serialize_data(self, data, data_type, **kwargs): + """Serialize generic data according to supplied data type. + + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :raises AttributeError: if required data is None. + :raises ValueError: if data is None + :raises SerializationError: if serialization fails. + :returns: The serialized data. + :rtype: str, int, float, bool, dict, list + """ + if data is None: + raise ValueError("No value for given attribute") + + try: + if data is CoreNull: + return None + if data_type in self.basic_types.values(): + return self.serialize_basic(data, data_type, **kwargs) + + if data_type in self.serialize_type: + return self.serialize_type[data_type](data, **kwargs) + + # If dependencies is empty, try with current data class + # It has to be a subclass of Enum anyway + enum_type = self.dependencies.get(data_type, data.__class__) + if issubclass(enum_type, Enum): + return Serializer.serialize_enum(data, enum_obj=enum_type) + + iter_type = data_type[0] + data_type[-1] + if iter_type in self.serialize_type: + return self.serialize_type[iter_type](data, data_type[1:-1], **kwargs) + + except (ValueError, TypeError) as err: + msg = "Unable to serialize value: {!r} as type: {!r}." + raise SerializationError(msg.format(data, data_type)) from err + return self._serialize(data, **kwargs) + + @classmethod + def _get_custom_serializers(cls, data_type, **kwargs): # pylint: disable=inconsistent-return-statements + custom_serializer = kwargs.get("basic_types_serializers", {}).get(data_type) + if custom_serializer: + return custom_serializer + if kwargs.get("is_xml", False): + return cls._xml_basic_types_serializers.get(data_type) + + @classmethod + def serialize_basic(cls, data, data_type, **kwargs): + """Serialize basic builting data type. + Serializes objects to str, int, float or bool. + + Possible kwargs: + - basic_types_serializers dict[str, callable] : If set, use the callable as serializer + - is_xml bool : If set, use xml_basic_types_serializers + + :param obj data: Object to be serialized. + :param str data_type: Type of object in the iterable. + :rtype: str, int, float, bool + :return: serialized object + """ + custom_serializer = cls._get_custom_serializers(data_type, **kwargs) + if custom_serializer: + return custom_serializer(data) + if data_type == "str": + return cls.serialize_unicode(data) + return eval(data_type)(data) # nosec # pylint: disable=eval-used + + @classmethod + def serialize_unicode(cls, data): + """Special handling for serializing unicode strings in Py2. + Encode to UTF-8 if unicode, otherwise handle as a str. + + :param str data: Object to be serialized. + :rtype: str + :return: serialized object + """ + try: # If I received an enum, return its value + return data.value + except AttributeError: + pass + + try: + if isinstance(data, unicode): # type: ignore + # Don't change it, JSON and XML ElementTree are totally able + # to serialize correctly u'' strings + return data + except NameError: + return str(data) + return str(data) + + def serialize_iter(self, data, iter_type, div=None, **kwargs): + """Serialize iterable. + + Supported kwargs: + - serialization_ctxt dict : The current entry of _attribute_map, or same format. + serialization_ctxt['type'] should be same as data_type. + - is_xml bool : If set, serialize as XML + + :param list data: Object to be serialized. + :param str iter_type: Type of object in the iterable. + :param str div: If set, this str will be used to combine the elements + in the iterable into a combined string. Default is 'None'. + Defaults to False. + :rtype: list, str + :return: serialized iterable + """ + if isinstance(data, str): + raise SerializationError("Refuse str type as a valid iter type.") + + serialization_ctxt = kwargs.get("serialization_ctxt", {}) + is_xml = kwargs.get("is_xml", False) + + serialized = [] + for d in data: + try: + serialized.append(self.serialize_data(d, iter_type, **kwargs)) + except ValueError as err: + if isinstance(err, SerializationError): + raise + serialized.append(None) + + if kwargs.get("do_quote", False): + serialized = ["" if s is None else quote(str(s), safe="") for s in serialized] + + if div: + serialized = ["" if s is None else str(s) for s in serialized] + serialized = div.join(serialized) + + if "xml" in serialization_ctxt or is_xml: + # XML serialization is more complicated + xml_desc = serialization_ctxt.get("xml", {}) + xml_name = xml_desc.get("name") + if not xml_name: + xml_name = serialization_ctxt["key"] + + # Create a wrap node if necessary (use the fact that Element and list have "append") + is_wrapped = xml_desc.get("wrapped", False) + node_name = xml_desc.get("itemsName", xml_name) + if is_wrapped: + final_result = _create_xml_node(xml_name, xml_desc.get("prefix", None), xml_desc.get("ns", None)) + else: + final_result = [] + # All list elements to "local_node" + for el in serialized: + if isinstance(el, ET.Element): + el_node = el + else: + el_node = _create_xml_node(node_name, xml_desc.get("prefix", None), xml_desc.get("ns", None)) + if el is not None: # Otherwise it writes "None" :-p + el_node.text = str(el) + final_result.append(el_node) + return final_result + return serialized + + def serialize_dict(self, attr, dict_type, **kwargs): + """Serialize a dictionary of objects. + + :param dict attr: Object to be serialized. + :param str dict_type: Type of object in the dictionary. + :rtype: dict + :return: serialized dictionary + """ + serialization_ctxt = kwargs.get("serialization_ctxt", {}) + serialized = {} + for key, value in attr.items(): + try: + serialized[self.serialize_unicode(key)] = self.serialize_data(value, dict_type, **kwargs) + except ValueError as err: + if isinstance(err, SerializationError): + raise + serialized[self.serialize_unicode(key)] = None + + if "xml" in serialization_ctxt: + # XML serialization is more complicated + xml_desc = serialization_ctxt["xml"] + xml_name = xml_desc["name"] + + final_result = _create_xml_node(xml_name, xml_desc.get("prefix", None), xml_desc.get("ns", None)) + for key, value in serialized.items(): + ET.SubElement(final_result, key).text = value + return final_result + + return serialized + + def serialize_object(self, attr, **kwargs): # pylint: disable=too-many-return-statements + """Serialize a generic object. + This will be handled as a dictionary. If object passed in is not + a basic type (str, int, float, dict, list) it will simply be + cast to str. + + :param dict attr: Object to be serialized. + :rtype: dict or str + :return: serialized object + """ + if attr is None: + return None + if isinstance(attr, ET.Element): + return attr + obj_type = type(attr) + if obj_type in self.basic_types: + return self.serialize_basic(attr, self.basic_types[obj_type], **kwargs) + if obj_type is _long_type: + return self.serialize_long(attr) + if obj_type is str: + return self.serialize_unicode(attr) + if obj_type is datetime.datetime: + return self.serialize_iso(attr) + if obj_type is datetime.date: + return self.serialize_date(attr) + if obj_type is datetime.time: + return self.serialize_time(attr) + if obj_type is datetime.timedelta: + return self.serialize_duration(attr) + if obj_type is decimal.Decimal: + return self.serialize_decimal(attr) + + # If it's a model or I know this dependency, serialize as a Model + if obj_type in self.dependencies.values() or isinstance(attr, Model): + return self._serialize(attr) + + if obj_type == dict: + serialized = {} + for key, value in attr.items(): + try: + serialized[self.serialize_unicode(key)] = self.serialize_object(value, **kwargs) + except ValueError: + serialized[self.serialize_unicode(key)] = None + return serialized + + if obj_type == list: + serialized = [] + for obj in attr: + try: + serialized.append(self.serialize_object(obj, **kwargs)) + except ValueError: + pass + return serialized + return str(attr) + + @staticmethod + def serialize_enum(attr, enum_obj=None): + try: + result = attr.value + except AttributeError: + result = attr + try: + enum_obj(result) # type: ignore + return result + except ValueError as exc: + for enum_value in enum_obj: # type: ignore + if enum_value.value.lower() == str(attr).lower(): + return enum_value.value + error = "{!r} is not valid value for enum {!r}" + raise SerializationError(error.format(attr, enum_obj)) from exc + + @staticmethod + def serialize_bytearray(attr, **kwargs): # pylint: disable=unused-argument + """Serialize bytearray into base-64 string. + + :param str attr: Object to be serialized. + :rtype: str + :return: serialized base64 + """ + return b64encode(attr).decode() + + @staticmethod + def serialize_base64(attr, **kwargs): # pylint: disable=unused-argument + """Serialize str into base-64 string. + + :param str attr: Object to be serialized. + :rtype: str + :return: serialized base64 + """ + encoded = b64encode(attr).decode("ascii") + return encoded.strip("=").replace("+", "-").replace("/", "_") + + @staticmethod + def serialize_decimal(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Decimal object to float. + + :param decimal attr: Object to be serialized. + :rtype: float + :return: serialized decimal + """ + return float(attr) + + @staticmethod + def serialize_long(attr, **kwargs): # pylint: disable=unused-argument + """Serialize long (Py2) or int (Py3). + + :param int attr: Object to be serialized. + :rtype: int/long + :return: serialized long + """ + return _long_type(attr) + + @staticmethod + def serialize_date(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Date object into ISO-8601 formatted string. + + :param Date attr: Object to be serialized. + :rtype: str + :return: serialized date + """ + if isinstance(attr, str): + attr = isodate.parse_date(attr) + t = "{:04}-{:02}-{:02}".format(attr.year, attr.month, attr.day) + return t + + @staticmethod + def serialize_time(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Time object into ISO-8601 formatted string. + + :param datetime.time attr: Object to be serialized. + :rtype: str + :return: serialized time + """ + if isinstance(attr, str): + attr = isodate.parse_time(attr) + t = "{:02}:{:02}:{:02}".format(attr.hour, attr.minute, attr.second) + if attr.microsecond: + t += ".{:02}".format(attr.microsecond) + return t + + @staticmethod + def serialize_duration(attr, **kwargs): # pylint: disable=unused-argument + """Serialize TimeDelta object into ISO-8601 formatted string. + + :param TimeDelta attr: Object to be serialized. + :rtype: str + :return: serialized duration + """ + if isinstance(attr, str): + attr = isodate.parse_duration(attr) + return isodate.duration_isoformat(attr) + + @staticmethod + def serialize_rfc(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Datetime object into RFC-1123 formatted string. + + :param Datetime attr: Object to be serialized. + :rtype: str + :raises TypeError: if format invalid. + :return: serialized rfc + """ + try: + if not attr.tzinfo: + _LOGGER.warning("Datetime with no tzinfo will be considered UTC.") + utc = attr.utctimetuple() + except AttributeError as exc: + raise TypeError("RFC1123 object must be valid Datetime object.") from exc + + return "{}, {:02} {} {:04} {:02}:{:02}:{:02} GMT".format( + Serializer.days[utc.tm_wday], + utc.tm_mday, + Serializer.months[utc.tm_mon], + utc.tm_year, + utc.tm_hour, + utc.tm_min, + utc.tm_sec, + ) + + @staticmethod + def serialize_iso(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Datetime object into ISO-8601 formatted string. + + :param Datetime attr: Object to be serialized. + :rtype: str + :raises SerializationError: if format invalid. + :return: serialized iso + """ + if isinstance(attr, str): + attr = isodate.parse_datetime(attr) + try: + if not attr.tzinfo: + _LOGGER.warning("Datetime with no tzinfo will be considered UTC.") + utc = attr.utctimetuple() + if utc.tm_year > 9999 or utc.tm_year < 1: + raise OverflowError("Hit max or min date") + + microseconds = str(attr.microsecond).rjust(6, "0").rstrip("0").ljust(3, "0") + if microseconds: + microseconds = "." + microseconds + date = "{:04}-{:02}-{:02}T{:02}:{:02}:{:02}".format( + utc.tm_year, utc.tm_mon, utc.tm_mday, utc.tm_hour, utc.tm_min, utc.tm_sec + ) + return date + microseconds + "Z" + except (ValueError, OverflowError) as err: + msg = "Unable to serialize datetime object." + raise SerializationError(msg) from err + except AttributeError as err: + msg = "ISO-8601 object must be valid Datetime object." + raise TypeError(msg) from err + + @staticmethod + def serialize_unix(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Datetime object into IntTime format. + This is represented as seconds. + + :param Datetime attr: Object to be serialized. + :rtype: int + :raises SerializationError: if format invalid + :return: serialied unix + """ + if isinstance(attr, int): + return attr + try: + if not attr.tzinfo: + _LOGGER.warning("Datetime with no tzinfo will be considered UTC.") + return int(calendar.timegm(attr.utctimetuple())) + except AttributeError as exc: + raise TypeError("Unix time object must be valid Datetime object.") from exc + + +def rest_key_extractor(attr, attr_desc, data): # pylint: disable=unused-argument + key = attr_desc["key"] + working_data = data + + while "." in key: + # Need the cast, as for some reasons "split" is typed as list[str | Any] + dict_keys = cast(List[str], _FLATTEN.split(key)) + if len(dict_keys) == 1: + key = _decode_attribute_map_key(dict_keys[0]) + break + working_key = _decode_attribute_map_key(dict_keys[0]) + working_data = working_data.get(working_key, data) + if working_data is None: + # If at any point while following flatten JSON path see None, it means + # that all properties under are None as well + return None + key = ".".join(dict_keys[1:]) + + return working_data.get(key) + + +def rest_key_case_insensitive_extractor( # pylint: disable=unused-argument, inconsistent-return-statements + attr, attr_desc, data +): + key = attr_desc["key"] + working_data = data + + while "." in key: + dict_keys = _FLATTEN.split(key) + if len(dict_keys) == 1: + key = _decode_attribute_map_key(dict_keys[0]) + break + working_key = _decode_attribute_map_key(dict_keys[0]) + working_data = attribute_key_case_insensitive_extractor(working_key, None, working_data) + if working_data is None: + # If at any point while following flatten JSON path see None, it means + # that all properties under are None as well + return None + key = ".".join(dict_keys[1:]) + + if working_data: + return attribute_key_case_insensitive_extractor(key, None, working_data) + + +def last_rest_key_extractor(attr, attr_desc, data): # pylint: disable=unused-argument + """Extract the attribute in "data" based on the last part of the JSON path key. + + :param str attr: The attribute to extract + :param dict attr_desc: The attribute description + :param dict data: The data to extract from + :rtype: object + :returns: The extracted attribute + """ + key = attr_desc["key"] + dict_keys = _FLATTEN.split(key) + return attribute_key_extractor(dict_keys[-1], None, data) + + +def last_rest_key_case_insensitive_extractor(attr, attr_desc, data): # pylint: disable=unused-argument + """Extract the attribute in "data" based on the last part of the JSON path key. + + This is the case insensitive version of "last_rest_key_extractor" + :param str attr: The attribute to extract + :param dict attr_desc: The attribute description + :param dict data: The data to extract from + :rtype: object + :returns: The extracted attribute + """ + key = attr_desc["key"] + dict_keys = _FLATTEN.split(key) + return attribute_key_case_insensitive_extractor(dict_keys[-1], None, data) + + +def attribute_key_extractor(attr, _, data): + return data.get(attr) + + +def attribute_key_case_insensitive_extractor(attr, _, data): + found_key = None + lower_attr = attr.lower() + for key in data: + if lower_attr == key.lower(): + found_key = key + break + + return data.get(found_key) + + +def _extract_name_from_internal_type(internal_type): + """Given an internal type XML description, extract correct XML name with namespace. + + :param dict internal_type: An model type + :rtype: tuple + :returns: A tuple XML name + namespace dict + """ + internal_type_xml_map = getattr(internal_type, "_xml_map", {}) + xml_name = internal_type_xml_map.get("name", internal_type.__name__) + xml_ns = internal_type_xml_map.get("ns", None) + if xml_ns: + xml_name = "{{{}}}{}".format(xml_ns, xml_name) + return xml_name + + +def xml_key_extractor(attr, attr_desc, data): # pylint: disable=unused-argument,too-many-return-statements + if isinstance(data, dict): + return None + + # Test if this model is XML ready first + if not isinstance(data, ET.Element): + return None + + xml_desc = attr_desc.get("xml", {}) + xml_name = xml_desc.get("name", attr_desc["key"]) + + # Look for a children + is_iter_type = attr_desc["type"].startswith("[") + is_wrapped = xml_desc.get("wrapped", False) + internal_type = attr_desc.get("internalType", None) + internal_type_xml_map = getattr(internal_type, "_xml_map", {}) + + # Integrate namespace if necessary + xml_ns = xml_desc.get("ns", internal_type_xml_map.get("ns", None)) + if xml_ns: + xml_name = "{{{}}}{}".format(xml_ns, xml_name) + + # If it's an attribute, that's simple + if xml_desc.get("attr", False): + return data.get(xml_name) + + # If it's x-ms-text, that's simple too + if xml_desc.get("text", False): + return data.text + + # Scenario where I take the local name: + # - Wrapped node + # - Internal type is an enum (considered basic types) + # - Internal type has no XML/Name node + if is_wrapped or (internal_type and (issubclass(internal_type, Enum) or "name" not in internal_type_xml_map)): + children = data.findall(xml_name) + # If internal type has a local name and it's not a list, I use that name + elif not is_iter_type and internal_type and "name" in internal_type_xml_map: + xml_name = _extract_name_from_internal_type(internal_type) + children = data.findall(xml_name) + # That's an array + else: + if internal_type: # Complex type, ignore itemsName and use the complex type name + items_name = _extract_name_from_internal_type(internal_type) + else: + items_name = xml_desc.get("itemsName", xml_name) + children = data.findall(items_name) + + if len(children) == 0: + if is_iter_type: + if is_wrapped: + return None # is_wrapped no node, we want None + return [] # not wrapped, assume empty list + return None # Assume it's not there, maybe an optional node. + + # If is_iter_type and not wrapped, return all found children + if is_iter_type: + if not is_wrapped: + return children + # Iter and wrapped, should have found one node only (the wrap one) + if len(children) != 1: + raise DeserializationError( + "Tried to deserialize an array not wrapped, and found several nodes '{}'. Maybe you should declare this array as wrapped?".format( + xml_name + ) + ) + return list(children[0]) # Might be empty list and that's ok. + + # Here it's not a itertype, we should have found one element only or empty + if len(children) > 1: + raise DeserializationError("Find several XML '{}' where it was not expected".format(xml_name)) + return children[0] + + +class Deserializer: + """Response object model deserializer. + + :param dict classes: Class type dictionary for deserializing complex types. + :ivar list key_extractors: Ordered list of extractors to be used by this deserializer. + """ + + basic_types = {str: "str", int: "int", bool: "bool", float: "float"} + + valid_date = re.compile(r"\d{4}[-]\d{2}[-]\d{2}T\d{2}:\d{2}:\d{2}\.?\d*Z?[-+]?[\d{2}]?:?[\d{2}]?") + + def __init__(self, classes: Optional[Mapping[str, type]] = None) -> None: + self.deserialize_type = { + "iso-8601": Deserializer.deserialize_iso, + "rfc-1123": Deserializer.deserialize_rfc, + "unix-time": Deserializer.deserialize_unix, + "duration": Deserializer.deserialize_duration, + "date": Deserializer.deserialize_date, + "time": Deserializer.deserialize_time, + "decimal": Deserializer.deserialize_decimal, + "long": Deserializer.deserialize_long, + "bytearray": Deserializer.deserialize_bytearray, + "base64": Deserializer.deserialize_base64, + "object": self.deserialize_object, + "[]": self.deserialize_iter, + "{}": self.deserialize_dict, + } + self.deserialize_expected_types = { + "duration": (isodate.Duration, datetime.timedelta), + "iso-8601": (datetime.datetime), + } + self.dependencies: Dict[str, type] = dict(classes) if classes else {} + self.key_extractors = [rest_key_extractor, xml_key_extractor] + # Additional properties only works if the "rest_key_extractor" is used to + # extract the keys. Making it to work whatever the key extractor is too much + # complicated, with no real scenario for now. + # So adding a flag to disable additional properties detection. This flag should be + # used if your expect the deserialization to NOT come from a JSON REST syntax. + # Otherwise, result are unexpected + self.additional_properties_detection = True + + def __call__(self, target_obj, response_data, content_type=None): + """Call the deserializer to process a REST response. + + :param str target_obj: Target data type to deserialize to. + :param requests.Response response_data: REST response object. + :param str content_type: Swagger "produces" if available. + :raises DeserializationError: if deserialization fails. + :return: Deserialized object. + :rtype: object + """ + data = self._unpack_content(response_data, content_type) + return self._deserialize(target_obj, data) + + def _deserialize(self, target_obj, data): # pylint: disable=inconsistent-return-statements + """Call the deserializer on a model. + + Data needs to be already deserialized as JSON or XML ElementTree + + :param str target_obj: Target data type to deserialize to. + :param object data: Object to deserialize. + :raises DeserializationError: if deserialization fails. + :return: Deserialized object. + :rtype: object + """ + # This is already a model, go recursive just in case + if hasattr(data, "_attribute_map"): + constants = [name for name, config in getattr(data, "_validation", {}).items() if config.get("constant")] + try: + for attr, mapconfig in data._attribute_map.items(): # pylint: disable=protected-access + if attr in constants: + continue + value = getattr(data, attr) + if value is None: + continue + local_type = mapconfig["type"] + internal_data_type = local_type.strip("[]{}") + if internal_data_type not in self.dependencies or isinstance(internal_data_type, Enum): + continue + setattr(data, attr, self._deserialize(local_type, value)) + return data + except AttributeError: + return + + response, class_name = self._classify_target(target_obj, data) + + if isinstance(response, str): + return self.deserialize_data(data, response) + if isinstance(response, type) and issubclass(response, Enum): + return self.deserialize_enum(data, response) + + if data is None or data is CoreNull: + return data + try: + attributes = response._attribute_map # type: ignore # pylint: disable=protected-access + d_attrs = {} + for attr, attr_desc in attributes.items(): + # Check empty string. If it's not empty, someone has a real "additionalProperties"... + if attr == "additional_properties" and attr_desc["key"] == "": + continue + raw_value = None + # Enhance attr_desc with some dynamic data + attr_desc = attr_desc.copy() # Do a copy, do not change the real one + internal_data_type = attr_desc["type"].strip("[]{}") + if internal_data_type in self.dependencies: + attr_desc["internalType"] = self.dependencies[internal_data_type] + + for key_extractor in self.key_extractors: + found_value = key_extractor(attr, attr_desc, data) + if found_value is not None: + if raw_value is not None and raw_value != found_value: + msg = ( + "Ignoring extracted value '%s' from %s for key '%s'" + " (duplicate extraction, follow extractors order)" + ) + _LOGGER.warning(msg, found_value, key_extractor, attr) + continue + raw_value = found_value + + value = self.deserialize_data(raw_value, attr_desc["type"]) + d_attrs[attr] = value + except (AttributeError, TypeError, KeyError) as err: + msg = "Unable to deserialize to object: " + class_name # type: ignore + raise DeserializationError(msg) from err + additional_properties = self._build_additional_properties(attributes, data) + return self._instantiate_model(response, d_attrs, additional_properties) + + def _build_additional_properties(self, attribute_map, data): + if not self.additional_properties_detection: + return None + if "additional_properties" in attribute_map and attribute_map.get("additional_properties", {}).get("key") != "": + # Check empty string. If it's not empty, someone has a real "additionalProperties" + return None + if isinstance(data, ET.Element): + data = {el.tag: el.text for el in data} + + known_keys = { + _decode_attribute_map_key(_FLATTEN.split(desc["key"])[0]) + for desc in attribute_map.values() + if desc["key"] != "" + } + present_keys = set(data.keys()) + missing_keys = present_keys - known_keys + return {key: data[key] for key in missing_keys} + + def _classify_target(self, target, data): + """Check to see whether the deserialization target object can + be classified into a subclass. + Once classification has been determined, initialize object. + + :param str target: The target object type to deserialize to. + :param str/dict data: The response data to deserialize. + :return: The classified target object and its class name. + :rtype: tuple + """ + if target is None: + return None, None + + if isinstance(target, str): + try: + target = self.dependencies[target] + except KeyError: + return target, target + + try: + target = target._classify(data, self.dependencies) # type: ignore # pylint: disable=protected-access + except AttributeError: + pass # Target is not a Model, no classify + return target, target.__class__.__name__ # type: ignore + + def failsafe_deserialize(self, target_obj, data, content_type=None): + """Ignores any errors encountered in deserialization, + and falls back to not deserializing the object. Recommended + for use in error deserialization, as we want to return the + HttpResponseError to users, and not have them deal with + a deserialization error. + + :param str target_obj: The target object type to deserialize to. + :param str/dict data: The response data to deserialize. + :param str content_type: Swagger "produces" if available. + :return: Deserialized object. + :rtype: object + """ + try: + return self(target_obj, data, content_type=content_type) + except: # pylint: disable=bare-except + _LOGGER.debug( + "Ran into a deserialization error. Ignoring since this is failsafe deserialization", exc_info=True + ) + return None + + @staticmethod + def _unpack_content(raw_data, content_type=None): + """Extract the correct structure for deserialization. + + If raw_data is a PipelineResponse, try to extract the result of RawDeserializer. + if we can't, raise. Your Pipeline should have a RawDeserializer. + + If not a pipeline response and raw_data is bytes or string, use content-type + to decode it. If no content-type, try JSON. + + If raw_data is something else, bypass all logic and return it directly. + + :param obj raw_data: Data to be processed. + :param str content_type: How to parse if raw_data is a string/bytes. + :raises JSONDecodeError: If JSON is requested and parsing is impossible. + :raises UnicodeDecodeError: If bytes is not UTF8 + :rtype: object + :return: Unpacked content. + """ + # Assume this is enough to detect a Pipeline Response without importing it + context = getattr(raw_data, "context", {}) + if context: + if RawDeserializer.CONTEXT_NAME in context: + return context[RawDeserializer.CONTEXT_NAME] + raise ValueError("This pipeline didn't have the RawDeserializer policy; can't deserialize") + + # Assume this is enough to recognize universal_http.ClientResponse without importing it + if hasattr(raw_data, "body"): + return RawDeserializer.deserialize_from_http_generics(raw_data.text(), raw_data.headers) + + # Assume this enough to recognize requests.Response without importing it. + if hasattr(raw_data, "_content_consumed"): + return RawDeserializer.deserialize_from_http_generics(raw_data.text, raw_data.headers) + + if isinstance(raw_data, (str, bytes)) or hasattr(raw_data, "read"): + return RawDeserializer.deserialize_from_text(raw_data, content_type) # type: ignore + return raw_data + + def _instantiate_model(self, response, attrs, additional_properties=None): + """Instantiate a response model passing in deserialized args. + + :param Response response: The response model class. + :param dict attrs: The deserialized response attributes. + :param dict additional_properties: Additional properties to be set. + :rtype: Response + :return: The instantiated response model. + """ + if callable(response): + subtype = getattr(response, "_subtype_map", {}) + try: + readonly = [ + k + for k, v in response._validation.items() # pylint: disable=protected-access # type: ignore + if v.get("readonly") + ] + const = [ + k + for k, v in response._validation.items() # pylint: disable=protected-access # type: ignore + if v.get("constant") + ] + kwargs = {k: v for k, v in attrs.items() if k not in subtype and k not in readonly + const} + response_obj = response(**kwargs) + for attr in readonly: + setattr(response_obj, attr, attrs.get(attr)) + if additional_properties: + response_obj.additional_properties = additional_properties # type: ignore + return response_obj + except TypeError as err: + msg = "Unable to deserialize {} into model {}. ".format(kwargs, response) # type: ignore + raise DeserializationError(msg + str(err)) from err + else: + try: + for attr, value in attrs.items(): + setattr(response, attr, value) + return response + except Exception as exp: + msg = "Unable to populate response model. " + msg += "Type: {}, Error: {}".format(type(response), exp) + raise DeserializationError(msg) from exp + + def deserialize_data(self, data, data_type): # pylint: disable=too-many-return-statements + """Process data for deserialization according to data type. + + :param str data: The response string to be deserialized. + :param str data_type: The type to deserialize to. + :raises DeserializationError: if deserialization fails. + :return: Deserialized object. + :rtype: object + """ + if data is None: + return data + + try: + if not data_type: + return data + if data_type in self.basic_types.values(): + return self.deserialize_basic(data, data_type) + if data_type in self.deserialize_type: + if isinstance(data, self.deserialize_expected_types.get(data_type, tuple())): + return data + + is_a_text_parsing_type = lambda x: x not in [ # pylint: disable=unnecessary-lambda-assignment + "object", + "[]", + r"{}", + ] + if isinstance(data, ET.Element) and is_a_text_parsing_type(data_type) and not data.text: + return None + data_val = self.deserialize_type[data_type](data) + return data_val + + iter_type = data_type[0] + data_type[-1] + if iter_type in self.deserialize_type: + return self.deserialize_type[iter_type](data, data_type[1:-1]) + + obj_type = self.dependencies[data_type] + if issubclass(obj_type, Enum): + if isinstance(data, ET.Element): + data = data.text + return self.deserialize_enum(data, obj_type) + + except (ValueError, TypeError, AttributeError) as err: + msg = "Unable to deserialize response data." + msg += " Data: {}, {}".format(data, data_type) + raise DeserializationError(msg) from err + return self._deserialize(obj_type, data) + + def deserialize_iter(self, attr, iter_type): + """Deserialize an iterable. + + :param list attr: Iterable to be deserialized. + :param str iter_type: The type of object in the iterable. + :return: Deserialized iterable. + :rtype: list + """ + if attr is None: + return None + if isinstance(attr, ET.Element): # If I receive an element here, get the children + attr = list(attr) + if not isinstance(attr, (list, set)): + raise DeserializationError("Cannot deserialize as [{}] an object of type {}".format(iter_type, type(attr))) + return [self.deserialize_data(a, iter_type) for a in attr] + + def deserialize_dict(self, attr, dict_type): + """Deserialize a dictionary. + + :param dict/list attr: Dictionary to be deserialized. Also accepts + a list of key, value pairs. + :param str dict_type: The object type of the items in the dictionary. + :return: Deserialized dictionary. + :rtype: dict + """ + if isinstance(attr, list): + return {x["key"]: self.deserialize_data(x["value"], dict_type) for x in attr} + + if isinstance(attr, ET.Element): + # Transform value into {"Key": "value"} + attr = {el.tag: el.text for el in attr} + return {k: self.deserialize_data(v, dict_type) for k, v in attr.items()} + + def deserialize_object(self, attr, **kwargs): # pylint: disable=too-many-return-statements + """Deserialize a generic object. + This will be handled as a dictionary. + + :param dict attr: Dictionary to be deserialized. + :return: Deserialized object. + :rtype: dict + :raises TypeError: if non-builtin datatype encountered. + """ + if attr is None: + return None + if isinstance(attr, ET.Element): + # Do no recurse on XML, just return the tree as-is + return attr + if isinstance(attr, str): + return self.deserialize_basic(attr, "str") + obj_type = type(attr) + if obj_type in self.basic_types: + return self.deserialize_basic(attr, self.basic_types[obj_type]) + if obj_type is _long_type: + return self.deserialize_long(attr) + + if obj_type == dict: + deserialized = {} + for key, value in attr.items(): + try: + deserialized[key] = self.deserialize_object(value, **kwargs) + except ValueError: + deserialized[key] = None + return deserialized + + if obj_type == list: + deserialized = [] + for obj in attr: + try: + deserialized.append(self.deserialize_object(obj, **kwargs)) + except ValueError: + pass + return deserialized + + error = "Cannot deserialize generic object with type: " + raise TypeError(error + str(obj_type)) + + def deserialize_basic(self, attr, data_type): # pylint: disable=too-many-return-statements + """Deserialize basic builtin data type from string. + Will attempt to convert to str, int, float and bool. + This function will also accept '1', '0', 'true' and 'false' as + valid bool values. + + :param str attr: response string to be deserialized. + :param str data_type: deserialization data type. + :return: Deserialized basic type. + :rtype: str, int, float or bool + :raises TypeError: if string format is not valid. + """ + # If we're here, data is supposed to be a basic type. + # If it's still an XML node, take the text + if isinstance(attr, ET.Element): + attr = attr.text + if not attr: + if data_type == "str": + # None or '', node is empty string. + return "" + # None or '', node with a strong type is None. + # Don't try to model "empty bool" or "empty int" + return None + + if data_type == "bool": + if attr in [True, False, 1, 0]: + return bool(attr) + if isinstance(attr, str): + if attr.lower() in ["true", "1"]: + return True + if attr.lower() in ["false", "0"]: + return False + raise TypeError("Invalid boolean value: {}".format(attr)) + + if data_type == "str": + return self.deserialize_unicode(attr) + return eval(data_type)(attr) # nosec # pylint: disable=eval-used + + @staticmethod + def deserialize_unicode(data): + """Preserve unicode objects in Python 2, otherwise return data + as a string. + + :param str data: response string to be deserialized. + :return: Deserialized string. + :rtype: str or unicode + """ + # We might be here because we have an enum modeled as string, + # and we try to deserialize a partial dict with enum inside + if isinstance(data, Enum): + return data + + # Consider this is real string + try: + if isinstance(data, unicode): # type: ignore + return data + except NameError: + return str(data) + return str(data) + + @staticmethod + def deserialize_enum(data, enum_obj): + """Deserialize string into enum object. + + If the string is not a valid enum value it will be returned as-is + and a warning will be logged. + + :param str data: Response string to be deserialized. If this value is + None or invalid it will be returned as-is. + :param Enum enum_obj: Enum object to deserialize to. + :return: Deserialized enum object. + :rtype: Enum + """ + if isinstance(data, enum_obj) or data is None: + return data + if isinstance(data, Enum): + data = data.value + if isinstance(data, int): + # Workaround. We might consider remove it in the future. + try: + return list(enum_obj.__members__.values())[data] + except IndexError as exc: + error = "{!r} is not a valid index for enum {!r}" + raise DeserializationError(error.format(data, enum_obj)) from exc + try: + return enum_obj(str(data)) + except ValueError: + for enum_value in enum_obj: + if enum_value.value.lower() == str(data).lower(): + return enum_value + # We don't fail anymore for unknown value, we deserialize as a string + _LOGGER.warning("Deserializer is not able to find %s as valid enum in %s", data, enum_obj) + return Deserializer.deserialize_unicode(data) + + @staticmethod + def deserialize_bytearray(attr): + """Deserialize string into bytearray. + + :param str attr: response string to be deserialized. + :return: Deserialized bytearray + :rtype: bytearray + :raises TypeError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + return bytearray(b64decode(attr)) # type: ignore + + @staticmethod + def deserialize_base64(attr): + """Deserialize base64 encoded string into string. + + :param str attr: response string to be deserialized. + :return: Deserialized base64 string + :rtype: bytearray + :raises TypeError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + padding = "=" * (3 - (len(attr) + 3) % 4) # type: ignore + attr = attr + padding # type: ignore + encoded = attr.replace("-", "+").replace("_", "/") + return b64decode(encoded) + + @staticmethod + def deserialize_decimal(attr): + """Deserialize string into Decimal object. + + :param str attr: response string to be deserialized. + :return: Deserialized decimal + :raises DeserializationError: if string format invalid. + :rtype: decimal + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + return decimal.Decimal(str(attr)) # type: ignore + except decimal.DecimalException as err: + msg = "Invalid decimal {}".format(attr) + raise DeserializationError(msg) from err + + @staticmethod + def deserialize_long(attr): + """Deserialize string into long (Py2) or int (Py3). + + :param str attr: response string to be deserialized. + :return: Deserialized int + :rtype: long or int + :raises ValueError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + return _long_type(attr) # type: ignore + + @staticmethod + def deserialize_duration(attr): + """Deserialize ISO-8601 formatted string into TimeDelta object. + + :param str attr: response string to be deserialized. + :return: Deserialized duration + :rtype: TimeDelta + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + duration = isodate.parse_duration(attr) + except (ValueError, OverflowError, AttributeError) as err: + msg = "Cannot deserialize duration object." + raise DeserializationError(msg) from err + return duration + + @staticmethod + def deserialize_date(attr): + """Deserialize ISO-8601 formatted string into Date object. + + :param str attr: response string to be deserialized. + :return: Deserialized date + :rtype: Date + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + if re.search(r"[^\W\d_]", attr, re.I + re.U): # type: ignore + raise DeserializationError("Date must have only digits and -. Received: %s" % attr) + # This must NOT use defaultmonth/defaultday. Using None ensure this raises an exception. + return isodate.parse_date(attr, defaultmonth=0, defaultday=0) + + @staticmethod + def deserialize_time(attr): + """Deserialize ISO-8601 formatted string into time object. + + :param str attr: response string to be deserialized. + :return: Deserialized time + :rtype: datetime.time + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + if re.search(r"[^\W\d_]", attr, re.I + re.U): # type: ignore + raise DeserializationError("Date must have only digits and -. Received: %s" % attr) + return isodate.parse_time(attr) + + @staticmethod + def deserialize_rfc(attr): + """Deserialize RFC-1123 formatted string into Datetime object. + + :param str attr: response string to be deserialized. + :return: Deserialized RFC datetime + :rtype: Datetime + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + parsed_date = email.utils.parsedate_tz(attr) # type: ignore + date_obj = datetime.datetime( + *parsed_date[:6], tzinfo=datetime.timezone(datetime.timedelta(minutes=(parsed_date[9] or 0) / 60)) + ) + if not date_obj.tzinfo: + date_obj = date_obj.astimezone(tz=TZ_UTC) + except ValueError as err: + msg = "Cannot deserialize to rfc datetime object." + raise DeserializationError(msg) from err + return date_obj + + @staticmethod + def deserialize_iso(attr): + """Deserialize ISO-8601 formatted string into Datetime object. + + :param str attr: response string to be deserialized. + :return: Deserialized ISO datetime + :rtype: Datetime + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + attr = attr.upper() # type: ignore + match = Deserializer.valid_date.match(attr) + if not match: + raise ValueError("Invalid datetime string: " + attr) + + check_decimal = attr.split(".") + if len(check_decimal) > 1: + decimal_str = "" + for digit in check_decimal[1]: + if digit.isdigit(): + decimal_str += digit + else: + break + if len(decimal_str) > 6: + attr = attr.replace(decimal_str, decimal_str[0:6]) + + date_obj = isodate.parse_datetime(attr) + test_utc = date_obj.utctimetuple() + if test_utc.tm_year > 9999 or test_utc.tm_year < 1: + raise OverflowError("Hit max or min date") + except (ValueError, OverflowError, AttributeError) as err: + msg = "Cannot deserialize datetime object." + raise DeserializationError(msg) from err + return date_obj + + @staticmethod + def deserialize_unix(attr): + """Serialize Datetime object into IntTime format. + This is represented as seconds. + + :param int attr: Object to be serialized. + :return: Deserialized datetime + :rtype: Datetime + :raises DeserializationError: if format invalid + """ + if isinstance(attr, ET.Element): + attr = int(attr.text) # type: ignore + try: + attr = int(attr) + date_obj = datetime.datetime.fromtimestamp(attr, TZ_UTC) + except ValueError as err: + msg = "Cannot deserialize to unix datetime object." + raise DeserializationError(msg) from err + return date_obj diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ParameterFlatteningVersionTolerant/parameterflatteningversiontolerant/aio/_client.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ParameterFlatteningVersionTolerant/parameterflatteningversiontolerant/aio/_client.py index 5d96bf35b3a..f6b1c22cd29 100644 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ParameterFlatteningVersionTolerant/parameterflatteningversiontolerant/aio/_client.py +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ParameterFlatteningVersionTolerant/parameterflatteningversiontolerant/aio/_client.py @@ -14,7 +14,7 @@ from azure.core.pipeline import policies from azure.core.rest import AsyncHttpResponse, HttpRequest -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import AutoRestParameterFlatteningConfiguration from .operations import AvailabilitySetsOperations diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ParameterFlatteningVersionTolerant/parameterflatteningversiontolerant/aio/operations/_operations.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ParameterFlatteningVersionTolerant/parameterflatteningversiontolerant/aio/operations/_operations.py index 1340aa0a7e4..35e11e60d5d 100644 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ParameterFlatteningVersionTolerant/parameterflatteningversiontolerant/aio/operations/_operations.py +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ParameterFlatteningVersionTolerant/parameterflatteningversiontolerant/aio/operations/_operations.py @@ -23,7 +23,7 @@ from azure.core.tracing.decorator_async import distributed_trace_async from azure.core.utils import case_insensitive_dict -from ..._serialization import Deserializer, Serializer +from ..._utils.serialization import Deserializer, Serializer from ...operations._operations import build_availability_sets_update_request from .._configuration import AutoRestParameterFlatteningConfiguration diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ParameterFlatteningVersionTolerant/parameterflatteningversiontolerant/operations/_operations.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ParameterFlatteningVersionTolerant/parameterflatteningversiontolerant/operations/_operations.py index 6226cb6dcbe..b284a47d816 100644 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ParameterFlatteningVersionTolerant/parameterflatteningversiontolerant/operations/_operations.py +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ParameterFlatteningVersionTolerant/parameterflatteningversiontolerant/operations/_operations.py @@ -24,7 +24,7 @@ from azure.core.utils import case_insensitive_dict from .._configuration import AutoRestParameterFlatteningConfiguration -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer JSON = MutableMapping[str, Any] T = TypeVar("T") diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ParameterizedEndpointVersionTolerant/parameterizedendpointversiontolerant/_client.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ParameterizedEndpointVersionTolerant/parameterizedendpointversiontolerant/_client.py index 0d4d2d8dcff..fd68bb5f75c 100644 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ParameterizedEndpointVersionTolerant/parameterizedendpointversiontolerant/_client.py +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ParameterizedEndpointVersionTolerant/parameterizedendpointversiontolerant/_client.py @@ -16,7 +16,7 @@ from ._configuration import ParmaterizedEndpointClientConfiguration from ._operations import ParmaterizedEndpointClientOperationsMixin -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer class ParmaterizedEndpointClient( diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ParameterizedEndpointVersionTolerant/parameterizedendpointversiontolerant/_operations/_operations.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ParameterizedEndpointVersionTolerant/parameterizedendpointversiontolerant/_operations/_operations.py index 2e05ef96c99..a60b6ec6ae8 100644 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ParameterizedEndpointVersionTolerant/parameterizedendpointversiontolerant/_operations/_operations.py +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ParameterizedEndpointVersionTolerant/parameterizedendpointversiontolerant/_operations/_operations.py @@ -8,6 +8,7 @@ from collections.abc import MutableMapping from typing import Any, Callable, Dict, Optional, TypeVar +from azure.core import PipelineClient from azure.core.exceptions import ( ClientAuthenticationError, HttpResponseError, @@ -20,8 +21,9 @@ from azure.core.rest import HttpRequest, HttpResponse from azure.core.tracing.decorator import distributed_trace -from .._serialization import Serializer -from .._vendor import ParmaterizedEndpointClientMixinABC +from .._configuration import ParmaterizedEndpointClientConfiguration +from .._utils.serialization import Serializer +from .._utils.utils import ClientMixinABC T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] @@ -37,7 +39,9 @@ def build_parmaterized_endpoint_get_request(**kwargs: Any) -> HttpRequest: return HttpRequest(method="GET", url=_url, **kwargs) -class ParmaterizedEndpointClientOperationsMixin(ParmaterizedEndpointClientMixinABC): # pylint: disable=name-too-long +class ParmaterizedEndpointClientOperationsMixin( # pylint: disable=name-too-long + ClientMixinABC[PipelineClient, ParmaterizedEndpointClientConfiguration] +): @distributed_trace def get(self, **kwargs: Any) -> None: # pylint: disable=inconsistent-return-statements diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ParameterizedEndpointVersionTolerant/parameterizedendpointversiontolerant/_utils/__init__.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ParameterizedEndpointVersionTolerant/parameterizedendpointversiontolerant/_utils/__init__.py new file mode 100644 index 00000000000..0af9b28f660 --- /dev/null +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ParameterizedEndpointVersionTolerant/parameterizedendpointversiontolerant/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ParameterizedEndpointVersionTolerant/parameterizedendpointversiontolerant/_utils/serialization.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ParameterizedEndpointVersionTolerant/parameterizedendpointversiontolerant/_utils/serialization.py new file mode 100644 index 00000000000..f5187701d7b --- /dev/null +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ParameterizedEndpointVersionTolerant/parameterizedendpointversiontolerant/_utils/serialization.py @@ -0,0 +1,2032 @@ +# pylint: disable=line-too-long,useless-suppression,too-many-lines +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +# pyright: reportUnnecessaryTypeIgnoreComment=false + +from base64 import b64decode, b64encode +import calendar +import datetime +import decimal +import email +from enum import Enum +import json +import logging +import re +import sys +import codecs +from typing import ( + Dict, + Any, + cast, + Optional, + Union, + AnyStr, + IO, + Mapping, + Callable, + MutableMapping, + List, +) + +try: + from urllib import quote # type: ignore +except ImportError: + from urllib.parse import quote +import xml.etree.ElementTree as ET + +import isodate # type: ignore +from typing_extensions import Self + +from azure.core.exceptions import DeserializationError, SerializationError +from azure.core.serialization import NULL as CoreNull + +_BOM = codecs.BOM_UTF8.decode(encoding="utf-8") + +JSON = MutableMapping[str, Any] + + +class RawDeserializer: + + # Accept "text" because we're open minded people... + JSON_REGEXP = re.compile(r"^(application|text)/([a-z+.]+\+)?json$") + + # Name used in context + CONTEXT_NAME = "deserialized_data" + + @classmethod + def deserialize_from_text(cls, data: Optional[Union[AnyStr, IO]], content_type: Optional[str] = None) -> Any: + """Decode data according to content-type. + + Accept a stream of data as well, but will be load at once in memory for now. + + If no content-type, will return the string version (not bytes, not stream) + + :param data: Input, could be bytes or stream (will be decoded with UTF8) or text + :type data: str or bytes or IO + :param str content_type: The content type. + :return: The deserialized data. + :rtype: object + """ + if hasattr(data, "read"): + # Assume a stream + data = cast(IO, data).read() + + if isinstance(data, bytes): + data_as_str = data.decode(encoding="utf-8-sig") + else: + # Explain to mypy the correct type. + data_as_str = cast(str, data) + + # Remove Byte Order Mark if present in string + data_as_str = data_as_str.lstrip(_BOM) + + if content_type is None: + return data + + if cls.JSON_REGEXP.match(content_type): + try: + return json.loads(data_as_str) + except ValueError as err: + raise DeserializationError("JSON is invalid: {}".format(err), err) from err + elif "xml" in (content_type or []): + try: + + try: + if isinstance(data, unicode): # type: ignore + # If I'm Python 2.7 and unicode XML will scream if I try a "fromstring" on unicode string + data_as_str = data_as_str.encode(encoding="utf-8") # type: ignore + except NameError: + pass + + return ET.fromstring(data_as_str) # nosec + except ET.ParseError as err: + # It might be because the server has an issue, and returned JSON with + # content-type XML.... + # So let's try a JSON load, and if it's still broken + # let's flow the initial exception + def _json_attemp(data): + try: + return True, json.loads(data) + except ValueError: + return False, None # Don't care about this one + + success, json_result = _json_attemp(data) + if success: + return json_result + # If i'm here, it's not JSON, it's not XML, let's scream + # and raise the last context in this block (the XML exception) + # The function hack is because Py2.7 messes up with exception + # context otherwise. + _LOGGER.critical("Wasn't XML not JSON, failing") + raise DeserializationError("XML is invalid") from err + elif content_type.startswith("text/"): + return data_as_str + raise DeserializationError("Cannot deserialize content-type: {}".format(content_type)) + + @classmethod + def deserialize_from_http_generics(cls, body_bytes: Optional[Union[AnyStr, IO]], headers: Mapping) -> Any: + """Deserialize from HTTP response. + + Use bytes and headers to NOT use any requests/aiohttp or whatever + specific implementation. + Headers will tested for "content-type" + + :param bytes body_bytes: The body of the response. + :param dict headers: The headers of the response. + :returns: The deserialized data. + :rtype: object + """ + # Try to use content-type from headers if available + content_type = None + if "content-type" in headers: + content_type = headers["content-type"].split(";")[0].strip().lower() + # Ouch, this server did not declare what it sent... + # Let's guess it's JSON... + # Also, since Autorest was considering that an empty body was a valid JSON, + # need that test as well.... + else: + content_type = "application/json" + + if body_bytes: + return cls.deserialize_from_text(body_bytes, content_type) + return None + + +_LOGGER = logging.getLogger(__name__) + +try: + _long_type = long # type: ignore +except NameError: + _long_type = int + +TZ_UTC = datetime.timezone.utc + +_FLATTEN = re.compile(r"(? None: + self.additional_properties: Optional[Dict[str, Any]] = {} + for k in kwargs: # pylint: disable=consider-using-dict-items + if k not in self._attribute_map: + _LOGGER.warning("%s is not a known attribute of class %s and will be ignored", k, self.__class__) + elif k in self._validation and self._validation[k].get("readonly", False): + _LOGGER.warning("Readonly attribute %s will be ignored in class %s", k, self.__class__) + else: + setattr(self, k, kwargs[k]) + + def __eq__(self, other: Any) -> bool: + """Compare objects by comparing all attributes. + + :param object other: The object to compare + :returns: True if objects are equal + :rtype: bool + """ + if isinstance(other, self.__class__): + return self.__dict__ == other.__dict__ + return False + + def __ne__(self, other: Any) -> bool: + """Compare objects by comparing all attributes. + + :param object other: The object to compare + :returns: True if objects are not equal + :rtype: bool + """ + return not self.__eq__(other) + + def __str__(self) -> str: + return str(self.__dict__) + + @classmethod + def enable_additional_properties_sending(cls) -> None: + cls._attribute_map["additional_properties"] = {"key": "", "type": "{object}"} + + @classmethod + def is_xml_model(cls) -> bool: + try: + cls._xml_map # type: ignore + except AttributeError: + return False + return True + + @classmethod + def _create_xml_node(cls): + """Create XML node. + + :returns: The XML node + :rtype: xml.etree.ElementTree.Element + """ + try: + xml_map = cls._xml_map # type: ignore + except AttributeError: + xml_map = {} + + return _create_xml_node(xml_map.get("name", cls.__name__), xml_map.get("prefix", None), xml_map.get("ns", None)) + + def serialize(self, keep_readonly: bool = False, **kwargs: Any) -> JSON: + """Return the JSON that would be sent to server from this model. + + This is an alias to `as_dict(full_restapi_key_transformer, keep_readonly=False)`. + + If you want XML serialization, you can pass the kwargs is_xml=True. + + :param bool keep_readonly: If you want to serialize the readonly attributes + :returns: A dict JSON compatible object + :rtype: dict + """ + serializer = Serializer(self._infer_class_models()) + return serializer._serialize( # type: ignore # pylint: disable=protected-access + self, keep_readonly=keep_readonly, **kwargs + ) + + def as_dict( + self, + keep_readonly: bool = True, + key_transformer: Callable[[str, Dict[str, Any], Any], Any] = attribute_transformer, + **kwargs: Any + ) -> JSON: + """Return a dict that can be serialized using json.dump. + + Advanced usage might optionally use a callback as parameter: + + .. code::python + + def my_key_transformer(key, attr_desc, value): + return key + + Key is the attribute name used in Python. Attr_desc + is a dict of metadata. Currently contains 'type' with the + msrest type and 'key' with the RestAPI encoded key. + Value is the current value in this object. + + The string returned will be used to serialize the key. + If the return type is a list, this is considered hierarchical + result dict. + + See the three examples in this file: + + - attribute_transformer + - full_restapi_key_transformer + - last_restapi_key_transformer + + If you want XML serialization, you can pass the kwargs is_xml=True. + + :param bool keep_readonly: If you want to serialize the readonly attributes + :param function key_transformer: A key transformer function. + :returns: A dict JSON compatible object + :rtype: dict + """ + serializer = Serializer(self._infer_class_models()) + return serializer._serialize( # type: ignore # pylint: disable=protected-access + self, key_transformer=key_transformer, keep_readonly=keep_readonly, **kwargs + ) + + @classmethod + def _infer_class_models(cls): + try: + str_models = cls.__module__.rsplit(".", 1)[0] + models = sys.modules[str_models] + client_models = {k: v for k, v in models.__dict__.items() if isinstance(v, type)} + if cls.__name__ not in client_models: + raise ValueError("Not Autorest generated code") + except Exception: # pylint: disable=broad-exception-caught + # Assume it's not Autorest generated (tests?). Add ourselves as dependencies. + client_models = {cls.__name__: cls} + return client_models + + @classmethod + def deserialize(cls, data: Any, content_type: Optional[str] = None) -> Self: + """Parse a str using the RestAPI syntax and return a model. + + :param str data: A str using RestAPI structure. JSON by default. + :param str content_type: JSON by default, set application/xml if XML. + :returns: An instance of this model + :raises DeserializationError: if something went wrong + :rtype: Self + """ + deserializer = Deserializer(cls._infer_class_models()) + return deserializer(cls.__name__, data, content_type=content_type) # type: ignore + + @classmethod + def from_dict( + cls, + data: Any, + key_extractors: Optional[Callable[[str, Dict[str, Any], Any], Any]] = None, + content_type: Optional[str] = None, + ) -> Self: + """Parse a dict using given key extractor return a model. + + By default consider key + extractors (rest_key_case_insensitive_extractor, attribute_key_case_insensitive_extractor + and last_rest_key_case_insensitive_extractor) + + :param dict data: A dict using RestAPI structure + :param function key_extractors: A key extractor function. + :param str content_type: JSON by default, set application/xml if XML. + :returns: An instance of this model + :raises DeserializationError: if something went wrong + :rtype: Self + """ + deserializer = Deserializer(cls._infer_class_models()) + deserializer.key_extractors = ( # type: ignore + [ # type: ignore + attribute_key_case_insensitive_extractor, + rest_key_case_insensitive_extractor, + last_rest_key_case_insensitive_extractor, + ] + if key_extractors is None + else key_extractors + ) + return deserializer(cls.__name__, data, content_type=content_type) # type: ignore + + @classmethod + def _flatten_subtype(cls, key, objects): + if "_subtype_map" not in cls.__dict__: + return {} + result = dict(cls._subtype_map[key]) + for valuetype in cls._subtype_map[key].values(): + result.update(objects[valuetype]._flatten_subtype(key, objects)) # pylint: disable=protected-access + return result + + @classmethod + def _classify(cls, response, objects): + """Check the class _subtype_map for any child classes. + We want to ignore any inherited _subtype_maps. + + :param dict response: The initial data + :param dict objects: The class objects + :returns: The class to be used + :rtype: class + """ + for subtype_key in cls.__dict__.get("_subtype_map", {}).keys(): + subtype_value = None + + if not isinstance(response, ET.Element): + rest_api_response_key = cls._get_rest_key_parts(subtype_key)[-1] + subtype_value = response.get(rest_api_response_key, None) or response.get(subtype_key, None) + else: + subtype_value = xml_key_extractor(subtype_key, cls._attribute_map[subtype_key], response) + if subtype_value: + # Try to match base class. Can be class name only + # (bug to fix in Autorest to support x-ms-discriminator-name) + if cls.__name__ == subtype_value: + return cls + flatten_mapping_type = cls._flatten_subtype(subtype_key, objects) + try: + return objects[flatten_mapping_type[subtype_value]] # type: ignore + except KeyError: + _LOGGER.warning( + "Subtype value %s has no mapping, use base class %s.", + subtype_value, + cls.__name__, + ) + break + else: + _LOGGER.warning("Discriminator %s is absent or null, use base class %s.", subtype_key, cls.__name__) + break + return cls + + @classmethod + def _get_rest_key_parts(cls, attr_key): + """Get the RestAPI key of this attr, split it and decode part + :param str attr_key: Attribute key must be in attribute_map. + :returns: A list of RestAPI part + :rtype: list + """ + rest_split_key = _FLATTEN.split(cls._attribute_map[attr_key]["key"]) + return [_decode_attribute_map_key(key_part) for key_part in rest_split_key] + + +def _decode_attribute_map_key(key): + """This decode a key in an _attribute_map to the actual key we want to look at + inside the received data. + + :param str key: A key string from the generated code + :returns: The decoded key + :rtype: str + """ + return key.replace("\\.", ".") + + +class Serializer: # pylint: disable=too-many-public-methods + """Request object model serializer.""" + + basic_types = {str: "str", int: "int", bool: "bool", float: "float"} + + _xml_basic_types_serializers = {"bool": lambda x: str(x).lower()} + days = {0: "Mon", 1: "Tue", 2: "Wed", 3: "Thu", 4: "Fri", 5: "Sat", 6: "Sun"} + months = { + 1: "Jan", + 2: "Feb", + 3: "Mar", + 4: "Apr", + 5: "May", + 6: "Jun", + 7: "Jul", + 8: "Aug", + 9: "Sep", + 10: "Oct", + 11: "Nov", + 12: "Dec", + } + validation = { + "min_length": lambda x, y: len(x) < y, + "max_length": lambda x, y: len(x) > y, + "minimum": lambda x, y: x < y, + "maximum": lambda x, y: x > y, + "minimum_ex": lambda x, y: x <= y, + "maximum_ex": lambda x, y: x >= y, + "min_items": lambda x, y: len(x) < y, + "max_items": lambda x, y: len(x) > y, + "pattern": lambda x, y: not re.match(y, x, re.UNICODE), + "unique": lambda x, y: len(x) != len(set(x)), + "multiple": lambda x, y: x % y != 0, + } + + def __init__(self, classes: Optional[Mapping[str, type]] = None) -> None: + self.serialize_type = { + "iso-8601": Serializer.serialize_iso, + "rfc-1123": Serializer.serialize_rfc, + "unix-time": Serializer.serialize_unix, + "duration": Serializer.serialize_duration, + "date": Serializer.serialize_date, + "time": Serializer.serialize_time, + "decimal": Serializer.serialize_decimal, + "long": Serializer.serialize_long, + "bytearray": Serializer.serialize_bytearray, + "base64": Serializer.serialize_base64, + "object": self.serialize_object, + "[]": self.serialize_iter, + "{}": self.serialize_dict, + } + self.dependencies: Dict[str, type] = dict(classes) if classes else {} + self.key_transformer = full_restapi_key_transformer + self.client_side_validation = True + + def _serialize( # pylint: disable=too-many-nested-blocks, too-many-branches, too-many-statements, too-many-locals + self, target_obj, data_type=None, **kwargs + ): + """Serialize data into a string according to type. + + :param object target_obj: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str, dict + :raises SerializationError: if serialization fails. + :returns: The serialized data. + """ + key_transformer = kwargs.get("key_transformer", self.key_transformer) + keep_readonly = kwargs.get("keep_readonly", False) + if target_obj is None: + return None + + attr_name = None + class_name = target_obj.__class__.__name__ + + if data_type: + return self.serialize_data(target_obj, data_type, **kwargs) + + if not hasattr(target_obj, "_attribute_map"): + data_type = type(target_obj).__name__ + if data_type in self.basic_types.values(): + return self.serialize_data(target_obj, data_type, **kwargs) + + # Force "is_xml" kwargs if we detect a XML model + try: + is_xml_model_serialization = kwargs["is_xml"] + except KeyError: + is_xml_model_serialization = kwargs.setdefault("is_xml", target_obj.is_xml_model()) + + serialized = {} + if is_xml_model_serialization: + serialized = target_obj._create_xml_node() # pylint: disable=protected-access + try: + attributes = target_obj._attribute_map # pylint: disable=protected-access + for attr, attr_desc in attributes.items(): + attr_name = attr + if not keep_readonly and target_obj._validation.get( # pylint: disable=protected-access + attr_name, {} + ).get("readonly", False): + continue + + if attr_name == "additional_properties" and attr_desc["key"] == "": + if target_obj.additional_properties is not None: + serialized.update(target_obj.additional_properties) + continue + try: + + orig_attr = getattr(target_obj, attr) + if is_xml_model_serialization: + pass # Don't provide "transformer" for XML for now. Keep "orig_attr" + else: # JSON + keys, orig_attr = key_transformer(attr, attr_desc.copy(), orig_attr) + keys = keys if isinstance(keys, list) else [keys] + + kwargs["serialization_ctxt"] = attr_desc + new_attr = self.serialize_data(orig_attr, attr_desc["type"], **kwargs) + + if is_xml_model_serialization: + xml_desc = attr_desc.get("xml", {}) + xml_name = xml_desc.get("name", attr_desc["key"]) + xml_prefix = xml_desc.get("prefix", None) + xml_ns = xml_desc.get("ns", None) + if xml_desc.get("attr", False): + if xml_ns: + ET.register_namespace(xml_prefix, xml_ns) + xml_name = "{{{}}}{}".format(xml_ns, xml_name) + serialized.set(xml_name, new_attr) # type: ignore + continue + if xml_desc.get("text", False): + serialized.text = new_attr # type: ignore + continue + if isinstance(new_attr, list): + serialized.extend(new_attr) # type: ignore + elif isinstance(new_attr, ET.Element): + # If the down XML has no XML/Name, + # we MUST replace the tag with the local tag. But keeping the namespaces. + if "name" not in getattr(orig_attr, "_xml_map", {}): + splitted_tag = new_attr.tag.split("}") + if len(splitted_tag) == 2: # Namespace + new_attr.tag = "}".join([splitted_tag[0], xml_name]) + else: + new_attr.tag = xml_name + serialized.append(new_attr) # type: ignore + else: # That's a basic type + # Integrate namespace if necessary + local_node = _create_xml_node(xml_name, xml_prefix, xml_ns) + local_node.text = str(new_attr) + serialized.append(local_node) # type: ignore + else: # JSON + for k in reversed(keys): # type: ignore + new_attr = {k: new_attr} + + _new_attr = new_attr + _serialized = serialized + for k in keys: # type: ignore + if k not in _serialized: + _serialized.update(_new_attr) # type: ignore + _new_attr = _new_attr[k] # type: ignore + _serialized = _serialized[k] + except ValueError as err: + if isinstance(err, SerializationError): + raise + + except (AttributeError, KeyError, TypeError) as err: + msg = "Attribute {} in object {} cannot be serialized.\n{}".format(attr_name, class_name, str(target_obj)) + raise SerializationError(msg) from err + return serialized + + def body(self, data, data_type, **kwargs): + """Serialize data intended for a request body. + + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: dict + :raises SerializationError: if serialization fails. + :raises ValueError: if data is None + :returns: The serialized request body + """ + + # Just in case this is a dict + internal_data_type_str = data_type.strip("[]{}") + internal_data_type = self.dependencies.get(internal_data_type_str, None) + try: + is_xml_model_serialization = kwargs["is_xml"] + except KeyError: + if internal_data_type and issubclass(internal_data_type, Model): + is_xml_model_serialization = kwargs.setdefault("is_xml", internal_data_type.is_xml_model()) + else: + is_xml_model_serialization = False + if internal_data_type and not isinstance(internal_data_type, Enum): + try: + deserializer = Deserializer(self.dependencies) + # Since it's on serialization, it's almost sure that format is not JSON REST + # We're not able to deal with additional properties for now. + deserializer.additional_properties_detection = False + if is_xml_model_serialization: + deserializer.key_extractors = [ # type: ignore + attribute_key_case_insensitive_extractor, + ] + else: + deserializer.key_extractors = [ + rest_key_case_insensitive_extractor, + attribute_key_case_insensitive_extractor, + last_rest_key_case_insensitive_extractor, + ] + data = deserializer._deserialize(data_type, data) # pylint: disable=protected-access + except DeserializationError as err: + raise SerializationError("Unable to build a model: " + str(err)) from err + + return self._serialize(data, data_type, **kwargs) + + def url(self, name, data, data_type, **kwargs): + """Serialize data intended for a URL path. + + :param str name: The name of the URL path parameter. + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str + :returns: The serialized URL path + :raises TypeError: if serialization fails. + :raises ValueError: if data is None + """ + try: + output = self.serialize_data(data, data_type, **kwargs) + if data_type == "bool": + output = json.dumps(output) + + if kwargs.get("skip_quote") is True: + output = str(output) + output = output.replace("{", quote("{")).replace("}", quote("}")) + else: + output = quote(str(output), safe="") + except SerializationError as exc: + raise TypeError("{} must be type {}.".format(name, data_type)) from exc + return output + + def query(self, name, data, data_type, **kwargs): + """Serialize data intended for a URL query. + + :param str name: The name of the query parameter. + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str, list + :raises TypeError: if serialization fails. + :raises ValueError: if data is None + :returns: The serialized query parameter + """ + try: + # Treat the list aside, since we don't want to encode the div separator + if data_type.startswith("["): + internal_data_type = data_type[1:-1] + do_quote = not kwargs.get("skip_quote", False) + return self.serialize_iter(data, internal_data_type, do_quote=do_quote, **kwargs) + + # Not a list, regular serialization + output = self.serialize_data(data, data_type, **kwargs) + if data_type == "bool": + output = json.dumps(output) + if kwargs.get("skip_quote") is True: + output = str(output) + else: + output = quote(str(output), safe="") + except SerializationError as exc: + raise TypeError("{} must be type {}.".format(name, data_type)) from exc + return str(output) + + def header(self, name, data, data_type, **kwargs): + """Serialize data intended for a request header. + + :param str name: The name of the header. + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str + :raises TypeError: if serialization fails. + :raises ValueError: if data is None + :returns: The serialized header + """ + try: + if data_type in ["[str]"]: + data = ["" if d is None else d for d in data] + + output = self.serialize_data(data, data_type, **kwargs) + if data_type == "bool": + output = json.dumps(output) + except SerializationError as exc: + raise TypeError("{} must be type {}.".format(name, data_type)) from exc + return str(output) + + def serialize_data(self, data, data_type, **kwargs): + """Serialize generic data according to supplied data type. + + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :raises AttributeError: if required data is None. + :raises ValueError: if data is None + :raises SerializationError: if serialization fails. + :returns: The serialized data. + :rtype: str, int, float, bool, dict, list + """ + if data is None: + raise ValueError("No value for given attribute") + + try: + if data is CoreNull: + return None + if data_type in self.basic_types.values(): + return self.serialize_basic(data, data_type, **kwargs) + + if data_type in self.serialize_type: + return self.serialize_type[data_type](data, **kwargs) + + # If dependencies is empty, try with current data class + # It has to be a subclass of Enum anyway + enum_type = self.dependencies.get(data_type, data.__class__) + if issubclass(enum_type, Enum): + return Serializer.serialize_enum(data, enum_obj=enum_type) + + iter_type = data_type[0] + data_type[-1] + if iter_type in self.serialize_type: + return self.serialize_type[iter_type](data, data_type[1:-1], **kwargs) + + except (ValueError, TypeError) as err: + msg = "Unable to serialize value: {!r} as type: {!r}." + raise SerializationError(msg.format(data, data_type)) from err + return self._serialize(data, **kwargs) + + @classmethod + def _get_custom_serializers(cls, data_type, **kwargs): # pylint: disable=inconsistent-return-statements + custom_serializer = kwargs.get("basic_types_serializers", {}).get(data_type) + if custom_serializer: + return custom_serializer + if kwargs.get("is_xml", False): + return cls._xml_basic_types_serializers.get(data_type) + + @classmethod + def serialize_basic(cls, data, data_type, **kwargs): + """Serialize basic builting data type. + Serializes objects to str, int, float or bool. + + Possible kwargs: + - basic_types_serializers dict[str, callable] : If set, use the callable as serializer + - is_xml bool : If set, use xml_basic_types_serializers + + :param obj data: Object to be serialized. + :param str data_type: Type of object in the iterable. + :rtype: str, int, float, bool + :return: serialized object + """ + custom_serializer = cls._get_custom_serializers(data_type, **kwargs) + if custom_serializer: + return custom_serializer(data) + if data_type == "str": + return cls.serialize_unicode(data) + return eval(data_type)(data) # nosec # pylint: disable=eval-used + + @classmethod + def serialize_unicode(cls, data): + """Special handling for serializing unicode strings in Py2. + Encode to UTF-8 if unicode, otherwise handle as a str. + + :param str data: Object to be serialized. + :rtype: str + :return: serialized object + """ + try: # If I received an enum, return its value + return data.value + except AttributeError: + pass + + try: + if isinstance(data, unicode): # type: ignore + # Don't change it, JSON and XML ElementTree are totally able + # to serialize correctly u'' strings + return data + except NameError: + return str(data) + return str(data) + + def serialize_iter(self, data, iter_type, div=None, **kwargs): + """Serialize iterable. + + Supported kwargs: + - serialization_ctxt dict : The current entry of _attribute_map, or same format. + serialization_ctxt['type'] should be same as data_type. + - is_xml bool : If set, serialize as XML + + :param list data: Object to be serialized. + :param str iter_type: Type of object in the iterable. + :param str div: If set, this str will be used to combine the elements + in the iterable into a combined string. Default is 'None'. + Defaults to False. + :rtype: list, str + :return: serialized iterable + """ + if isinstance(data, str): + raise SerializationError("Refuse str type as a valid iter type.") + + serialization_ctxt = kwargs.get("serialization_ctxt", {}) + is_xml = kwargs.get("is_xml", False) + + serialized = [] + for d in data: + try: + serialized.append(self.serialize_data(d, iter_type, **kwargs)) + except ValueError as err: + if isinstance(err, SerializationError): + raise + serialized.append(None) + + if kwargs.get("do_quote", False): + serialized = ["" if s is None else quote(str(s), safe="") for s in serialized] + + if div: + serialized = ["" if s is None else str(s) for s in serialized] + serialized = div.join(serialized) + + if "xml" in serialization_ctxt or is_xml: + # XML serialization is more complicated + xml_desc = serialization_ctxt.get("xml", {}) + xml_name = xml_desc.get("name") + if not xml_name: + xml_name = serialization_ctxt["key"] + + # Create a wrap node if necessary (use the fact that Element and list have "append") + is_wrapped = xml_desc.get("wrapped", False) + node_name = xml_desc.get("itemsName", xml_name) + if is_wrapped: + final_result = _create_xml_node(xml_name, xml_desc.get("prefix", None), xml_desc.get("ns", None)) + else: + final_result = [] + # All list elements to "local_node" + for el in serialized: + if isinstance(el, ET.Element): + el_node = el + else: + el_node = _create_xml_node(node_name, xml_desc.get("prefix", None), xml_desc.get("ns", None)) + if el is not None: # Otherwise it writes "None" :-p + el_node.text = str(el) + final_result.append(el_node) + return final_result + return serialized + + def serialize_dict(self, attr, dict_type, **kwargs): + """Serialize a dictionary of objects. + + :param dict attr: Object to be serialized. + :param str dict_type: Type of object in the dictionary. + :rtype: dict + :return: serialized dictionary + """ + serialization_ctxt = kwargs.get("serialization_ctxt", {}) + serialized = {} + for key, value in attr.items(): + try: + serialized[self.serialize_unicode(key)] = self.serialize_data(value, dict_type, **kwargs) + except ValueError as err: + if isinstance(err, SerializationError): + raise + serialized[self.serialize_unicode(key)] = None + + if "xml" in serialization_ctxt: + # XML serialization is more complicated + xml_desc = serialization_ctxt["xml"] + xml_name = xml_desc["name"] + + final_result = _create_xml_node(xml_name, xml_desc.get("prefix", None), xml_desc.get("ns", None)) + for key, value in serialized.items(): + ET.SubElement(final_result, key).text = value + return final_result + + return serialized + + def serialize_object(self, attr, **kwargs): # pylint: disable=too-many-return-statements + """Serialize a generic object. + This will be handled as a dictionary. If object passed in is not + a basic type (str, int, float, dict, list) it will simply be + cast to str. + + :param dict attr: Object to be serialized. + :rtype: dict or str + :return: serialized object + """ + if attr is None: + return None + if isinstance(attr, ET.Element): + return attr + obj_type = type(attr) + if obj_type in self.basic_types: + return self.serialize_basic(attr, self.basic_types[obj_type], **kwargs) + if obj_type is _long_type: + return self.serialize_long(attr) + if obj_type is str: + return self.serialize_unicode(attr) + if obj_type is datetime.datetime: + return self.serialize_iso(attr) + if obj_type is datetime.date: + return self.serialize_date(attr) + if obj_type is datetime.time: + return self.serialize_time(attr) + if obj_type is datetime.timedelta: + return self.serialize_duration(attr) + if obj_type is decimal.Decimal: + return self.serialize_decimal(attr) + + # If it's a model or I know this dependency, serialize as a Model + if obj_type in self.dependencies.values() or isinstance(attr, Model): + return self._serialize(attr) + + if obj_type == dict: + serialized = {} + for key, value in attr.items(): + try: + serialized[self.serialize_unicode(key)] = self.serialize_object(value, **kwargs) + except ValueError: + serialized[self.serialize_unicode(key)] = None + return serialized + + if obj_type == list: + serialized = [] + for obj in attr: + try: + serialized.append(self.serialize_object(obj, **kwargs)) + except ValueError: + pass + return serialized + return str(attr) + + @staticmethod + def serialize_enum(attr, enum_obj=None): + try: + result = attr.value + except AttributeError: + result = attr + try: + enum_obj(result) # type: ignore + return result + except ValueError as exc: + for enum_value in enum_obj: # type: ignore + if enum_value.value.lower() == str(attr).lower(): + return enum_value.value + error = "{!r} is not valid value for enum {!r}" + raise SerializationError(error.format(attr, enum_obj)) from exc + + @staticmethod + def serialize_bytearray(attr, **kwargs): # pylint: disable=unused-argument + """Serialize bytearray into base-64 string. + + :param str attr: Object to be serialized. + :rtype: str + :return: serialized base64 + """ + return b64encode(attr).decode() + + @staticmethod + def serialize_base64(attr, **kwargs): # pylint: disable=unused-argument + """Serialize str into base-64 string. + + :param str attr: Object to be serialized. + :rtype: str + :return: serialized base64 + """ + encoded = b64encode(attr).decode("ascii") + return encoded.strip("=").replace("+", "-").replace("/", "_") + + @staticmethod + def serialize_decimal(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Decimal object to float. + + :param decimal attr: Object to be serialized. + :rtype: float + :return: serialized decimal + """ + return float(attr) + + @staticmethod + def serialize_long(attr, **kwargs): # pylint: disable=unused-argument + """Serialize long (Py2) or int (Py3). + + :param int attr: Object to be serialized. + :rtype: int/long + :return: serialized long + """ + return _long_type(attr) + + @staticmethod + def serialize_date(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Date object into ISO-8601 formatted string. + + :param Date attr: Object to be serialized. + :rtype: str + :return: serialized date + """ + if isinstance(attr, str): + attr = isodate.parse_date(attr) + t = "{:04}-{:02}-{:02}".format(attr.year, attr.month, attr.day) + return t + + @staticmethod + def serialize_time(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Time object into ISO-8601 formatted string. + + :param datetime.time attr: Object to be serialized. + :rtype: str + :return: serialized time + """ + if isinstance(attr, str): + attr = isodate.parse_time(attr) + t = "{:02}:{:02}:{:02}".format(attr.hour, attr.minute, attr.second) + if attr.microsecond: + t += ".{:02}".format(attr.microsecond) + return t + + @staticmethod + def serialize_duration(attr, **kwargs): # pylint: disable=unused-argument + """Serialize TimeDelta object into ISO-8601 formatted string. + + :param TimeDelta attr: Object to be serialized. + :rtype: str + :return: serialized duration + """ + if isinstance(attr, str): + attr = isodate.parse_duration(attr) + return isodate.duration_isoformat(attr) + + @staticmethod + def serialize_rfc(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Datetime object into RFC-1123 formatted string. + + :param Datetime attr: Object to be serialized. + :rtype: str + :raises TypeError: if format invalid. + :return: serialized rfc + """ + try: + if not attr.tzinfo: + _LOGGER.warning("Datetime with no tzinfo will be considered UTC.") + utc = attr.utctimetuple() + except AttributeError as exc: + raise TypeError("RFC1123 object must be valid Datetime object.") from exc + + return "{}, {:02} {} {:04} {:02}:{:02}:{:02} GMT".format( + Serializer.days[utc.tm_wday], + utc.tm_mday, + Serializer.months[utc.tm_mon], + utc.tm_year, + utc.tm_hour, + utc.tm_min, + utc.tm_sec, + ) + + @staticmethod + def serialize_iso(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Datetime object into ISO-8601 formatted string. + + :param Datetime attr: Object to be serialized. + :rtype: str + :raises SerializationError: if format invalid. + :return: serialized iso + """ + if isinstance(attr, str): + attr = isodate.parse_datetime(attr) + try: + if not attr.tzinfo: + _LOGGER.warning("Datetime with no tzinfo will be considered UTC.") + utc = attr.utctimetuple() + if utc.tm_year > 9999 or utc.tm_year < 1: + raise OverflowError("Hit max or min date") + + microseconds = str(attr.microsecond).rjust(6, "0").rstrip("0").ljust(3, "0") + if microseconds: + microseconds = "." + microseconds + date = "{:04}-{:02}-{:02}T{:02}:{:02}:{:02}".format( + utc.tm_year, utc.tm_mon, utc.tm_mday, utc.tm_hour, utc.tm_min, utc.tm_sec + ) + return date + microseconds + "Z" + except (ValueError, OverflowError) as err: + msg = "Unable to serialize datetime object." + raise SerializationError(msg) from err + except AttributeError as err: + msg = "ISO-8601 object must be valid Datetime object." + raise TypeError(msg) from err + + @staticmethod + def serialize_unix(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Datetime object into IntTime format. + This is represented as seconds. + + :param Datetime attr: Object to be serialized. + :rtype: int + :raises SerializationError: if format invalid + :return: serialied unix + """ + if isinstance(attr, int): + return attr + try: + if not attr.tzinfo: + _LOGGER.warning("Datetime with no tzinfo will be considered UTC.") + return int(calendar.timegm(attr.utctimetuple())) + except AttributeError as exc: + raise TypeError("Unix time object must be valid Datetime object.") from exc + + +def rest_key_extractor(attr, attr_desc, data): # pylint: disable=unused-argument + key = attr_desc["key"] + working_data = data + + while "." in key: + # Need the cast, as for some reasons "split" is typed as list[str | Any] + dict_keys = cast(List[str], _FLATTEN.split(key)) + if len(dict_keys) == 1: + key = _decode_attribute_map_key(dict_keys[0]) + break + working_key = _decode_attribute_map_key(dict_keys[0]) + working_data = working_data.get(working_key, data) + if working_data is None: + # If at any point while following flatten JSON path see None, it means + # that all properties under are None as well + return None + key = ".".join(dict_keys[1:]) + + return working_data.get(key) + + +def rest_key_case_insensitive_extractor( # pylint: disable=unused-argument, inconsistent-return-statements + attr, attr_desc, data +): + key = attr_desc["key"] + working_data = data + + while "." in key: + dict_keys = _FLATTEN.split(key) + if len(dict_keys) == 1: + key = _decode_attribute_map_key(dict_keys[0]) + break + working_key = _decode_attribute_map_key(dict_keys[0]) + working_data = attribute_key_case_insensitive_extractor(working_key, None, working_data) + if working_data is None: + # If at any point while following flatten JSON path see None, it means + # that all properties under are None as well + return None + key = ".".join(dict_keys[1:]) + + if working_data: + return attribute_key_case_insensitive_extractor(key, None, working_data) + + +def last_rest_key_extractor(attr, attr_desc, data): # pylint: disable=unused-argument + """Extract the attribute in "data" based on the last part of the JSON path key. + + :param str attr: The attribute to extract + :param dict attr_desc: The attribute description + :param dict data: The data to extract from + :rtype: object + :returns: The extracted attribute + """ + key = attr_desc["key"] + dict_keys = _FLATTEN.split(key) + return attribute_key_extractor(dict_keys[-1], None, data) + + +def last_rest_key_case_insensitive_extractor(attr, attr_desc, data): # pylint: disable=unused-argument + """Extract the attribute in "data" based on the last part of the JSON path key. + + This is the case insensitive version of "last_rest_key_extractor" + :param str attr: The attribute to extract + :param dict attr_desc: The attribute description + :param dict data: The data to extract from + :rtype: object + :returns: The extracted attribute + """ + key = attr_desc["key"] + dict_keys = _FLATTEN.split(key) + return attribute_key_case_insensitive_extractor(dict_keys[-1], None, data) + + +def attribute_key_extractor(attr, _, data): + return data.get(attr) + + +def attribute_key_case_insensitive_extractor(attr, _, data): + found_key = None + lower_attr = attr.lower() + for key in data: + if lower_attr == key.lower(): + found_key = key + break + + return data.get(found_key) + + +def _extract_name_from_internal_type(internal_type): + """Given an internal type XML description, extract correct XML name with namespace. + + :param dict internal_type: An model type + :rtype: tuple + :returns: A tuple XML name + namespace dict + """ + internal_type_xml_map = getattr(internal_type, "_xml_map", {}) + xml_name = internal_type_xml_map.get("name", internal_type.__name__) + xml_ns = internal_type_xml_map.get("ns", None) + if xml_ns: + xml_name = "{{{}}}{}".format(xml_ns, xml_name) + return xml_name + + +def xml_key_extractor(attr, attr_desc, data): # pylint: disable=unused-argument,too-many-return-statements + if isinstance(data, dict): + return None + + # Test if this model is XML ready first + if not isinstance(data, ET.Element): + return None + + xml_desc = attr_desc.get("xml", {}) + xml_name = xml_desc.get("name", attr_desc["key"]) + + # Look for a children + is_iter_type = attr_desc["type"].startswith("[") + is_wrapped = xml_desc.get("wrapped", False) + internal_type = attr_desc.get("internalType", None) + internal_type_xml_map = getattr(internal_type, "_xml_map", {}) + + # Integrate namespace if necessary + xml_ns = xml_desc.get("ns", internal_type_xml_map.get("ns", None)) + if xml_ns: + xml_name = "{{{}}}{}".format(xml_ns, xml_name) + + # If it's an attribute, that's simple + if xml_desc.get("attr", False): + return data.get(xml_name) + + # If it's x-ms-text, that's simple too + if xml_desc.get("text", False): + return data.text + + # Scenario where I take the local name: + # - Wrapped node + # - Internal type is an enum (considered basic types) + # - Internal type has no XML/Name node + if is_wrapped or (internal_type and (issubclass(internal_type, Enum) or "name" not in internal_type_xml_map)): + children = data.findall(xml_name) + # If internal type has a local name and it's not a list, I use that name + elif not is_iter_type and internal_type and "name" in internal_type_xml_map: + xml_name = _extract_name_from_internal_type(internal_type) + children = data.findall(xml_name) + # That's an array + else: + if internal_type: # Complex type, ignore itemsName and use the complex type name + items_name = _extract_name_from_internal_type(internal_type) + else: + items_name = xml_desc.get("itemsName", xml_name) + children = data.findall(items_name) + + if len(children) == 0: + if is_iter_type: + if is_wrapped: + return None # is_wrapped no node, we want None + return [] # not wrapped, assume empty list + return None # Assume it's not there, maybe an optional node. + + # If is_iter_type and not wrapped, return all found children + if is_iter_type: + if not is_wrapped: + return children + # Iter and wrapped, should have found one node only (the wrap one) + if len(children) != 1: + raise DeserializationError( + "Tried to deserialize an array not wrapped, and found several nodes '{}'. Maybe you should declare this array as wrapped?".format( + xml_name + ) + ) + return list(children[0]) # Might be empty list and that's ok. + + # Here it's not a itertype, we should have found one element only or empty + if len(children) > 1: + raise DeserializationError("Find several XML '{}' where it was not expected".format(xml_name)) + return children[0] + + +class Deserializer: + """Response object model deserializer. + + :param dict classes: Class type dictionary for deserializing complex types. + :ivar list key_extractors: Ordered list of extractors to be used by this deserializer. + """ + + basic_types = {str: "str", int: "int", bool: "bool", float: "float"} + + valid_date = re.compile(r"\d{4}[-]\d{2}[-]\d{2}T\d{2}:\d{2}:\d{2}\.?\d*Z?[-+]?[\d{2}]?:?[\d{2}]?") + + def __init__(self, classes: Optional[Mapping[str, type]] = None) -> None: + self.deserialize_type = { + "iso-8601": Deserializer.deserialize_iso, + "rfc-1123": Deserializer.deserialize_rfc, + "unix-time": Deserializer.deserialize_unix, + "duration": Deserializer.deserialize_duration, + "date": Deserializer.deserialize_date, + "time": Deserializer.deserialize_time, + "decimal": Deserializer.deserialize_decimal, + "long": Deserializer.deserialize_long, + "bytearray": Deserializer.deserialize_bytearray, + "base64": Deserializer.deserialize_base64, + "object": self.deserialize_object, + "[]": self.deserialize_iter, + "{}": self.deserialize_dict, + } + self.deserialize_expected_types = { + "duration": (isodate.Duration, datetime.timedelta), + "iso-8601": (datetime.datetime), + } + self.dependencies: Dict[str, type] = dict(classes) if classes else {} + self.key_extractors = [rest_key_extractor, xml_key_extractor] + # Additional properties only works if the "rest_key_extractor" is used to + # extract the keys. Making it to work whatever the key extractor is too much + # complicated, with no real scenario for now. + # So adding a flag to disable additional properties detection. This flag should be + # used if your expect the deserialization to NOT come from a JSON REST syntax. + # Otherwise, result are unexpected + self.additional_properties_detection = True + + def __call__(self, target_obj, response_data, content_type=None): + """Call the deserializer to process a REST response. + + :param str target_obj: Target data type to deserialize to. + :param requests.Response response_data: REST response object. + :param str content_type: Swagger "produces" if available. + :raises DeserializationError: if deserialization fails. + :return: Deserialized object. + :rtype: object + """ + data = self._unpack_content(response_data, content_type) + return self._deserialize(target_obj, data) + + def _deserialize(self, target_obj, data): # pylint: disable=inconsistent-return-statements + """Call the deserializer on a model. + + Data needs to be already deserialized as JSON or XML ElementTree + + :param str target_obj: Target data type to deserialize to. + :param object data: Object to deserialize. + :raises DeserializationError: if deserialization fails. + :return: Deserialized object. + :rtype: object + """ + # This is already a model, go recursive just in case + if hasattr(data, "_attribute_map"): + constants = [name for name, config in getattr(data, "_validation", {}).items() if config.get("constant")] + try: + for attr, mapconfig in data._attribute_map.items(): # pylint: disable=protected-access + if attr in constants: + continue + value = getattr(data, attr) + if value is None: + continue + local_type = mapconfig["type"] + internal_data_type = local_type.strip("[]{}") + if internal_data_type not in self.dependencies or isinstance(internal_data_type, Enum): + continue + setattr(data, attr, self._deserialize(local_type, value)) + return data + except AttributeError: + return + + response, class_name = self._classify_target(target_obj, data) + + if isinstance(response, str): + return self.deserialize_data(data, response) + if isinstance(response, type) and issubclass(response, Enum): + return self.deserialize_enum(data, response) + + if data is None or data is CoreNull: + return data + try: + attributes = response._attribute_map # type: ignore # pylint: disable=protected-access + d_attrs = {} + for attr, attr_desc in attributes.items(): + # Check empty string. If it's not empty, someone has a real "additionalProperties"... + if attr == "additional_properties" and attr_desc["key"] == "": + continue + raw_value = None + # Enhance attr_desc with some dynamic data + attr_desc = attr_desc.copy() # Do a copy, do not change the real one + internal_data_type = attr_desc["type"].strip("[]{}") + if internal_data_type in self.dependencies: + attr_desc["internalType"] = self.dependencies[internal_data_type] + + for key_extractor in self.key_extractors: + found_value = key_extractor(attr, attr_desc, data) + if found_value is not None: + if raw_value is not None and raw_value != found_value: + msg = ( + "Ignoring extracted value '%s' from %s for key '%s'" + " (duplicate extraction, follow extractors order)" + ) + _LOGGER.warning(msg, found_value, key_extractor, attr) + continue + raw_value = found_value + + value = self.deserialize_data(raw_value, attr_desc["type"]) + d_attrs[attr] = value + except (AttributeError, TypeError, KeyError) as err: + msg = "Unable to deserialize to object: " + class_name # type: ignore + raise DeserializationError(msg) from err + additional_properties = self._build_additional_properties(attributes, data) + return self._instantiate_model(response, d_attrs, additional_properties) + + def _build_additional_properties(self, attribute_map, data): + if not self.additional_properties_detection: + return None + if "additional_properties" in attribute_map and attribute_map.get("additional_properties", {}).get("key") != "": + # Check empty string. If it's not empty, someone has a real "additionalProperties" + return None + if isinstance(data, ET.Element): + data = {el.tag: el.text for el in data} + + known_keys = { + _decode_attribute_map_key(_FLATTEN.split(desc["key"])[0]) + for desc in attribute_map.values() + if desc["key"] != "" + } + present_keys = set(data.keys()) + missing_keys = present_keys - known_keys + return {key: data[key] for key in missing_keys} + + def _classify_target(self, target, data): + """Check to see whether the deserialization target object can + be classified into a subclass. + Once classification has been determined, initialize object. + + :param str target: The target object type to deserialize to. + :param str/dict data: The response data to deserialize. + :return: The classified target object and its class name. + :rtype: tuple + """ + if target is None: + return None, None + + if isinstance(target, str): + try: + target = self.dependencies[target] + except KeyError: + return target, target + + try: + target = target._classify(data, self.dependencies) # type: ignore # pylint: disable=protected-access + except AttributeError: + pass # Target is not a Model, no classify + return target, target.__class__.__name__ # type: ignore + + def failsafe_deserialize(self, target_obj, data, content_type=None): + """Ignores any errors encountered in deserialization, + and falls back to not deserializing the object. Recommended + for use in error deserialization, as we want to return the + HttpResponseError to users, and not have them deal with + a deserialization error. + + :param str target_obj: The target object type to deserialize to. + :param str/dict data: The response data to deserialize. + :param str content_type: Swagger "produces" if available. + :return: Deserialized object. + :rtype: object + """ + try: + return self(target_obj, data, content_type=content_type) + except: # pylint: disable=bare-except + _LOGGER.debug( + "Ran into a deserialization error. Ignoring since this is failsafe deserialization", exc_info=True + ) + return None + + @staticmethod + def _unpack_content(raw_data, content_type=None): + """Extract the correct structure for deserialization. + + If raw_data is a PipelineResponse, try to extract the result of RawDeserializer. + if we can't, raise. Your Pipeline should have a RawDeserializer. + + If not a pipeline response and raw_data is bytes or string, use content-type + to decode it. If no content-type, try JSON. + + If raw_data is something else, bypass all logic and return it directly. + + :param obj raw_data: Data to be processed. + :param str content_type: How to parse if raw_data is a string/bytes. + :raises JSONDecodeError: If JSON is requested and parsing is impossible. + :raises UnicodeDecodeError: If bytes is not UTF8 + :rtype: object + :return: Unpacked content. + """ + # Assume this is enough to detect a Pipeline Response without importing it + context = getattr(raw_data, "context", {}) + if context: + if RawDeserializer.CONTEXT_NAME in context: + return context[RawDeserializer.CONTEXT_NAME] + raise ValueError("This pipeline didn't have the RawDeserializer policy; can't deserialize") + + # Assume this is enough to recognize universal_http.ClientResponse without importing it + if hasattr(raw_data, "body"): + return RawDeserializer.deserialize_from_http_generics(raw_data.text(), raw_data.headers) + + # Assume this enough to recognize requests.Response without importing it. + if hasattr(raw_data, "_content_consumed"): + return RawDeserializer.deserialize_from_http_generics(raw_data.text, raw_data.headers) + + if isinstance(raw_data, (str, bytes)) or hasattr(raw_data, "read"): + return RawDeserializer.deserialize_from_text(raw_data, content_type) # type: ignore + return raw_data + + def _instantiate_model(self, response, attrs, additional_properties=None): + """Instantiate a response model passing in deserialized args. + + :param Response response: The response model class. + :param dict attrs: The deserialized response attributes. + :param dict additional_properties: Additional properties to be set. + :rtype: Response + :return: The instantiated response model. + """ + if callable(response): + subtype = getattr(response, "_subtype_map", {}) + try: + readonly = [ + k + for k, v in response._validation.items() # pylint: disable=protected-access # type: ignore + if v.get("readonly") + ] + const = [ + k + for k, v in response._validation.items() # pylint: disable=protected-access # type: ignore + if v.get("constant") + ] + kwargs = {k: v for k, v in attrs.items() if k not in subtype and k not in readonly + const} + response_obj = response(**kwargs) + for attr in readonly: + setattr(response_obj, attr, attrs.get(attr)) + if additional_properties: + response_obj.additional_properties = additional_properties # type: ignore + return response_obj + except TypeError as err: + msg = "Unable to deserialize {} into model {}. ".format(kwargs, response) # type: ignore + raise DeserializationError(msg + str(err)) from err + else: + try: + for attr, value in attrs.items(): + setattr(response, attr, value) + return response + except Exception as exp: + msg = "Unable to populate response model. " + msg += "Type: {}, Error: {}".format(type(response), exp) + raise DeserializationError(msg) from exp + + def deserialize_data(self, data, data_type): # pylint: disable=too-many-return-statements + """Process data for deserialization according to data type. + + :param str data: The response string to be deserialized. + :param str data_type: The type to deserialize to. + :raises DeserializationError: if deserialization fails. + :return: Deserialized object. + :rtype: object + """ + if data is None: + return data + + try: + if not data_type: + return data + if data_type in self.basic_types.values(): + return self.deserialize_basic(data, data_type) + if data_type in self.deserialize_type: + if isinstance(data, self.deserialize_expected_types.get(data_type, tuple())): + return data + + is_a_text_parsing_type = lambda x: x not in [ # pylint: disable=unnecessary-lambda-assignment + "object", + "[]", + r"{}", + ] + if isinstance(data, ET.Element) and is_a_text_parsing_type(data_type) and not data.text: + return None + data_val = self.deserialize_type[data_type](data) + return data_val + + iter_type = data_type[0] + data_type[-1] + if iter_type in self.deserialize_type: + return self.deserialize_type[iter_type](data, data_type[1:-1]) + + obj_type = self.dependencies[data_type] + if issubclass(obj_type, Enum): + if isinstance(data, ET.Element): + data = data.text + return self.deserialize_enum(data, obj_type) + + except (ValueError, TypeError, AttributeError) as err: + msg = "Unable to deserialize response data." + msg += " Data: {}, {}".format(data, data_type) + raise DeserializationError(msg) from err + return self._deserialize(obj_type, data) + + def deserialize_iter(self, attr, iter_type): + """Deserialize an iterable. + + :param list attr: Iterable to be deserialized. + :param str iter_type: The type of object in the iterable. + :return: Deserialized iterable. + :rtype: list + """ + if attr is None: + return None + if isinstance(attr, ET.Element): # If I receive an element here, get the children + attr = list(attr) + if not isinstance(attr, (list, set)): + raise DeserializationError("Cannot deserialize as [{}] an object of type {}".format(iter_type, type(attr))) + return [self.deserialize_data(a, iter_type) for a in attr] + + def deserialize_dict(self, attr, dict_type): + """Deserialize a dictionary. + + :param dict/list attr: Dictionary to be deserialized. Also accepts + a list of key, value pairs. + :param str dict_type: The object type of the items in the dictionary. + :return: Deserialized dictionary. + :rtype: dict + """ + if isinstance(attr, list): + return {x["key"]: self.deserialize_data(x["value"], dict_type) for x in attr} + + if isinstance(attr, ET.Element): + # Transform value into {"Key": "value"} + attr = {el.tag: el.text for el in attr} + return {k: self.deserialize_data(v, dict_type) for k, v in attr.items()} + + def deserialize_object(self, attr, **kwargs): # pylint: disable=too-many-return-statements + """Deserialize a generic object. + This will be handled as a dictionary. + + :param dict attr: Dictionary to be deserialized. + :return: Deserialized object. + :rtype: dict + :raises TypeError: if non-builtin datatype encountered. + """ + if attr is None: + return None + if isinstance(attr, ET.Element): + # Do no recurse on XML, just return the tree as-is + return attr + if isinstance(attr, str): + return self.deserialize_basic(attr, "str") + obj_type = type(attr) + if obj_type in self.basic_types: + return self.deserialize_basic(attr, self.basic_types[obj_type]) + if obj_type is _long_type: + return self.deserialize_long(attr) + + if obj_type == dict: + deserialized = {} + for key, value in attr.items(): + try: + deserialized[key] = self.deserialize_object(value, **kwargs) + except ValueError: + deserialized[key] = None + return deserialized + + if obj_type == list: + deserialized = [] + for obj in attr: + try: + deserialized.append(self.deserialize_object(obj, **kwargs)) + except ValueError: + pass + return deserialized + + error = "Cannot deserialize generic object with type: " + raise TypeError(error + str(obj_type)) + + def deserialize_basic(self, attr, data_type): # pylint: disable=too-many-return-statements + """Deserialize basic builtin data type from string. + Will attempt to convert to str, int, float and bool. + This function will also accept '1', '0', 'true' and 'false' as + valid bool values. + + :param str attr: response string to be deserialized. + :param str data_type: deserialization data type. + :return: Deserialized basic type. + :rtype: str, int, float or bool + :raises TypeError: if string format is not valid. + """ + # If we're here, data is supposed to be a basic type. + # If it's still an XML node, take the text + if isinstance(attr, ET.Element): + attr = attr.text + if not attr: + if data_type == "str": + # None or '', node is empty string. + return "" + # None or '', node with a strong type is None. + # Don't try to model "empty bool" or "empty int" + return None + + if data_type == "bool": + if attr in [True, False, 1, 0]: + return bool(attr) + if isinstance(attr, str): + if attr.lower() in ["true", "1"]: + return True + if attr.lower() in ["false", "0"]: + return False + raise TypeError("Invalid boolean value: {}".format(attr)) + + if data_type == "str": + return self.deserialize_unicode(attr) + return eval(data_type)(attr) # nosec # pylint: disable=eval-used + + @staticmethod + def deserialize_unicode(data): + """Preserve unicode objects in Python 2, otherwise return data + as a string. + + :param str data: response string to be deserialized. + :return: Deserialized string. + :rtype: str or unicode + """ + # We might be here because we have an enum modeled as string, + # and we try to deserialize a partial dict with enum inside + if isinstance(data, Enum): + return data + + # Consider this is real string + try: + if isinstance(data, unicode): # type: ignore + return data + except NameError: + return str(data) + return str(data) + + @staticmethod + def deserialize_enum(data, enum_obj): + """Deserialize string into enum object. + + If the string is not a valid enum value it will be returned as-is + and a warning will be logged. + + :param str data: Response string to be deserialized. If this value is + None or invalid it will be returned as-is. + :param Enum enum_obj: Enum object to deserialize to. + :return: Deserialized enum object. + :rtype: Enum + """ + if isinstance(data, enum_obj) or data is None: + return data + if isinstance(data, Enum): + data = data.value + if isinstance(data, int): + # Workaround. We might consider remove it in the future. + try: + return list(enum_obj.__members__.values())[data] + except IndexError as exc: + error = "{!r} is not a valid index for enum {!r}" + raise DeserializationError(error.format(data, enum_obj)) from exc + try: + return enum_obj(str(data)) + except ValueError: + for enum_value in enum_obj: + if enum_value.value.lower() == str(data).lower(): + return enum_value + # We don't fail anymore for unknown value, we deserialize as a string + _LOGGER.warning("Deserializer is not able to find %s as valid enum in %s", data, enum_obj) + return Deserializer.deserialize_unicode(data) + + @staticmethod + def deserialize_bytearray(attr): + """Deserialize string into bytearray. + + :param str attr: response string to be deserialized. + :return: Deserialized bytearray + :rtype: bytearray + :raises TypeError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + return bytearray(b64decode(attr)) # type: ignore + + @staticmethod + def deserialize_base64(attr): + """Deserialize base64 encoded string into string. + + :param str attr: response string to be deserialized. + :return: Deserialized base64 string + :rtype: bytearray + :raises TypeError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + padding = "=" * (3 - (len(attr) + 3) % 4) # type: ignore + attr = attr + padding # type: ignore + encoded = attr.replace("-", "+").replace("_", "/") + return b64decode(encoded) + + @staticmethod + def deserialize_decimal(attr): + """Deserialize string into Decimal object. + + :param str attr: response string to be deserialized. + :return: Deserialized decimal + :raises DeserializationError: if string format invalid. + :rtype: decimal + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + return decimal.Decimal(str(attr)) # type: ignore + except decimal.DecimalException as err: + msg = "Invalid decimal {}".format(attr) + raise DeserializationError(msg) from err + + @staticmethod + def deserialize_long(attr): + """Deserialize string into long (Py2) or int (Py3). + + :param str attr: response string to be deserialized. + :return: Deserialized int + :rtype: long or int + :raises ValueError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + return _long_type(attr) # type: ignore + + @staticmethod + def deserialize_duration(attr): + """Deserialize ISO-8601 formatted string into TimeDelta object. + + :param str attr: response string to be deserialized. + :return: Deserialized duration + :rtype: TimeDelta + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + duration = isodate.parse_duration(attr) + except (ValueError, OverflowError, AttributeError) as err: + msg = "Cannot deserialize duration object." + raise DeserializationError(msg) from err + return duration + + @staticmethod + def deserialize_date(attr): + """Deserialize ISO-8601 formatted string into Date object. + + :param str attr: response string to be deserialized. + :return: Deserialized date + :rtype: Date + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + if re.search(r"[^\W\d_]", attr, re.I + re.U): # type: ignore + raise DeserializationError("Date must have only digits and -. Received: %s" % attr) + # This must NOT use defaultmonth/defaultday. Using None ensure this raises an exception. + return isodate.parse_date(attr, defaultmonth=0, defaultday=0) + + @staticmethod + def deserialize_time(attr): + """Deserialize ISO-8601 formatted string into time object. + + :param str attr: response string to be deserialized. + :return: Deserialized time + :rtype: datetime.time + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + if re.search(r"[^\W\d_]", attr, re.I + re.U): # type: ignore + raise DeserializationError("Date must have only digits and -. Received: %s" % attr) + return isodate.parse_time(attr) + + @staticmethod + def deserialize_rfc(attr): + """Deserialize RFC-1123 formatted string into Datetime object. + + :param str attr: response string to be deserialized. + :return: Deserialized RFC datetime + :rtype: Datetime + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + parsed_date = email.utils.parsedate_tz(attr) # type: ignore + date_obj = datetime.datetime( + *parsed_date[:6], tzinfo=datetime.timezone(datetime.timedelta(minutes=(parsed_date[9] or 0) / 60)) + ) + if not date_obj.tzinfo: + date_obj = date_obj.astimezone(tz=TZ_UTC) + except ValueError as err: + msg = "Cannot deserialize to rfc datetime object." + raise DeserializationError(msg) from err + return date_obj + + @staticmethod + def deserialize_iso(attr): + """Deserialize ISO-8601 formatted string into Datetime object. + + :param str attr: response string to be deserialized. + :return: Deserialized ISO datetime + :rtype: Datetime + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + attr = attr.upper() # type: ignore + match = Deserializer.valid_date.match(attr) + if not match: + raise ValueError("Invalid datetime string: " + attr) + + check_decimal = attr.split(".") + if len(check_decimal) > 1: + decimal_str = "" + for digit in check_decimal[1]: + if digit.isdigit(): + decimal_str += digit + else: + break + if len(decimal_str) > 6: + attr = attr.replace(decimal_str, decimal_str[0:6]) + + date_obj = isodate.parse_datetime(attr) + test_utc = date_obj.utctimetuple() + if test_utc.tm_year > 9999 or test_utc.tm_year < 1: + raise OverflowError("Hit max or min date") + except (ValueError, OverflowError, AttributeError) as err: + msg = "Cannot deserialize datetime object." + raise DeserializationError(msg) from err + return date_obj + + @staticmethod + def deserialize_unix(attr): + """Serialize Datetime object into IntTime format. + This is represented as seconds. + + :param int attr: Object to be serialized. + :return: Deserialized datetime + :rtype: Datetime + :raises DeserializationError: if format invalid + """ + if isinstance(attr, ET.Element): + attr = int(attr.text) # type: ignore + try: + attr = int(attr) + date_obj = datetime.datetime.fromtimestamp(attr, TZ_UTC) + except ValueError as err: + msg = "Cannot deserialize to unix datetime object." + raise DeserializationError(msg) from err + return date_obj diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ParameterizedEndpointVersionTolerant/parameterizedendpointversiontolerant/_utils/utils.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ParameterizedEndpointVersionTolerant/parameterizedendpointversiontolerant/_utils/utils.py new file mode 100644 index 00000000000..39b612f39a9 --- /dev/null +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ParameterizedEndpointVersionTolerant/parameterizedendpointversiontolerant/_utils/utils.py @@ -0,0 +1,25 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from abc import ABC +from typing import Generic, TYPE_CHECKING, TypeVar + +if TYPE_CHECKING: + from .serialization import Deserializer, Serializer + + +TClient = TypeVar("TClient") +TConfig = TypeVar("TConfig") + + +class ClientMixinABC(ABC, Generic[TClient, TConfig]): + """DO NOT use this class. It is for internal typing use only.""" + + _client: TClient + _config: TConfig + _serialize: "Serializer" + _deserialize: "Deserializer" diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ParameterizedEndpointVersionTolerant/parameterizedendpointversiontolerant/_vendor.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ParameterizedEndpointVersionTolerant/parameterizedendpointversiontolerant/_vendor.py deleted file mode 100644 index a9e7ad280de..00000000000 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ParameterizedEndpointVersionTolerant/parameterizedendpointversiontolerant/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) AutoRest Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import ParmaterizedEndpointClientConfiguration - -if TYPE_CHECKING: - from azure.core import PipelineClient - - from ._serialization import Deserializer, Serializer - - -class ParmaterizedEndpointClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "PipelineClient" - _config: ParmaterizedEndpointClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ParameterizedEndpointVersionTolerant/parameterizedendpointversiontolerant/aio/_client.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ParameterizedEndpointVersionTolerant/parameterizedendpointversiontolerant/aio/_client.py index ce95df6636a..362eff8b6c2 100644 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ParameterizedEndpointVersionTolerant/parameterizedendpointversiontolerant/aio/_client.py +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ParameterizedEndpointVersionTolerant/parameterizedendpointversiontolerant/aio/_client.py @@ -14,7 +14,7 @@ from azure.core.pipeline import policies from azure.core.rest import AsyncHttpResponse, HttpRequest -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import ParmaterizedEndpointClientConfiguration from ._operations import ParmaterizedEndpointClientOperationsMixin diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ParameterizedEndpointVersionTolerant/parameterizedendpointversiontolerant/aio/_operations/_operations.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ParameterizedEndpointVersionTolerant/parameterizedendpointversiontolerant/aio/_operations/_operations.py index 8cb49168bf3..498fbac0437 100644 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ParameterizedEndpointVersionTolerant/parameterizedendpointversiontolerant/aio/_operations/_operations.py +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ParameterizedEndpointVersionTolerant/parameterizedendpointversiontolerant/aio/_operations/_operations.py @@ -9,6 +9,7 @@ from collections.abc import MutableMapping from typing import Any, Callable, Dict, Optional, TypeVar +from azure.core import AsyncPipelineClient from azure.core.exceptions import ( ClientAuthenticationError, HttpResponseError, @@ -22,13 +23,16 @@ from azure.core.tracing.decorator_async import distributed_trace_async from ..._operations._operations import build_parmaterized_endpoint_get_request -from .._vendor import ParmaterizedEndpointClientMixinABC +from ..._utils.utils import ClientMixinABC +from .._configuration import ParmaterizedEndpointClientConfiguration T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, AsyncHttpResponse], T, Dict[str, Any]], Any]] -class ParmaterizedEndpointClientOperationsMixin(ParmaterizedEndpointClientMixinABC): # pylint: disable=name-too-long +class ParmaterizedEndpointClientOperationsMixin( # pylint: disable=name-too-long + ClientMixinABC[AsyncPipelineClient, ParmaterizedEndpointClientConfiguration] +): @distributed_trace_async async def get(self, **kwargs: Any) -> None: diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ParameterizedEndpointVersionTolerant/parameterizedendpointversiontolerant/aio/_vendor.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ParameterizedEndpointVersionTolerant/parameterizedendpointversiontolerant/aio/_vendor.py deleted file mode 100644 index 32921e9fc7d..00000000000 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ParameterizedEndpointVersionTolerant/parameterizedendpointversiontolerant/aio/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) AutoRest Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import ParmaterizedEndpointClientConfiguration - -if TYPE_CHECKING: - from azure.core import AsyncPipelineClient - - from .._serialization import Deserializer, Serializer - - -class ParmaterizedEndpointClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "AsyncPipelineClient" - _config: ParmaterizedEndpointClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ReportVersionTolerant/reportversiontolerant/_client.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ReportVersionTolerant/reportversiontolerant/_client.py index 476be5fbde7..aaebb3d12d1 100644 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ReportVersionTolerant/reportversiontolerant/_client.py +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ReportVersionTolerant/reportversiontolerant/_client.py @@ -16,7 +16,7 @@ from ._configuration import AutoRestReportServiceConfiguration from ._operations import AutoRestReportServiceOperationsMixin -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer class AutoRestReportService(AutoRestReportServiceOperationsMixin): # pylint: disable=client-accepts-api-version-keyword diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ReportVersionTolerant/reportversiontolerant/_operations/_operations.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ReportVersionTolerant/reportversiontolerant/_operations/_operations.py index 8e9632e0672..507feac22e4 100644 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ReportVersionTolerant/reportversiontolerant/_operations/_operations.py +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ReportVersionTolerant/reportversiontolerant/_operations/_operations.py @@ -8,6 +8,7 @@ from collections.abc import MutableMapping from typing import Any, Callable, Dict, Optional, TypeVar, cast +from azure.core import PipelineClient from azure.core.exceptions import ( ClientAuthenticationError, HttpResponseError, @@ -21,8 +22,9 @@ from azure.core.tracing.decorator import distributed_trace from azure.core.utils import case_insensitive_dict -from .._serialization import Serializer -from .._vendor import AutoRestReportServiceMixinABC +from .._configuration import AutoRestReportServiceConfiguration +from .._utils.serialization import Serializer +from .._utils.utils import ClientMixinABC T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] @@ -73,7 +75,7 @@ def build_auto_rest_report_service_get_optional_report_request( # pylint: disab return HttpRequest(method="GET", url=_url, params=_params, headers=_headers, **kwargs) -class AutoRestReportServiceOperationsMixin(AutoRestReportServiceMixinABC): +class AutoRestReportServiceOperationsMixin(ClientMixinABC[PipelineClient, AutoRestReportServiceConfiguration]): @distributed_trace def get_report(self, *, qualifier: Optional[str] = None, **kwargs: Any) -> Dict[str, int]: diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ReportVersionTolerant/reportversiontolerant/_utils/__init__.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ReportVersionTolerant/reportversiontolerant/_utils/__init__.py new file mode 100644 index 00000000000..0af9b28f660 --- /dev/null +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ReportVersionTolerant/reportversiontolerant/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ReportVersionTolerant/reportversiontolerant/_utils/serialization.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ReportVersionTolerant/reportversiontolerant/_utils/serialization.py new file mode 100644 index 00000000000..f5187701d7b --- /dev/null +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ReportVersionTolerant/reportversiontolerant/_utils/serialization.py @@ -0,0 +1,2032 @@ +# pylint: disable=line-too-long,useless-suppression,too-many-lines +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +# pyright: reportUnnecessaryTypeIgnoreComment=false + +from base64 import b64decode, b64encode +import calendar +import datetime +import decimal +import email +from enum import Enum +import json +import logging +import re +import sys +import codecs +from typing import ( + Dict, + Any, + cast, + Optional, + Union, + AnyStr, + IO, + Mapping, + Callable, + MutableMapping, + List, +) + +try: + from urllib import quote # type: ignore +except ImportError: + from urllib.parse import quote +import xml.etree.ElementTree as ET + +import isodate # type: ignore +from typing_extensions import Self + +from azure.core.exceptions import DeserializationError, SerializationError +from azure.core.serialization import NULL as CoreNull + +_BOM = codecs.BOM_UTF8.decode(encoding="utf-8") + +JSON = MutableMapping[str, Any] + + +class RawDeserializer: + + # Accept "text" because we're open minded people... + JSON_REGEXP = re.compile(r"^(application|text)/([a-z+.]+\+)?json$") + + # Name used in context + CONTEXT_NAME = "deserialized_data" + + @classmethod + def deserialize_from_text(cls, data: Optional[Union[AnyStr, IO]], content_type: Optional[str] = None) -> Any: + """Decode data according to content-type. + + Accept a stream of data as well, but will be load at once in memory for now. + + If no content-type, will return the string version (not bytes, not stream) + + :param data: Input, could be bytes or stream (will be decoded with UTF8) or text + :type data: str or bytes or IO + :param str content_type: The content type. + :return: The deserialized data. + :rtype: object + """ + if hasattr(data, "read"): + # Assume a stream + data = cast(IO, data).read() + + if isinstance(data, bytes): + data_as_str = data.decode(encoding="utf-8-sig") + else: + # Explain to mypy the correct type. + data_as_str = cast(str, data) + + # Remove Byte Order Mark if present in string + data_as_str = data_as_str.lstrip(_BOM) + + if content_type is None: + return data + + if cls.JSON_REGEXP.match(content_type): + try: + return json.loads(data_as_str) + except ValueError as err: + raise DeserializationError("JSON is invalid: {}".format(err), err) from err + elif "xml" in (content_type or []): + try: + + try: + if isinstance(data, unicode): # type: ignore + # If I'm Python 2.7 and unicode XML will scream if I try a "fromstring" on unicode string + data_as_str = data_as_str.encode(encoding="utf-8") # type: ignore + except NameError: + pass + + return ET.fromstring(data_as_str) # nosec + except ET.ParseError as err: + # It might be because the server has an issue, and returned JSON with + # content-type XML.... + # So let's try a JSON load, and if it's still broken + # let's flow the initial exception + def _json_attemp(data): + try: + return True, json.loads(data) + except ValueError: + return False, None # Don't care about this one + + success, json_result = _json_attemp(data) + if success: + return json_result + # If i'm here, it's not JSON, it's not XML, let's scream + # and raise the last context in this block (the XML exception) + # The function hack is because Py2.7 messes up with exception + # context otherwise. + _LOGGER.critical("Wasn't XML not JSON, failing") + raise DeserializationError("XML is invalid") from err + elif content_type.startswith("text/"): + return data_as_str + raise DeserializationError("Cannot deserialize content-type: {}".format(content_type)) + + @classmethod + def deserialize_from_http_generics(cls, body_bytes: Optional[Union[AnyStr, IO]], headers: Mapping) -> Any: + """Deserialize from HTTP response. + + Use bytes and headers to NOT use any requests/aiohttp or whatever + specific implementation. + Headers will tested for "content-type" + + :param bytes body_bytes: The body of the response. + :param dict headers: The headers of the response. + :returns: The deserialized data. + :rtype: object + """ + # Try to use content-type from headers if available + content_type = None + if "content-type" in headers: + content_type = headers["content-type"].split(";")[0].strip().lower() + # Ouch, this server did not declare what it sent... + # Let's guess it's JSON... + # Also, since Autorest was considering that an empty body was a valid JSON, + # need that test as well.... + else: + content_type = "application/json" + + if body_bytes: + return cls.deserialize_from_text(body_bytes, content_type) + return None + + +_LOGGER = logging.getLogger(__name__) + +try: + _long_type = long # type: ignore +except NameError: + _long_type = int + +TZ_UTC = datetime.timezone.utc + +_FLATTEN = re.compile(r"(? None: + self.additional_properties: Optional[Dict[str, Any]] = {} + for k in kwargs: # pylint: disable=consider-using-dict-items + if k not in self._attribute_map: + _LOGGER.warning("%s is not a known attribute of class %s and will be ignored", k, self.__class__) + elif k in self._validation and self._validation[k].get("readonly", False): + _LOGGER.warning("Readonly attribute %s will be ignored in class %s", k, self.__class__) + else: + setattr(self, k, kwargs[k]) + + def __eq__(self, other: Any) -> bool: + """Compare objects by comparing all attributes. + + :param object other: The object to compare + :returns: True if objects are equal + :rtype: bool + """ + if isinstance(other, self.__class__): + return self.__dict__ == other.__dict__ + return False + + def __ne__(self, other: Any) -> bool: + """Compare objects by comparing all attributes. + + :param object other: The object to compare + :returns: True if objects are not equal + :rtype: bool + """ + return not self.__eq__(other) + + def __str__(self) -> str: + return str(self.__dict__) + + @classmethod + def enable_additional_properties_sending(cls) -> None: + cls._attribute_map["additional_properties"] = {"key": "", "type": "{object}"} + + @classmethod + def is_xml_model(cls) -> bool: + try: + cls._xml_map # type: ignore + except AttributeError: + return False + return True + + @classmethod + def _create_xml_node(cls): + """Create XML node. + + :returns: The XML node + :rtype: xml.etree.ElementTree.Element + """ + try: + xml_map = cls._xml_map # type: ignore + except AttributeError: + xml_map = {} + + return _create_xml_node(xml_map.get("name", cls.__name__), xml_map.get("prefix", None), xml_map.get("ns", None)) + + def serialize(self, keep_readonly: bool = False, **kwargs: Any) -> JSON: + """Return the JSON that would be sent to server from this model. + + This is an alias to `as_dict(full_restapi_key_transformer, keep_readonly=False)`. + + If you want XML serialization, you can pass the kwargs is_xml=True. + + :param bool keep_readonly: If you want to serialize the readonly attributes + :returns: A dict JSON compatible object + :rtype: dict + """ + serializer = Serializer(self._infer_class_models()) + return serializer._serialize( # type: ignore # pylint: disable=protected-access + self, keep_readonly=keep_readonly, **kwargs + ) + + def as_dict( + self, + keep_readonly: bool = True, + key_transformer: Callable[[str, Dict[str, Any], Any], Any] = attribute_transformer, + **kwargs: Any + ) -> JSON: + """Return a dict that can be serialized using json.dump. + + Advanced usage might optionally use a callback as parameter: + + .. code::python + + def my_key_transformer(key, attr_desc, value): + return key + + Key is the attribute name used in Python. Attr_desc + is a dict of metadata. Currently contains 'type' with the + msrest type and 'key' with the RestAPI encoded key. + Value is the current value in this object. + + The string returned will be used to serialize the key. + If the return type is a list, this is considered hierarchical + result dict. + + See the three examples in this file: + + - attribute_transformer + - full_restapi_key_transformer + - last_restapi_key_transformer + + If you want XML serialization, you can pass the kwargs is_xml=True. + + :param bool keep_readonly: If you want to serialize the readonly attributes + :param function key_transformer: A key transformer function. + :returns: A dict JSON compatible object + :rtype: dict + """ + serializer = Serializer(self._infer_class_models()) + return serializer._serialize( # type: ignore # pylint: disable=protected-access + self, key_transformer=key_transformer, keep_readonly=keep_readonly, **kwargs + ) + + @classmethod + def _infer_class_models(cls): + try: + str_models = cls.__module__.rsplit(".", 1)[0] + models = sys.modules[str_models] + client_models = {k: v for k, v in models.__dict__.items() if isinstance(v, type)} + if cls.__name__ not in client_models: + raise ValueError("Not Autorest generated code") + except Exception: # pylint: disable=broad-exception-caught + # Assume it's not Autorest generated (tests?). Add ourselves as dependencies. + client_models = {cls.__name__: cls} + return client_models + + @classmethod + def deserialize(cls, data: Any, content_type: Optional[str] = None) -> Self: + """Parse a str using the RestAPI syntax and return a model. + + :param str data: A str using RestAPI structure. JSON by default. + :param str content_type: JSON by default, set application/xml if XML. + :returns: An instance of this model + :raises DeserializationError: if something went wrong + :rtype: Self + """ + deserializer = Deserializer(cls._infer_class_models()) + return deserializer(cls.__name__, data, content_type=content_type) # type: ignore + + @classmethod + def from_dict( + cls, + data: Any, + key_extractors: Optional[Callable[[str, Dict[str, Any], Any], Any]] = None, + content_type: Optional[str] = None, + ) -> Self: + """Parse a dict using given key extractor return a model. + + By default consider key + extractors (rest_key_case_insensitive_extractor, attribute_key_case_insensitive_extractor + and last_rest_key_case_insensitive_extractor) + + :param dict data: A dict using RestAPI structure + :param function key_extractors: A key extractor function. + :param str content_type: JSON by default, set application/xml if XML. + :returns: An instance of this model + :raises DeserializationError: if something went wrong + :rtype: Self + """ + deserializer = Deserializer(cls._infer_class_models()) + deserializer.key_extractors = ( # type: ignore + [ # type: ignore + attribute_key_case_insensitive_extractor, + rest_key_case_insensitive_extractor, + last_rest_key_case_insensitive_extractor, + ] + if key_extractors is None + else key_extractors + ) + return deserializer(cls.__name__, data, content_type=content_type) # type: ignore + + @classmethod + def _flatten_subtype(cls, key, objects): + if "_subtype_map" not in cls.__dict__: + return {} + result = dict(cls._subtype_map[key]) + for valuetype in cls._subtype_map[key].values(): + result.update(objects[valuetype]._flatten_subtype(key, objects)) # pylint: disable=protected-access + return result + + @classmethod + def _classify(cls, response, objects): + """Check the class _subtype_map for any child classes. + We want to ignore any inherited _subtype_maps. + + :param dict response: The initial data + :param dict objects: The class objects + :returns: The class to be used + :rtype: class + """ + for subtype_key in cls.__dict__.get("_subtype_map", {}).keys(): + subtype_value = None + + if not isinstance(response, ET.Element): + rest_api_response_key = cls._get_rest_key_parts(subtype_key)[-1] + subtype_value = response.get(rest_api_response_key, None) or response.get(subtype_key, None) + else: + subtype_value = xml_key_extractor(subtype_key, cls._attribute_map[subtype_key], response) + if subtype_value: + # Try to match base class. Can be class name only + # (bug to fix in Autorest to support x-ms-discriminator-name) + if cls.__name__ == subtype_value: + return cls + flatten_mapping_type = cls._flatten_subtype(subtype_key, objects) + try: + return objects[flatten_mapping_type[subtype_value]] # type: ignore + except KeyError: + _LOGGER.warning( + "Subtype value %s has no mapping, use base class %s.", + subtype_value, + cls.__name__, + ) + break + else: + _LOGGER.warning("Discriminator %s is absent or null, use base class %s.", subtype_key, cls.__name__) + break + return cls + + @classmethod + def _get_rest_key_parts(cls, attr_key): + """Get the RestAPI key of this attr, split it and decode part + :param str attr_key: Attribute key must be in attribute_map. + :returns: A list of RestAPI part + :rtype: list + """ + rest_split_key = _FLATTEN.split(cls._attribute_map[attr_key]["key"]) + return [_decode_attribute_map_key(key_part) for key_part in rest_split_key] + + +def _decode_attribute_map_key(key): + """This decode a key in an _attribute_map to the actual key we want to look at + inside the received data. + + :param str key: A key string from the generated code + :returns: The decoded key + :rtype: str + """ + return key.replace("\\.", ".") + + +class Serializer: # pylint: disable=too-many-public-methods + """Request object model serializer.""" + + basic_types = {str: "str", int: "int", bool: "bool", float: "float"} + + _xml_basic_types_serializers = {"bool": lambda x: str(x).lower()} + days = {0: "Mon", 1: "Tue", 2: "Wed", 3: "Thu", 4: "Fri", 5: "Sat", 6: "Sun"} + months = { + 1: "Jan", + 2: "Feb", + 3: "Mar", + 4: "Apr", + 5: "May", + 6: "Jun", + 7: "Jul", + 8: "Aug", + 9: "Sep", + 10: "Oct", + 11: "Nov", + 12: "Dec", + } + validation = { + "min_length": lambda x, y: len(x) < y, + "max_length": lambda x, y: len(x) > y, + "minimum": lambda x, y: x < y, + "maximum": lambda x, y: x > y, + "minimum_ex": lambda x, y: x <= y, + "maximum_ex": lambda x, y: x >= y, + "min_items": lambda x, y: len(x) < y, + "max_items": lambda x, y: len(x) > y, + "pattern": lambda x, y: not re.match(y, x, re.UNICODE), + "unique": lambda x, y: len(x) != len(set(x)), + "multiple": lambda x, y: x % y != 0, + } + + def __init__(self, classes: Optional[Mapping[str, type]] = None) -> None: + self.serialize_type = { + "iso-8601": Serializer.serialize_iso, + "rfc-1123": Serializer.serialize_rfc, + "unix-time": Serializer.serialize_unix, + "duration": Serializer.serialize_duration, + "date": Serializer.serialize_date, + "time": Serializer.serialize_time, + "decimal": Serializer.serialize_decimal, + "long": Serializer.serialize_long, + "bytearray": Serializer.serialize_bytearray, + "base64": Serializer.serialize_base64, + "object": self.serialize_object, + "[]": self.serialize_iter, + "{}": self.serialize_dict, + } + self.dependencies: Dict[str, type] = dict(classes) if classes else {} + self.key_transformer = full_restapi_key_transformer + self.client_side_validation = True + + def _serialize( # pylint: disable=too-many-nested-blocks, too-many-branches, too-many-statements, too-many-locals + self, target_obj, data_type=None, **kwargs + ): + """Serialize data into a string according to type. + + :param object target_obj: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str, dict + :raises SerializationError: if serialization fails. + :returns: The serialized data. + """ + key_transformer = kwargs.get("key_transformer", self.key_transformer) + keep_readonly = kwargs.get("keep_readonly", False) + if target_obj is None: + return None + + attr_name = None + class_name = target_obj.__class__.__name__ + + if data_type: + return self.serialize_data(target_obj, data_type, **kwargs) + + if not hasattr(target_obj, "_attribute_map"): + data_type = type(target_obj).__name__ + if data_type in self.basic_types.values(): + return self.serialize_data(target_obj, data_type, **kwargs) + + # Force "is_xml" kwargs if we detect a XML model + try: + is_xml_model_serialization = kwargs["is_xml"] + except KeyError: + is_xml_model_serialization = kwargs.setdefault("is_xml", target_obj.is_xml_model()) + + serialized = {} + if is_xml_model_serialization: + serialized = target_obj._create_xml_node() # pylint: disable=protected-access + try: + attributes = target_obj._attribute_map # pylint: disable=protected-access + for attr, attr_desc in attributes.items(): + attr_name = attr + if not keep_readonly and target_obj._validation.get( # pylint: disable=protected-access + attr_name, {} + ).get("readonly", False): + continue + + if attr_name == "additional_properties" and attr_desc["key"] == "": + if target_obj.additional_properties is not None: + serialized.update(target_obj.additional_properties) + continue + try: + + orig_attr = getattr(target_obj, attr) + if is_xml_model_serialization: + pass # Don't provide "transformer" for XML for now. Keep "orig_attr" + else: # JSON + keys, orig_attr = key_transformer(attr, attr_desc.copy(), orig_attr) + keys = keys if isinstance(keys, list) else [keys] + + kwargs["serialization_ctxt"] = attr_desc + new_attr = self.serialize_data(orig_attr, attr_desc["type"], **kwargs) + + if is_xml_model_serialization: + xml_desc = attr_desc.get("xml", {}) + xml_name = xml_desc.get("name", attr_desc["key"]) + xml_prefix = xml_desc.get("prefix", None) + xml_ns = xml_desc.get("ns", None) + if xml_desc.get("attr", False): + if xml_ns: + ET.register_namespace(xml_prefix, xml_ns) + xml_name = "{{{}}}{}".format(xml_ns, xml_name) + serialized.set(xml_name, new_attr) # type: ignore + continue + if xml_desc.get("text", False): + serialized.text = new_attr # type: ignore + continue + if isinstance(new_attr, list): + serialized.extend(new_attr) # type: ignore + elif isinstance(new_attr, ET.Element): + # If the down XML has no XML/Name, + # we MUST replace the tag with the local tag. But keeping the namespaces. + if "name" not in getattr(orig_attr, "_xml_map", {}): + splitted_tag = new_attr.tag.split("}") + if len(splitted_tag) == 2: # Namespace + new_attr.tag = "}".join([splitted_tag[0], xml_name]) + else: + new_attr.tag = xml_name + serialized.append(new_attr) # type: ignore + else: # That's a basic type + # Integrate namespace if necessary + local_node = _create_xml_node(xml_name, xml_prefix, xml_ns) + local_node.text = str(new_attr) + serialized.append(local_node) # type: ignore + else: # JSON + for k in reversed(keys): # type: ignore + new_attr = {k: new_attr} + + _new_attr = new_attr + _serialized = serialized + for k in keys: # type: ignore + if k not in _serialized: + _serialized.update(_new_attr) # type: ignore + _new_attr = _new_attr[k] # type: ignore + _serialized = _serialized[k] + except ValueError as err: + if isinstance(err, SerializationError): + raise + + except (AttributeError, KeyError, TypeError) as err: + msg = "Attribute {} in object {} cannot be serialized.\n{}".format(attr_name, class_name, str(target_obj)) + raise SerializationError(msg) from err + return serialized + + def body(self, data, data_type, **kwargs): + """Serialize data intended for a request body. + + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: dict + :raises SerializationError: if serialization fails. + :raises ValueError: if data is None + :returns: The serialized request body + """ + + # Just in case this is a dict + internal_data_type_str = data_type.strip("[]{}") + internal_data_type = self.dependencies.get(internal_data_type_str, None) + try: + is_xml_model_serialization = kwargs["is_xml"] + except KeyError: + if internal_data_type and issubclass(internal_data_type, Model): + is_xml_model_serialization = kwargs.setdefault("is_xml", internal_data_type.is_xml_model()) + else: + is_xml_model_serialization = False + if internal_data_type and not isinstance(internal_data_type, Enum): + try: + deserializer = Deserializer(self.dependencies) + # Since it's on serialization, it's almost sure that format is not JSON REST + # We're not able to deal with additional properties for now. + deserializer.additional_properties_detection = False + if is_xml_model_serialization: + deserializer.key_extractors = [ # type: ignore + attribute_key_case_insensitive_extractor, + ] + else: + deserializer.key_extractors = [ + rest_key_case_insensitive_extractor, + attribute_key_case_insensitive_extractor, + last_rest_key_case_insensitive_extractor, + ] + data = deserializer._deserialize(data_type, data) # pylint: disable=protected-access + except DeserializationError as err: + raise SerializationError("Unable to build a model: " + str(err)) from err + + return self._serialize(data, data_type, **kwargs) + + def url(self, name, data, data_type, **kwargs): + """Serialize data intended for a URL path. + + :param str name: The name of the URL path parameter. + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str + :returns: The serialized URL path + :raises TypeError: if serialization fails. + :raises ValueError: if data is None + """ + try: + output = self.serialize_data(data, data_type, **kwargs) + if data_type == "bool": + output = json.dumps(output) + + if kwargs.get("skip_quote") is True: + output = str(output) + output = output.replace("{", quote("{")).replace("}", quote("}")) + else: + output = quote(str(output), safe="") + except SerializationError as exc: + raise TypeError("{} must be type {}.".format(name, data_type)) from exc + return output + + def query(self, name, data, data_type, **kwargs): + """Serialize data intended for a URL query. + + :param str name: The name of the query parameter. + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str, list + :raises TypeError: if serialization fails. + :raises ValueError: if data is None + :returns: The serialized query parameter + """ + try: + # Treat the list aside, since we don't want to encode the div separator + if data_type.startswith("["): + internal_data_type = data_type[1:-1] + do_quote = not kwargs.get("skip_quote", False) + return self.serialize_iter(data, internal_data_type, do_quote=do_quote, **kwargs) + + # Not a list, regular serialization + output = self.serialize_data(data, data_type, **kwargs) + if data_type == "bool": + output = json.dumps(output) + if kwargs.get("skip_quote") is True: + output = str(output) + else: + output = quote(str(output), safe="") + except SerializationError as exc: + raise TypeError("{} must be type {}.".format(name, data_type)) from exc + return str(output) + + def header(self, name, data, data_type, **kwargs): + """Serialize data intended for a request header. + + :param str name: The name of the header. + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str + :raises TypeError: if serialization fails. + :raises ValueError: if data is None + :returns: The serialized header + """ + try: + if data_type in ["[str]"]: + data = ["" if d is None else d for d in data] + + output = self.serialize_data(data, data_type, **kwargs) + if data_type == "bool": + output = json.dumps(output) + except SerializationError as exc: + raise TypeError("{} must be type {}.".format(name, data_type)) from exc + return str(output) + + def serialize_data(self, data, data_type, **kwargs): + """Serialize generic data according to supplied data type. + + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :raises AttributeError: if required data is None. + :raises ValueError: if data is None + :raises SerializationError: if serialization fails. + :returns: The serialized data. + :rtype: str, int, float, bool, dict, list + """ + if data is None: + raise ValueError("No value for given attribute") + + try: + if data is CoreNull: + return None + if data_type in self.basic_types.values(): + return self.serialize_basic(data, data_type, **kwargs) + + if data_type in self.serialize_type: + return self.serialize_type[data_type](data, **kwargs) + + # If dependencies is empty, try with current data class + # It has to be a subclass of Enum anyway + enum_type = self.dependencies.get(data_type, data.__class__) + if issubclass(enum_type, Enum): + return Serializer.serialize_enum(data, enum_obj=enum_type) + + iter_type = data_type[0] + data_type[-1] + if iter_type in self.serialize_type: + return self.serialize_type[iter_type](data, data_type[1:-1], **kwargs) + + except (ValueError, TypeError) as err: + msg = "Unable to serialize value: {!r} as type: {!r}." + raise SerializationError(msg.format(data, data_type)) from err + return self._serialize(data, **kwargs) + + @classmethod + def _get_custom_serializers(cls, data_type, **kwargs): # pylint: disable=inconsistent-return-statements + custom_serializer = kwargs.get("basic_types_serializers", {}).get(data_type) + if custom_serializer: + return custom_serializer + if kwargs.get("is_xml", False): + return cls._xml_basic_types_serializers.get(data_type) + + @classmethod + def serialize_basic(cls, data, data_type, **kwargs): + """Serialize basic builting data type. + Serializes objects to str, int, float or bool. + + Possible kwargs: + - basic_types_serializers dict[str, callable] : If set, use the callable as serializer + - is_xml bool : If set, use xml_basic_types_serializers + + :param obj data: Object to be serialized. + :param str data_type: Type of object in the iterable. + :rtype: str, int, float, bool + :return: serialized object + """ + custom_serializer = cls._get_custom_serializers(data_type, **kwargs) + if custom_serializer: + return custom_serializer(data) + if data_type == "str": + return cls.serialize_unicode(data) + return eval(data_type)(data) # nosec # pylint: disable=eval-used + + @classmethod + def serialize_unicode(cls, data): + """Special handling for serializing unicode strings in Py2. + Encode to UTF-8 if unicode, otherwise handle as a str. + + :param str data: Object to be serialized. + :rtype: str + :return: serialized object + """ + try: # If I received an enum, return its value + return data.value + except AttributeError: + pass + + try: + if isinstance(data, unicode): # type: ignore + # Don't change it, JSON and XML ElementTree are totally able + # to serialize correctly u'' strings + return data + except NameError: + return str(data) + return str(data) + + def serialize_iter(self, data, iter_type, div=None, **kwargs): + """Serialize iterable. + + Supported kwargs: + - serialization_ctxt dict : The current entry of _attribute_map, or same format. + serialization_ctxt['type'] should be same as data_type. + - is_xml bool : If set, serialize as XML + + :param list data: Object to be serialized. + :param str iter_type: Type of object in the iterable. + :param str div: If set, this str will be used to combine the elements + in the iterable into a combined string. Default is 'None'. + Defaults to False. + :rtype: list, str + :return: serialized iterable + """ + if isinstance(data, str): + raise SerializationError("Refuse str type as a valid iter type.") + + serialization_ctxt = kwargs.get("serialization_ctxt", {}) + is_xml = kwargs.get("is_xml", False) + + serialized = [] + for d in data: + try: + serialized.append(self.serialize_data(d, iter_type, **kwargs)) + except ValueError as err: + if isinstance(err, SerializationError): + raise + serialized.append(None) + + if kwargs.get("do_quote", False): + serialized = ["" if s is None else quote(str(s), safe="") for s in serialized] + + if div: + serialized = ["" if s is None else str(s) for s in serialized] + serialized = div.join(serialized) + + if "xml" in serialization_ctxt or is_xml: + # XML serialization is more complicated + xml_desc = serialization_ctxt.get("xml", {}) + xml_name = xml_desc.get("name") + if not xml_name: + xml_name = serialization_ctxt["key"] + + # Create a wrap node if necessary (use the fact that Element and list have "append") + is_wrapped = xml_desc.get("wrapped", False) + node_name = xml_desc.get("itemsName", xml_name) + if is_wrapped: + final_result = _create_xml_node(xml_name, xml_desc.get("prefix", None), xml_desc.get("ns", None)) + else: + final_result = [] + # All list elements to "local_node" + for el in serialized: + if isinstance(el, ET.Element): + el_node = el + else: + el_node = _create_xml_node(node_name, xml_desc.get("prefix", None), xml_desc.get("ns", None)) + if el is not None: # Otherwise it writes "None" :-p + el_node.text = str(el) + final_result.append(el_node) + return final_result + return serialized + + def serialize_dict(self, attr, dict_type, **kwargs): + """Serialize a dictionary of objects. + + :param dict attr: Object to be serialized. + :param str dict_type: Type of object in the dictionary. + :rtype: dict + :return: serialized dictionary + """ + serialization_ctxt = kwargs.get("serialization_ctxt", {}) + serialized = {} + for key, value in attr.items(): + try: + serialized[self.serialize_unicode(key)] = self.serialize_data(value, dict_type, **kwargs) + except ValueError as err: + if isinstance(err, SerializationError): + raise + serialized[self.serialize_unicode(key)] = None + + if "xml" in serialization_ctxt: + # XML serialization is more complicated + xml_desc = serialization_ctxt["xml"] + xml_name = xml_desc["name"] + + final_result = _create_xml_node(xml_name, xml_desc.get("prefix", None), xml_desc.get("ns", None)) + for key, value in serialized.items(): + ET.SubElement(final_result, key).text = value + return final_result + + return serialized + + def serialize_object(self, attr, **kwargs): # pylint: disable=too-many-return-statements + """Serialize a generic object. + This will be handled as a dictionary. If object passed in is not + a basic type (str, int, float, dict, list) it will simply be + cast to str. + + :param dict attr: Object to be serialized. + :rtype: dict or str + :return: serialized object + """ + if attr is None: + return None + if isinstance(attr, ET.Element): + return attr + obj_type = type(attr) + if obj_type in self.basic_types: + return self.serialize_basic(attr, self.basic_types[obj_type], **kwargs) + if obj_type is _long_type: + return self.serialize_long(attr) + if obj_type is str: + return self.serialize_unicode(attr) + if obj_type is datetime.datetime: + return self.serialize_iso(attr) + if obj_type is datetime.date: + return self.serialize_date(attr) + if obj_type is datetime.time: + return self.serialize_time(attr) + if obj_type is datetime.timedelta: + return self.serialize_duration(attr) + if obj_type is decimal.Decimal: + return self.serialize_decimal(attr) + + # If it's a model or I know this dependency, serialize as a Model + if obj_type in self.dependencies.values() or isinstance(attr, Model): + return self._serialize(attr) + + if obj_type == dict: + serialized = {} + for key, value in attr.items(): + try: + serialized[self.serialize_unicode(key)] = self.serialize_object(value, **kwargs) + except ValueError: + serialized[self.serialize_unicode(key)] = None + return serialized + + if obj_type == list: + serialized = [] + for obj in attr: + try: + serialized.append(self.serialize_object(obj, **kwargs)) + except ValueError: + pass + return serialized + return str(attr) + + @staticmethod + def serialize_enum(attr, enum_obj=None): + try: + result = attr.value + except AttributeError: + result = attr + try: + enum_obj(result) # type: ignore + return result + except ValueError as exc: + for enum_value in enum_obj: # type: ignore + if enum_value.value.lower() == str(attr).lower(): + return enum_value.value + error = "{!r} is not valid value for enum {!r}" + raise SerializationError(error.format(attr, enum_obj)) from exc + + @staticmethod + def serialize_bytearray(attr, **kwargs): # pylint: disable=unused-argument + """Serialize bytearray into base-64 string. + + :param str attr: Object to be serialized. + :rtype: str + :return: serialized base64 + """ + return b64encode(attr).decode() + + @staticmethod + def serialize_base64(attr, **kwargs): # pylint: disable=unused-argument + """Serialize str into base-64 string. + + :param str attr: Object to be serialized. + :rtype: str + :return: serialized base64 + """ + encoded = b64encode(attr).decode("ascii") + return encoded.strip("=").replace("+", "-").replace("/", "_") + + @staticmethod + def serialize_decimal(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Decimal object to float. + + :param decimal attr: Object to be serialized. + :rtype: float + :return: serialized decimal + """ + return float(attr) + + @staticmethod + def serialize_long(attr, **kwargs): # pylint: disable=unused-argument + """Serialize long (Py2) or int (Py3). + + :param int attr: Object to be serialized. + :rtype: int/long + :return: serialized long + """ + return _long_type(attr) + + @staticmethod + def serialize_date(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Date object into ISO-8601 formatted string. + + :param Date attr: Object to be serialized. + :rtype: str + :return: serialized date + """ + if isinstance(attr, str): + attr = isodate.parse_date(attr) + t = "{:04}-{:02}-{:02}".format(attr.year, attr.month, attr.day) + return t + + @staticmethod + def serialize_time(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Time object into ISO-8601 formatted string. + + :param datetime.time attr: Object to be serialized. + :rtype: str + :return: serialized time + """ + if isinstance(attr, str): + attr = isodate.parse_time(attr) + t = "{:02}:{:02}:{:02}".format(attr.hour, attr.minute, attr.second) + if attr.microsecond: + t += ".{:02}".format(attr.microsecond) + return t + + @staticmethod + def serialize_duration(attr, **kwargs): # pylint: disable=unused-argument + """Serialize TimeDelta object into ISO-8601 formatted string. + + :param TimeDelta attr: Object to be serialized. + :rtype: str + :return: serialized duration + """ + if isinstance(attr, str): + attr = isodate.parse_duration(attr) + return isodate.duration_isoformat(attr) + + @staticmethod + def serialize_rfc(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Datetime object into RFC-1123 formatted string. + + :param Datetime attr: Object to be serialized. + :rtype: str + :raises TypeError: if format invalid. + :return: serialized rfc + """ + try: + if not attr.tzinfo: + _LOGGER.warning("Datetime with no tzinfo will be considered UTC.") + utc = attr.utctimetuple() + except AttributeError as exc: + raise TypeError("RFC1123 object must be valid Datetime object.") from exc + + return "{}, {:02} {} {:04} {:02}:{:02}:{:02} GMT".format( + Serializer.days[utc.tm_wday], + utc.tm_mday, + Serializer.months[utc.tm_mon], + utc.tm_year, + utc.tm_hour, + utc.tm_min, + utc.tm_sec, + ) + + @staticmethod + def serialize_iso(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Datetime object into ISO-8601 formatted string. + + :param Datetime attr: Object to be serialized. + :rtype: str + :raises SerializationError: if format invalid. + :return: serialized iso + """ + if isinstance(attr, str): + attr = isodate.parse_datetime(attr) + try: + if not attr.tzinfo: + _LOGGER.warning("Datetime with no tzinfo will be considered UTC.") + utc = attr.utctimetuple() + if utc.tm_year > 9999 or utc.tm_year < 1: + raise OverflowError("Hit max or min date") + + microseconds = str(attr.microsecond).rjust(6, "0").rstrip("0").ljust(3, "0") + if microseconds: + microseconds = "." + microseconds + date = "{:04}-{:02}-{:02}T{:02}:{:02}:{:02}".format( + utc.tm_year, utc.tm_mon, utc.tm_mday, utc.tm_hour, utc.tm_min, utc.tm_sec + ) + return date + microseconds + "Z" + except (ValueError, OverflowError) as err: + msg = "Unable to serialize datetime object." + raise SerializationError(msg) from err + except AttributeError as err: + msg = "ISO-8601 object must be valid Datetime object." + raise TypeError(msg) from err + + @staticmethod + def serialize_unix(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Datetime object into IntTime format. + This is represented as seconds. + + :param Datetime attr: Object to be serialized. + :rtype: int + :raises SerializationError: if format invalid + :return: serialied unix + """ + if isinstance(attr, int): + return attr + try: + if not attr.tzinfo: + _LOGGER.warning("Datetime with no tzinfo will be considered UTC.") + return int(calendar.timegm(attr.utctimetuple())) + except AttributeError as exc: + raise TypeError("Unix time object must be valid Datetime object.") from exc + + +def rest_key_extractor(attr, attr_desc, data): # pylint: disable=unused-argument + key = attr_desc["key"] + working_data = data + + while "." in key: + # Need the cast, as for some reasons "split" is typed as list[str | Any] + dict_keys = cast(List[str], _FLATTEN.split(key)) + if len(dict_keys) == 1: + key = _decode_attribute_map_key(dict_keys[0]) + break + working_key = _decode_attribute_map_key(dict_keys[0]) + working_data = working_data.get(working_key, data) + if working_data is None: + # If at any point while following flatten JSON path see None, it means + # that all properties under are None as well + return None + key = ".".join(dict_keys[1:]) + + return working_data.get(key) + + +def rest_key_case_insensitive_extractor( # pylint: disable=unused-argument, inconsistent-return-statements + attr, attr_desc, data +): + key = attr_desc["key"] + working_data = data + + while "." in key: + dict_keys = _FLATTEN.split(key) + if len(dict_keys) == 1: + key = _decode_attribute_map_key(dict_keys[0]) + break + working_key = _decode_attribute_map_key(dict_keys[0]) + working_data = attribute_key_case_insensitive_extractor(working_key, None, working_data) + if working_data is None: + # If at any point while following flatten JSON path see None, it means + # that all properties under are None as well + return None + key = ".".join(dict_keys[1:]) + + if working_data: + return attribute_key_case_insensitive_extractor(key, None, working_data) + + +def last_rest_key_extractor(attr, attr_desc, data): # pylint: disable=unused-argument + """Extract the attribute in "data" based on the last part of the JSON path key. + + :param str attr: The attribute to extract + :param dict attr_desc: The attribute description + :param dict data: The data to extract from + :rtype: object + :returns: The extracted attribute + """ + key = attr_desc["key"] + dict_keys = _FLATTEN.split(key) + return attribute_key_extractor(dict_keys[-1], None, data) + + +def last_rest_key_case_insensitive_extractor(attr, attr_desc, data): # pylint: disable=unused-argument + """Extract the attribute in "data" based on the last part of the JSON path key. + + This is the case insensitive version of "last_rest_key_extractor" + :param str attr: The attribute to extract + :param dict attr_desc: The attribute description + :param dict data: The data to extract from + :rtype: object + :returns: The extracted attribute + """ + key = attr_desc["key"] + dict_keys = _FLATTEN.split(key) + return attribute_key_case_insensitive_extractor(dict_keys[-1], None, data) + + +def attribute_key_extractor(attr, _, data): + return data.get(attr) + + +def attribute_key_case_insensitive_extractor(attr, _, data): + found_key = None + lower_attr = attr.lower() + for key in data: + if lower_attr == key.lower(): + found_key = key + break + + return data.get(found_key) + + +def _extract_name_from_internal_type(internal_type): + """Given an internal type XML description, extract correct XML name with namespace. + + :param dict internal_type: An model type + :rtype: tuple + :returns: A tuple XML name + namespace dict + """ + internal_type_xml_map = getattr(internal_type, "_xml_map", {}) + xml_name = internal_type_xml_map.get("name", internal_type.__name__) + xml_ns = internal_type_xml_map.get("ns", None) + if xml_ns: + xml_name = "{{{}}}{}".format(xml_ns, xml_name) + return xml_name + + +def xml_key_extractor(attr, attr_desc, data): # pylint: disable=unused-argument,too-many-return-statements + if isinstance(data, dict): + return None + + # Test if this model is XML ready first + if not isinstance(data, ET.Element): + return None + + xml_desc = attr_desc.get("xml", {}) + xml_name = xml_desc.get("name", attr_desc["key"]) + + # Look for a children + is_iter_type = attr_desc["type"].startswith("[") + is_wrapped = xml_desc.get("wrapped", False) + internal_type = attr_desc.get("internalType", None) + internal_type_xml_map = getattr(internal_type, "_xml_map", {}) + + # Integrate namespace if necessary + xml_ns = xml_desc.get("ns", internal_type_xml_map.get("ns", None)) + if xml_ns: + xml_name = "{{{}}}{}".format(xml_ns, xml_name) + + # If it's an attribute, that's simple + if xml_desc.get("attr", False): + return data.get(xml_name) + + # If it's x-ms-text, that's simple too + if xml_desc.get("text", False): + return data.text + + # Scenario where I take the local name: + # - Wrapped node + # - Internal type is an enum (considered basic types) + # - Internal type has no XML/Name node + if is_wrapped or (internal_type and (issubclass(internal_type, Enum) or "name" not in internal_type_xml_map)): + children = data.findall(xml_name) + # If internal type has a local name and it's not a list, I use that name + elif not is_iter_type and internal_type and "name" in internal_type_xml_map: + xml_name = _extract_name_from_internal_type(internal_type) + children = data.findall(xml_name) + # That's an array + else: + if internal_type: # Complex type, ignore itemsName and use the complex type name + items_name = _extract_name_from_internal_type(internal_type) + else: + items_name = xml_desc.get("itemsName", xml_name) + children = data.findall(items_name) + + if len(children) == 0: + if is_iter_type: + if is_wrapped: + return None # is_wrapped no node, we want None + return [] # not wrapped, assume empty list + return None # Assume it's not there, maybe an optional node. + + # If is_iter_type and not wrapped, return all found children + if is_iter_type: + if not is_wrapped: + return children + # Iter and wrapped, should have found one node only (the wrap one) + if len(children) != 1: + raise DeserializationError( + "Tried to deserialize an array not wrapped, and found several nodes '{}'. Maybe you should declare this array as wrapped?".format( + xml_name + ) + ) + return list(children[0]) # Might be empty list and that's ok. + + # Here it's not a itertype, we should have found one element only or empty + if len(children) > 1: + raise DeserializationError("Find several XML '{}' where it was not expected".format(xml_name)) + return children[0] + + +class Deserializer: + """Response object model deserializer. + + :param dict classes: Class type dictionary for deserializing complex types. + :ivar list key_extractors: Ordered list of extractors to be used by this deserializer. + """ + + basic_types = {str: "str", int: "int", bool: "bool", float: "float"} + + valid_date = re.compile(r"\d{4}[-]\d{2}[-]\d{2}T\d{2}:\d{2}:\d{2}\.?\d*Z?[-+]?[\d{2}]?:?[\d{2}]?") + + def __init__(self, classes: Optional[Mapping[str, type]] = None) -> None: + self.deserialize_type = { + "iso-8601": Deserializer.deserialize_iso, + "rfc-1123": Deserializer.deserialize_rfc, + "unix-time": Deserializer.deserialize_unix, + "duration": Deserializer.deserialize_duration, + "date": Deserializer.deserialize_date, + "time": Deserializer.deserialize_time, + "decimal": Deserializer.deserialize_decimal, + "long": Deserializer.deserialize_long, + "bytearray": Deserializer.deserialize_bytearray, + "base64": Deserializer.deserialize_base64, + "object": self.deserialize_object, + "[]": self.deserialize_iter, + "{}": self.deserialize_dict, + } + self.deserialize_expected_types = { + "duration": (isodate.Duration, datetime.timedelta), + "iso-8601": (datetime.datetime), + } + self.dependencies: Dict[str, type] = dict(classes) if classes else {} + self.key_extractors = [rest_key_extractor, xml_key_extractor] + # Additional properties only works if the "rest_key_extractor" is used to + # extract the keys. Making it to work whatever the key extractor is too much + # complicated, with no real scenario for now. + # So adding a flag to disable additional properties detection. This flag should be + # used if your expect the deserialization to NOT come from a JSON REST syntax. + # Otherwise, result are unexpected + self.additional_properties_detection = True + + def __call__(self, target_obj, response_data, content_type=None): + """Call the deserializer to process a REST response. + + :param str target_obj: Target data type to deserialize to. + :param requests.Response response_data: REST response object. + :param str content_type: Swagger "produces" if available. + :raises DeserializationError: if deserialization fails. + :return: Deserialized object. + :rtype: object + """ + data = self._unpack_content(response_data, content_type) + return self._deserialize(target_obj, data) + + def _deserialize(self, target_obj, data): # pylint: disable=inconsistent-return-statements + """Call the deserializer on a model. + + Data needs to be already deserialized as JSON or XML ElementTree + + :param str target_obj: Target data type to deserialize to. + :param object data: Object to deserialize. + :raises DeserializationError: if deserialization fails. + :return: Deserialized object. + :rtype: object + """ + # This is already a model, go recursive just in case + if hasattr(data, "_attribute_map"): + constants = [name for name, config in getattr(data, "_validation", {}).items() if config.get("constant")] + try: + for attr, mapconfig in data._attribute_map.items(): # pylint: disable=protected-access + if attr in constants: + continue + value = getattr(data, attr) + if value is None: + continue + local_type = mapconfig["type"] + internal_data_type = local_type.strip("[]{}") + if internal_data_type not in self.dependencies or isinstance(internal_data_type, Enum): + continue + setattr(data, attr, self._deserialize(local_type, value)) + return data + except AttributeError: + return + + response, class_name = self._classify_target(target_obj, data) + + if isinstance(response, str): + return self.deserialize_data(data, response) + if isinstance(response, type) and issubclass(response, Enum): + return self.deserialize_enum(data, response) + + if data is None or data is CoreNull: + return data + try: + attributes = response._attribute_map # type: ignore # pylint: disable=protected-access + d_attrs = {} + for attr, attr_desc in attributes.items(): + # Check empty string. If it's not empty, someone has a real "additionalProperties"... + if attr == "additional_properties" and attr_desc["key"] == "": + continue + raw_value = None + # Enhance attr_desc with some dynamic data + attr_desc = attr_desc.copy() # Do a copy, do not change the real one + internal_data_type = attr_desc["type"].strip("[]{}") + if internal_data_type in self.dependencies: + attr_desc["internalType"] = self.dependencies[internal_data_type] + + for key_extractor in self.key_extractors: + found_value = key_extractor(attr, attr_desc, data) + if found_value is not None: + if raw_value is not None and raw_value != found_value: + msg = ( + "Ignoring extracted value '%s' from %s for key '%s'" + " (duplicate extraction, follow extractors order)" + ) + _LOGGER.warning(msg, found_value, key_extractor, attr) + continue + raw_value = found_value + + value = self.deserialize_data(raw_value, attr_desc["type"]) + d_attrs[attr] = value + except (AttributeError, TypeError, KeyError) as err: + msg = "Unable to deserialize to object: " + class_name # type: ignore + raise DeserializationError(msg) from err + additional_properties = self._build_additional_properties(attributes, data) + return self._instantiate_model(response, d_attrs, additional_properties) + + def _build_additional_properties(self, attribute_map, data): + if not self.additional_properties_detection: + return None + if "additional_properties" in attribute_map and attribute_map.get("additional_properties", {}).get("key") != "": + # Check empty string. If it's not empty, someone has a real "additionalProperties" + return None + if isinstance(data, ET.Element): + data = {el.tag: el.text for el in data} + + known_keys = { + _decode_attribute_map_key(_FLATTEN.split(desc["key"])[0]) + for desc in attribute_map.values() + if desc["key"] != "" + } + present_keys = set(data.keys()) + missing_keys = present_keys - known_keys + return {key: data[key] for key in missing_keys} + + def _classify_target(self, target, data): + """Check to see whether the deserialization target object can + be classified into a subclass. + Once classification has been determined, initialize object. + + :param str target: The target object type to deserialize to. + :param str/dict data: The response data to deserialize. + :return: The classified target object and its class name. + :rtype: tuple + """ + if target is None: + return None, None + + if isinstance(target, str): + try: + target = self.dependencies[target] + except KeyError: + return target, target + + try: + target = target._classify(data, self.dependencies) # type: ignore # pylint: disable=protected-access + except AttributeError: + pass # Target is not a Model, no classify + return target, target.__class__.__name__ # type: ignore + + def failsafe_deserialize(self, target_obj, data, content_type=None): + """Ignores any errors encountered in deserialization, + and falls back to not deserializing the object. Recommended + for use in error deserialization, as we want to return the + HttpResponseError to users, and not have them deal with + a deserialization error. + + :param str target_obj: The target object type to deserialize to. + :param str/dict data: The response data to deserialize. + :param str content_type: Swagger "produces" if available. + :return: Deserialized object. + :rtype: object + """ + try: + return self(target_obj, data, content_type=content_type) + except: # pylint: disable=bare-except + _LOGGER.debug( + "Ran into a deserialization error. Ignoring since this is failsafe deserialization", exc_info=True + ) + return None + + @staticmethod + def _unpack_content(raw_data, content_type=None): + """Extract the correct structure for deserialization. + + If raw_data is a PipelineResponse, try to extract the result of RawDeserializer. + if we can't, raise. Your Pipeline should have a RawDeserializer. + + If not a pipeline response and raw_data is bytes or string, use content-type + to decode it. If no content-type, try JSON. + + If raw_data is something else, bypass all logic and return it directly. + + :param obj raw_data: Data to be processed. + :param str content_type: How to parse if raw_data is a string/bytes. + :raises JSONDecodeError: If JSON is requested and parsing is impossible. + :raises UnicodeDecodeError: If bytes is not UTF8 + :rtype: object + :return: Unpacked content. + """ + # Assume this is enough to detect a Pipeline Response without importing it + context = getattr(raw_data, "context", {}) + if context: + if RawDeserializer.CONTEXT_NAME in context: + return context[RawDeserializer.CONTEXT_NAME] + raise ValueError("This pipeline didn't have the RawDeserializer policy; can't deserialize") + + # Assume this is enough to recognize universal_http.ClientResponse without importing it + if hasattr(raw_data, "body"): + return RawDeserializer.deserialize_from_http_generics(raw_data.text(), raw_data.headers) + + # Assume this enough to recognize requests.Response without importing it. + if hasattr(raw_data, "_content_consumed"): + return RawDeserializer.deserialize_from_http_generics(raw_data.text, raw_data.headers) + + if isinstance(raw_data, (str, bytes)) or hasattr(raw_data, "read"): + return RawDeserializer.deserialize_from_text(raw_data, content_type) # type: ignore + return raw_data + + def _instantiate_model(self, response, attrs, additional_properties=None): + """Instantiate a response model passing in deserialized args. + + :param Response response: The response model class. + :param dict attrs: The deserialized response attributes. + :param dict additional_properties: Additional properties to be set. + :rtype: Response + :return: The instantiated response model. + """ + if callable(response): + subtype = getattr(response, "_subtype_map", {}) + try: + readonly = [ + k + for k, v in response._validation.items() # pylint: disable=protected-access # type: ignore + if v.get("readonly") + ] + const = [ + k + for k, v in response._validation.items() # pylint: disable=protected-access # type: ignore + if v.get("constant") + ] + kwargs = {k: v for k, v in attrs.items() if k not in subtype and k not in readonly + const} + response_obj = response(**kwargs) + for attr in readonly: + setattr(response_obj, attr, attrs.get(attr)) + if additional_properties: + response_obj.additional_properties = additional_properties # type: ignore + return response_obj + except TypeError as err: + msg = "Unable to deserialize {} into model {}. ".format(kwargs, response) # type: ignore + raise DeserializationError(msg + str(err)) from err + else: + try: + for attr, value in attrs.items(): + setattr(response, attr, value) + return response + except Exception as exp: + msg = "Unable to populate response model. " + msg += "Type: {}, Error: {}".format(type(response), exp) + raise DeserializationError(msg) from exp + + def deserialize_data(self, data, data_type): # pylint: disable=too-many-return-statements + """Process data for deserialization according to data type. + + :param str data: The response string to be deserialized. + :param str data_type: The type to deserialize to. + :raises DeserializationError: if deserialization fails. + :return: Deserialized object. + :rtype: object + """ + if data is None: + return data + + try: + if not data_type: + return data + if data_type in self.basic_types.values(): + return self.deserialize_basic(data, data_type) + if data_type in self.deserialize_type: + if isinstance(data, self.deserialize_expected_types.get(data_type, tuple())): + return data + + is_a_text_parsing_type = lambda x: x not in [ # pylint: disable=unnecessary-lambda-assignment + "object", + "[]", + r"{}", + ] + if isinstance(data, ET.Element) and is_a_text_parsing_type(data_type) and not data.text: + return None + data_val = self.deserialize_type[data_type](data) + return data_val + + iter_type = data_type[0] + data_type[-1] + if iter_type in self.deserialize_type: + return self.deserialize_type[iter_type](data, data_type[1:-1]) + + obj_type = self.dependencies[data_type] + if issubclass(obj_type, Enum): + if isinstance(data, ET.Element): + data = data.text + return self.deserialize_enum(data, obj_type) + + except (ValueError, TypeError, AttributeError) as err: + msg = "Unable to deserialize response data." + msg += " Data: {}, {}".format(data, data_type) + raise DeserializationError(msg) from err + return self._deserialize(obj_type, data) + + def deserialize_iter(self, attr, iter_type): + """Deserialize an iterable. + + :param list attr: Iterable to be deserialized. + :param str iter_type: The type of object in the iterable. + :return: Deserialized iterable. + :rtype: list + """ + if attr is None: + return None + if isinstance(attr, ET.Element): # If I receive an element here, get the children + attr = list(attr) + if not isinstance(attr, (list, set)): + raise DeserializationError("Cannot deserialize as [{}] an object of type {}".format(iter_type, type(attr))) + return [self.deserialize_data(a, iter_type) for a in attr] + + def deserialize_dict(self, attr, dict_type): + """Deserialize a dictionary. + + :param dict/list attr: Dictionary to be deserialized. Also accepts + a list of key, value pairs. + :param str dict_type: The object type of the items in the dictionary. + :return: Deserialized dictionary. + :rtype: dict + """ + if isinstance(attr, list): + return {x["key"]: self.deserialize_data(x["value"], dict_type) for x in attr} + + if isinstance(attr, ET.Element): + # Transform value into {"Key": "value"} + attr = {el.tag: el.text for el in attr} + return {k: self.deserialize_data(v, dict_type) for k, v in attr.items()} + + def deserialize_object(self, attr, **kwargs): # pylint: disable=too-many-return-statements + """Deserialize a generic object. + This will be handled as a dictionary. + + :param dict attr: Dictionary to be deserialized. + :return: Deserialized object. + :rtype: dict + :raises TypeError: if non-builtin datatype encountered. + """ + if attr is None: + return None + if isinstance(attr, ET.Element): + # Do no recurse on XML, just return the tree as-is + return attr + if isinstance(attr, str): + return self.deserialize_basic(attr, "str") + obj_type = type(attr) + if obj_type in self.basic_types: + return self.deserialize_basic(attr, self.basic_types[obj_type]) + if obj_type is _long_type: + return self.deserialize_long(attr) + + if obj_type == dict: + deserialized = {} + for key, value in attr.items(): + try: + deserialized[key] = self.deserialize_object(value, **kwargs) + except ValueError: + deserialized[key] = None + return deserialized + + if obj_type == list: + deserialized = [] + for obj in attr: + try: + deserialized.append(self.deserialize_object(obj, **kwargs)) + except ValueError: + pass + return deserialized + + error = "Cannot deserialize generic object with type: " + raise TypeError(error + str(obj_type)) + + def deserialize_basic(self, attr, data_type): # pylint: disable=too-many-return-statements + """Deserialize basic builtin data type from string. + Will attempt to convert to str, int, float and bool. + This function will also accept '1', '0', 'true' and 'false' as + valid bool values. + + :param str attr: response string to be deserialized. + :param str data_type: deserialization data type. + :return: Deserialized basic type. + :rtype: str, int, float or bool + :raises TypeError: if string format is not valid. + """ + # If we're here, data is supposed to be a basic type. + # If it's still an XML node, take the text + if isinstance(attr, ET.Element): + attr = attr.text + if not attr: + if data_type == "str": + # None or '', node is empty string. + return "" + # None or '', node with a strong type is None. + # Don't try to model "empty bool" or "empty int" + return None + + if data_type == "bool": + if attr in [True, False, 1, 0]: + return bool(attr) + if isinstance(attr, str): + if attr.lower() in ["true", "1"]: + return True + if attr.lower() in ["false", "0"]: + return False + raise TypeError("Invalid boolean value: {}".format(attr)) + + if data_type == "str": + return self.deserialize_unicode(attr) + return eval(data_type)(attr) # nosec # pylint: disable=eval-used + + @staticmethod + def deserialize_unicode(data): + """Preserve unicode objects in Python 2, otherwise return data + as a string. + + :param str data: response string to be deserialized. + :return: Deserialized string. + :rtype: str or unicode + """ + # We might be here because we have an enum modeled as string, + # and we try to deserialize a partial dict with enum inside + if isinstance(data, Enum): + return data + + # Consider this is real string + try: + if isinstance(data, unicode): # type: ignore + return data + except NameError: + return str(data) + return str(data) + + @staticmethod + def deserialize_enum(data, enum_obj): + """Deserialize string into enum object. + + If the string is not a valid enum value it will be returned as-is + and a warning will be logged. + + :param str data: Response string to be deserialized. If this value is + None or invalid it will be returned as-is. + :param Enum enum_obj: Enum object to deserialize to. + :return: Deserialized enum object. + :rtype: Enum + """ + if isinstance(data, enum_obj) or data is None: + return data + if isinstance(data, Enum): + data = data.value + if isinstance(data, int): + # Workaround. We might consider remove it in the future. + try: + return list(enum_obj.__members__.values())[data] + except IndexError as exc: + error = "{!r} is not a valid index for enum {!r}" + raise DeserializationError(error.format(data, enum_obj)) from exc + try: + return enum_obj(str(data)) + except ValueError: + for enum_value in enum_obj: + if enum_value.value.lower() == str(data).lower(): + return enum_value + # We don't fail anymore for unknown value, we deserialize as a string + _LOGGER.warning("Deserializer is not able to find %s as valid enum in %s", data, enum_obj) + return Deserializer.deserialize_unicode(data) + + @staticmethod + def deserialize_bytearray(attr): + """Deserialize string into bytearray. + + :param str attr: response string to be deserialized. + :return: Deserialized bytearray + :rtype: bytearray + :raises TypeError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + return bytearray(b64decode(attr)) # type: ignore + + @staticmethod + def deserialize_base64(attr): + """Deserialize base64 encoded string into string. + + :param str attr: response string to be deserialized. + :return: Deserialized base64 string + :rtype: bytearray + :raises TypeError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + padding = "=" * (3 - (len(attr) + 3) % 4) # type: ignore + attr = attr + padding # type: ignore + encoded = attr.replace("-", "+").replace("_", "/") + return b64decode(encoded) + + @staticmethod + def deserialize_decimal(attr): + """Deserialize string into Decimal object. + + :param str attr: response string to be deserialized. + :return: Deserialized decimal + :raises DeserializationError: if string format invalid. + :rtype: decimal + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + return decimal.Decimal(str(attr)) # type: ignore + except decimal.DecimalException as err: + msg = "Invalid decimal {}".format(attr) + raise DeserializationError(msg) from err + + @staticmethod + def deserialize_long(attr): + """Deserialize string into long (Py2) or int (Py3). + + :param str attr: response string to be deserialized. + :return: Deserialized int + :rtype: long or int + :raises ValueError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + return _long_type(attr) # type: ignore + + @staticmethod + def deserialize_duration(attr): + """Deserialize ISO-8601 formatted string into TimeDelta object. + + :param str attr: response string to be deserialized. + :return: Deserialized duration + :rtype: TimeDelta + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + duration = isodate.parse_duration(attr) + except (ValueError, OverflowError, AttributeError) as err: + msg = "Cannot deserialize duration object." + raise DeserializationError(msg) from err + return duration + + @staticmethod + def deserialize_date(attr): + """Deserialize ISO-8601 formatted string into Date object. + + :param str attr: response string to be deserialized. + :return: Deserialized date + :rtype: Date + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + if re.search(r"[^\W\d_]", attr, re.I + re.U): # type: ignore + raise DeserializationError("Date must have only digits and -. Received: %s" % attr) + # This must NOT use defaultmonth/defaultday. Using None ensure this raises an exception. + return isodate.parse_date(attr, defaultmonth=0, defaultday=0) + + @staticmethod + def deserialize_time(attr): + """Deserialize ISO-8601 formatted string into time object. + + :param str attr: response string to be deserialized. + :return: Deserialized time + :rtype: datetime.time + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + if re.search(r"[^\W\d_]", attr, re.I + re.U): # type: ignore + raise DeserializationError("Date must have only digits and -. Received: %s" % attr) + return isodate.parse_time(attr) + + @staticmethod + def deserialize_rfc(attr): + """Deserialize RFC-1123 formatted string into Datetime object. + + :param str attr: response string to be deserialized. + :return: Deserialized RFC datetime + :rtype: Datetime + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + parsed_date = email.utils.parsedate_tz(attr) # type: ignore + date_obj = datetime.datetime( + *parsed_date[:6], tzinfo=datetime.timezone(datetime.timedelta(minutes=(parsed_date[9] or 0) / 60)) + ) + if not date_obj.tzinfo: + date_obj = date_obj.astimezone(tz=TZ_UTC) + except ValueError as err: + msg = "Cannot deserialize to rfc datetime object." + raise DeserializationError(msg) from err + return date_obj + + @staticmethod + def deserialize_iso(attr): + """Deserialize ISO-8601 formatted string into Datetime object. + + :param str attr: response string to be deserialized. + :return: Deserialized ISO datetime + :rtype: Datetime + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + attr = attr.upper() # type: ignore + match = Deserializer.valid_date.match(attr) + if not match: + raise ValueError("Invalid datetime string: " + attr) + + check_decimal = attr.split(".") + if len(check_decimal) > 1: + decimal_str = "" + for digit in check_decimal[1]: + if digit.isdigit(): + decimal_str += digit + else: + break + if len(decimal_str) > 6: + attr = attr.replace(decimal_str, decimal_str[0:6]) + + date_obj = isodate.parse_datetime(attr) + test_utc = date_obj.utctimetuple() + if test_utc.tm_year > 9999 or test_utc.tm_year < 1: + raise OverflowError("Hit max or min date") + except (ValueError, OverflowError, AttributeError) as err: + msg = "Cannot deserialize datetime object." + raise DeserializationError(msg) from err + return date_obj + + @staticmethod + def deserialize_unix(attr): + """Serialize Datetime object into IntTime format. + This is represented as seconds. + + :param int attr: Object to be serialized. + :return: Deserialized datetime + :rtype: Datetime + :raises DeserializationError: if format invalid + """ + if isinstance(attr, ET.Element): + attr = int(attr.text) # type: ignore + try: + attr = int(attr) + date_obj = datetime.datetime.fromtimestamp(attr, TZ_UTC) + except ValueError as err: + msg = "Cannot deserialize to unix datetime object." + raise DeserializationError(msg) from err + return date_obj diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ReportVersionTolerant/reportversiontolerant/_utils/utils.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ReportVersionTolerant/reportversiontolerant/_utils/utils.py new file mode 100644 index 00000000000..39b612f39a9 --- /dev/null +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ReportVersionTolerant/reportversiontolerant/_utils/utils.py @@ -0,0 +1,25 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from abc import ABC +from typing import Generic, TYPE_CHECKING, TypeVar + +if TYPE_CHECKING: + from .serialization import Deserializer, Serializer + + +TClient = TypeVar("TClient") +TConfig = TypeVar("TConfig") + + +class ClientMixinABC(ABC, Generic[TClient, TConfig]): + """DO NOT use this class. It is for internal typing use only.""" + + _client: TClient + _config: TConfig + _serialize: "Serializer" + _deserialize: "Deserializer" diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ReportVersionTolerant/reportversiontolerant/_vendor.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ReportVersionTolerant/reportversiontolerant/_vendor.py deleted file mode 100644 index 823d06e3b42..00000000000 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ReportVersionTolerant/reportversiontolerant/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) AutoRest Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import AutoRestReportServiceConfiguration - -if TYPE_CHECKING: - from azure.core import PipelineClient - - from ._serialization import Deserializer, Serializer - - -class AutoRestReportServiceMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "PipelineClient" - _config: AutoRestReportServiceConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ReportVersionTolerant/reportversiontolerant/aio/_client.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ReportVersionTolerant/reportversiontolerant/aio/_client.py index 7051bf848ed..add51244876 100644 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ReportVersionTolerant/reportversiontolerant/aio/_client.py +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ReportVersionTolerant/reportversiontolerant/aio/_client.py @@ -14,7 +14,7 @@ from azure.core.pipeline import policies from azure.core.rest import AsyncHttpResponse, HttpRequest -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import AutoRestReportServiceConfiguration from ._operations import AutoRestReportServiceOperationsMixin diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ReportVersionTolerant/reportversiontolerant/aio/_operations/_operations.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ReportVersionTolerant/reportversiontolerant/aio/_operations/_operations.py index c9c7f7b17d7..dd2f83e3667 100644 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ReportVersionTolerant/reportversiontolerant/aio/_operations/_operations.py +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ReportVersionTolerant/reportversiontolerant/aio/_operations/_operations.py @@ -9,6 +9,7 @@ from collections.abc import MutableMapping from typing import Any, Callable, Dict, Optional, TypeVar, cast +from azure.core import AsyncPipelineClient from azure.core.exceptions import ( ClientAuthenticationError, HttpResponseError, @@ -25,13 +26,14 @@ build_auto_rest_report_service_get_optional_report_request, build_auto_rest_report_service_get_report_request, ) -from .._vendor import AutoRestReportServiceMixinABC +from ..._utils.utils import ClientMixinABC +from .._configuration import AutoRestReportServiceConfiguration T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, AsyncHttpResponse], T, Dict[str, Any]], Any]] -class AutoRestReportServiceOperationsMixin(AutoRestReportServiceMixinABC): +class AutoRestReportServiceOperationsMixin(ClientMixinABC[AsyncPipelineClient, AutoRestReportServiceConfiguration]): @distributed_trace_async async def get_report(self, *, qualifier: Optional[str] = None, **kwargs: Any) -> Dict[str, int]: diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ReportVersionTolerant/reportversiontolerant/aio/_vendor.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ReportVersionTolerant/reportversiontolerant/aio/_vendor.py deleted file mode 100644 index 4777573d29a..00000000000 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ReportVersionTolerant/reportversiontolerant/aio/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) AutoRest Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import AutoRestReportServiceConfiguration - -if TYPE_CHECKING: - from azure.core import AsyncPipelineClient - - from .._serialization import Deserializer, Serializer - - -class AutoRestReportServiceMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "AsyncPipelineClient" - _config: AutoRestReportServiceConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/RequiredOptionalVersionTolerant/requiredoptionalversiontolerant/_client.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/RequiredOptionalVersionTolerant/requiredoptionalversiontolerant/_client.py index f5d4698eb73..d9e73ca8fca 100644 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/RequiredOptionalVersionTolerant/requiredoptionalversiontolerant/_client.py +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/RequiredOptionalVersionTolerant/requiredoptionalversiontolerant/_client.py @@ -15,7 +15,7 @@ from azure.core.rest import HttpRequest, HttpResponse from ._configuration import AutoRestRequiredOptionalTestServiceConfiguration -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer from .operations import ExplicitOperations, ImplicitOperations diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/RequiredOptionalVersionTolerant/requiredoptionalversiontolerant/_utils/__init__.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/RequiredOptionalVersionTolerant/requiredoptionalversiontolerant/_utils/__init__.py new file mode 100644 index 00000000000..0af9b28f660 --- /dev/null +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/RequiredOptionalVersionTolerant/requiredoptionalversiontolerant/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/RequiredOptionalVersionTolerant/requiredoptionalversiontolerant/_utils/serialization.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/RequiredOptionalVersionTolerant/requiredoptionalversiontolerant/_utils/serialization.py new file mode 100644 index 00000000000..f5187701d7b --- /dev/null +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/RequiredOptionalVersionTolerant/requiredoptionalversiontolerant/_utils/serialization.py @@ -0,0 +1,2032 @@ +# pylint: disable=line-too-long,useless-suppression,too-many-lines +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +# pyright: reportUnnecessaryTypeIgnoreComment=false + +from base64 import b64decode, b64encode +import calendar +import datetime +import decimal +import email +from enum import Enum +import json +import logging +import re +import sys +import codecs +from typing import ( + Dict, + Any, + cast, + Optional, + Union, + AnyStr, + IO, + Mapping, + Callable, + MutableMapping, + List, +) + +try: + from urllib import quote # type: ignore +except ImportError: + from urllib.parse import quote +import xml.etree.ElementTree as ET + +import isodate # type: ignore +from typing_extensions import Self + +from azure.core.exceptions import DeserializationError, SerializationError +from azure.core.serialization import NULL as CoreNull + +_BOM = codecs.BOM_UTF8.decode(encoding="utf-8") + +JSON = MutableMapping[str, Any] + + +class RawDeserializer: + + # Accept "text" because we're open minded people... + JSON_REGEXP = re.compile(r"^(application|text)/([a-z+.]+\+)?json$") + + # Name used in context + CONTEXT_NAME = "deserialized_data" + + @classmethod + def deserialize_from_text(cls, data: Optional[Union[AnyStr, IO]], content_type: Optional[str] = None) -> Any: + """Decode data according to content-type. + + Accept a stream of data as well, but will be load at once in memory for now. + + If no content-type, will return the string version (not bytes, not stream) + + :param data: Input, could be bytes or stream (will be decoded with UTF8) or text + :type data: str or bytes or IO + :param str content_type: The content type. + :return: The deserialized data. + :rtype: object + """ + if hasattr(data, "read"): + # Assume a stream + data = cast(IO, data).read() + + if isinstance(data, bytes): + data_as_str = data.decode(encoding="utf-8-sig") + else: + # Explain to mypy the correct type. + data_as_str = cast(str, data) + + # Remove Byte Order Mark if present in string + data_as_str = data_as_str.lstrip(_BOM) + + if content_type is None: + return data + + if cls.JSON_REGEXP.match(content_type): + try: + return json.loads(data_as_str) + except ValueError as err: + raise DeserializationError("JSON is invalid: {}".format(err), err) from err + elif "xml" in (content_type or []): + try: + + try: + if isinstance(data, unicode): # type: ignore + # If I'm Python 2.7 and unicode XML will scream if I try a "fromstring" on unicode string + data_as_str = data_as_str.encode(encoding="utf-8") # type: ignore + except NameError: + pass + + return ET.fromstring(data_as_str) # nosec + except ET.ParseError as err: + # It might be because the server has an issue, and returned JSON with + # content-type XML.... + # So let's try a JSON load, and if it's still broken + # let's flow the initial exception + def _json_attemp(data): + try: + return True, json.loads(data) + except ValueError: + return False, None # Don't care about this one + + success, json_result = _json_attemp(data) + if success: + return json_result + # If i'm here, it's not JSON, it's not XML, let's scream + # and raise the last context in this block (the XML exception) + # The function hack is because Py2.7 messes up with exception + # context otherwise. + _LOGGER.critical("Wasn't XML not JSON, failing") + raise DeserializationError("XML is invalid") from err + elif content_type.startswith("text/"): + return data_as_str + raise DeserializationError("Cannot deserialize content-type: {}".format(content_type)) + + @classmethod + def deserialize_from_http_generics(cls, body_bytes: Optional[Union[AnyStr, IO]], headers: Mapping) -> Any: + """Deserialize from HTTP response. + + Use bytes and headers to NOT use any requests/aiohttp or whatever + specific implementation. + Headers will tested for "content-type" + + :param bytes body_bytes: The body of the response. + :param dict headers: The headers of the response. + :returns: The deserialized data. + :rtype: object + """ + # Try to use content-type from headers if available + content_type = None + if "content-type" in headers: + content_type = headers["content-type"].split(";")[0].strip().lower() + # Ouch, this server did not declare what it sent... + # Let's guess it's JSON... + # Also, since Autorest was considering that an empty body was a valid JSON, + # need that test as well.... + else: + content_type = "application/json" + + if body_bytes: + return cls.deserialize_from_text(body_bytes, content_type) + return None + + +_LOGGER = logging.getLogger(__name__) + +try: + _long_type = long # type: ignore +except NameError: + _long_type = int + +TZ_UTC = datetime.timezone.utc + +_FLATTEN = re.compile(r"(? None: + self.additional_properties: Optional[Dict[str, Any]] = {} + for k in kwargs: # pylint: disable=consider-using-dict-items + if k not in self._attribute_map: + _LOGGER.warning("%s is not a known attribute of class %s and will be ignored", k, self.__class__) + elif k in self._validation and self._validation[k].get("readonly", False): + _LOGGER.warning("Readonly attribute %s will be ignored in class %s", k, self.__class__) + else: + setattr(self, k, kwargs[k]) + + def __eq__(self, other: Any) -> bool: + """Compare objects by comparing all attributes. + + :param object other: The object to compare + :returns: True if objects are equal + :rtype: bool + """ + if isinstance(other, self.__class__): + return self.__dict__ == other.__dict__ + return False + + def __ne__(self, other: Any) -> bool: + """Compare objects by comparing all attributes. + + :param object other: The object to compare + :returns: True if objects are not equal + :rtype: bool + """ + return not self.__eq__(other) + + def __str__(self) -> str: + return str(self.__dict__) + + @classmethod + def enable_additional_properties_sending(cls) -> None: + cls._attribute_map["additional_properties"] = {"key": "", "type": "{object}"} + + @classmethod + def is_xml_model(cls) -> bool: + try: + cls._xml_map # type: ignore + except AttributeError: + return False + return True + + @classmethod + def _create_xml_node(cls): + """Create XML node. + + :returns: The XML node + :rtype: xml.etree.ElementTree.Element + """ + try: + xml_map = cls._xml_map # type: ignore + except AttributeError: + xml_map = {} + + return _create_xml_node(xml_map.get("name", cls.__name__), xml_map.get("prefix", None), xml_map.get("ns", None)) + + def serialize(self, keep_readonly: bool = False, **kwargs: Any) -> JSON: + """Return the JSON that would be sent to server from this model. + + This is an alias to `as_dict(full_restapi_key_transformer, keep_readonly=False)`. + + If you want XML serialization, you can pass the kwargs is_xml=True. + + :param bool keep_readonly: If you want to serialize the readonly attributes + :returns: A dict JSON compatible object + :rtype: dict + """ + serializer = Serializer(self._infer_class_models()) + return serializer._serialize( # type: ignore # pylint: disable=protected-access + self, keep_readonly=keep_readonly, **kwargs + ) + + def as_dict( + self, + keep_readonly: bool = True, + key_transformer: Callable[[str, Dict[str, Any], Any], Any] = attribute_transformer, + **kwargs: Any + ) -> JSON: + """Return a dict that can be serialized using json.dump. + + Advanced usage might optionally use a callback as parameter: + + .. code::python + + def my_key_transformer(key, attr_desc, value): + return key + + Key is the attribute name used in Python. Attr_desc + is a dict of metadata. Currently contains 'type' with the + msrest type and 'key' with the RestAPI encoded key. + Value is the current value in this object. + + The string returned will be used to serialize the key. + If the return type is a list, this is considered hierarchical + result dict. + + See the three examples in this file: + + - attribute_transformer + - full_restapi_key_transformer + - last_restapi_key_transformer + + If you want XML serialization, you can pass the kwargs is_xml=True. + + :param bool keep_readonly: If you want to serialize the readonly attributes + :param function key_transformer: A key transformer function. + :returns: A dict JSON compatible object + :rtype: dict + """ + serializer = Serializer(self._infer_class_models()) + return serializer._serialize( # type: ignore # pylint: disable=protected-access + self, key_transformer=key_transformer, keep_readonly=keep_readonly, **kwargs + ) + + @classmethod + def _infer_class_models(cls): + try: + str_models = cls.__module__.rsplit(".", 1)[0] + models = sys.modules[str_models] + client_models = {k: v for k, v in models.__dict__.items() if isinstance(v, type)} + if cls.__name__ not in client_models: + raise ValueError("Not Autorest generated code") + except Exception: # pylint: disable=broad-exception-caught + # Assume it's not Autorest generated (tests?). Add ourselves as dependencies. + client_models = {cls.__name__: cls} + return client_models + + @classmethod + def deserialize(cls, data: Any, content_type: Optional[str] = None) -> Self: + """Parse a str using the RestAPI syntax and return a model. + + :param str data: A str using RestAPI structure. JSON by default. + :param str content_type: JSON by default, set application/xml if XML. + :returns: An instance of this model + :raises DeserializationError: if something went wrong + :rtype: Self + """ + deserializer = Deserializer(cls._infer_class_models()) + return deserializer(cls.__name__, data, content_type=content_type) # type: ignore + + @classmethod + def from_dict( + cls, + data: Any, + key_extractors: Optional[Callable[[str, Dict[str, Any], Any], Any]] = None, + content_type: Optional[str] = None, + ) -> Self: + """Parse a dict using given key extractor return a model. + + By default consider key + extractors (rest_key_case_insensitive_extractor, attribute_key_case_insensitive_extractor + and last_rest_key_case_insensitive_extractor) + + :param dict data: A dict using RestAPI structure + :param function key_extractors: A key extractor function. + :param str content_type: JSON by default, set application/xml if XML. + :returns: An instance of this model + :raises DeserializationError: if something went wrong + :rtype: Self + """ + deserializer = Deserializer(cls._infer_class_models()) + deserializer.key_extractors = ( # type: ignore + [ # type: ignore + attribute_key_case_insensitive_extractor, + rest_key_case_insensitive_extractor, + last_rest_key_case_insensitive_extractor, + ] + if key_extractors is None + else key_extractors + ) + return deserializer(cls.__name__, data, content_type=content_type) # type: ignore + + @classmethod + def _flatten_subtype(cls, key, objects): + if "_subtype_map" not in cls.__dict__: + return {} + result = dict(cls._subtype_map[key]) + for valuetype in cls._subtype_map[key].values(): + result.update(objects[valuetype]._flatten_subtype(key, objects)) # pylint: disable=protected-access + return result + + @classmethod + def _classify(cls, response, objects): + """Check the class _subtype_map for any child classes. + We want to ignore any inherited _subtype_maps. + + :param dict response: The initial data + :param dict objects: The class objects + :returns: The class to be used + :rtype: class + """ + for subtype_key in cls.__dict__.get("_subtype_map", {}).keys(): + subtype_value = None + + if not isinstance(response, ET.Element): + rest_api_response_key = cls._get_rest_key_parts(subtype_key)[-1] + subtype_value = response.get(rest_api_response_key, None) or response.get(subtype_key, None) + else: + subtype_value = xml_key_extractor(subtype_key, cls._attribute_map[subtype_key], response) + if subtype_value: + # Try to match base class. Can be class name only + # (bug to fix in Autorest to support x-ms-discriminator-name) + if cls.__name__ == subtype_value: + return cls + flatten_mapping_type = cls._flatten_subtype(subtype_key, objects) + try: + return objects[flatten_mapping_type[subtype_value]] # type: ignore + except KeyError: + _LOGGER.warning( + "Subtype value %s has no mapping, use base class %s.", + subtype_value, + cls.__name__, + ) + break + else: + _LOGGER.warning("Discriminator %s is absent or null, use base class %s.", subtype_key, cls.__name__) + break + return cls + + @classmethod + def _get_rest_key_parts(cls, attr_key): + """Get the RestAPI key of this attr, split it and decode part + :param str attr_key: Attribute key must be in attribute_map. + :returns: A list of RestAPI part + :rtype: list + """ + rest_split_key = _FLATTEN.split(cls._attribute_map[attr_key]["key"]) + return [_decode_attribute_map_key(key_part) for key_part in rest_split_key] + + +def _decode_attribute_map_key(key): + """This decode a key in an _attribute_map to the actual key we want to look at + inside the received data. + + :param str key: A key string from the generated code + :returns: The decoded key + :rtype: str + """ + return key.replace("\\.", ".") + + +class Serializer: # pylint: disable=too-many-public-methods + """Request object model serializer.""" + + basic_types = {str: "str", int: "int", bool: "bool", float: "float"} + + _xml_basic_types_serializers = {"bool": lambda x: str(x).lower()} + days = {0: "Mon", 1: "Tue", 2: "Wed", 3: "Thu", 4: "Fri", 5: "Sat", 6: "Sun"} + months = { + 1: "Jan", + 2: "Feb", + 3: "Mar", + 4: "Apr", + 5: "May", + 6: "Jun", + 7: "Jul", + 8: "Aug", + 9: "Sep", + 10: "Oct", + 11: "Nov", + 12: "Dec", + } + validation = { + "min_length": lambda x, y: len(x) < y, + "max_length": lambda x, y: len(x) > y, + "minimum": lambda x, y: x < y, + "maximum": lambda x, y: x > y, + "minimum_ex": lambda x, y: x <= y, + "maximum_ex": lambda x, y: x >= y, + "min_items": lambda x, y: len(x) < y, + "max_items": lambda x, y: len(x) > y, + "pattern": lambda x, y: not re.match(y, x, re.UNICODE), + "unique": lambda x, y: len(x) != len(set(x)), + "multiple": lambda x, y: x % y != 0, + } + + def __init__(self, classes: Optional[Mapping[str, type]] = None) -> None: + self.serialize_type = { + "iso-8601": Serializer.serialize_iso, + "rfc-1123": Serializer.serialize_rfc, + "unix-time": Serializer.serialize_unix, + "duration": Serializer.serialize_duration, + "date": Serializer.serialize_date, + "time": Serializer.serialize_time, + "decimal": Serializer.serialize_decimal, + "long": Serializer.serialize_long, + "bytearray": Serializer.serialize_bytearray, + "base64": Serializer.serialize_base64, + "object": self.serialize_object, + "[]": self.serialize_iter, + "{}": self.serialize_dict, + } + self.dependencies: Dict[str, type] = dict(classes) if classes else {} + self.key_transformer = full_restapi_key_transformer + self.client_side_validation = True + + def _serialize( # pylint: disable=too-many-nested-blocks, too-many-branches, too-many-statements, too-many-locals + self, target_obj, data_type=None, **kwargs + ): + """Serialize data into a string according to type. + + :param object target_obj: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str, dict + :raises SerializationError: if serialization fails. + :returns: The serialized data. + """ + key_transformer = kwargs.get("key_transformer", self.key_transformer) + keep_readonly = kwargs.get("keep_readonly", False) + if target_obj is None: + return None + + attr_name = None + class_name = target_obj.__class__.__name__ + + if data_type: + return self.serialize_data(target_obj, data_type, **kwargs) + + if not hasattr(target_obj, "_attribute_map"): + data_type = type(target_obj).__name__ + if data_type in self.basic_types.values(): + return self.serialize_data(target_obj, data_type, **kwargs) + + # Force "is_xml" kwargs if we detect a XML model + try: + is_xml_model_serialization = kwargs["is_xml"] + except KeyError: + is_xml_model_serialization = kwargs.setdefault("is_xml", target_obj.is_xml_model()) + + serialized = {} + if is_xml_model_serialization: + serialized = target_obj._create_xml_node() # pylint: disable=protected-access + try: + attributes = target_obj._attribute_map # pylint: disable=protected-access + for attr, attr_desc in attributes.items(): + attr_name = attr + if not keep_readonly and target_obj._validation.get( # pylint: disable=protected-access + attr_name, {} + ).get("readonly", False): + continue + + if attr_name == "additional_properties" and attr_desc["key"] == "": + if target_obj.additional_properties is not None: + serialized.update(target_obj.additional_properties) + continue + try: + + orig_attr = getattr(target_obj, attr) + if is_xml_model_serialization: + pass # Don't provide "transformer" for XML for now. Keep "orig_attr" + else: # JSON + keys, orig_attr = key_transformer(attr, attr_desc.copy(), orig_attr) + keys = keys if isinstance(keys, list) else [keys] + + kwargs["serialization_ctxt"] = attr_desc + new_attr = self.serialize_data(orig_attr, attr_desc["type"], **kwargs) + + if is_xml_model_serialization: + xml_desc = attr_desc.get("xml", {}) + xml_name = xml_desc.get("name", attr_desc["key"]) + xml_prefix = xml_desc.get("prefix", None) + xml_ns = xml_desc.get("ns", None) + if xml_desc.get("attr", False): + if xml_ns: + ET.register_namespace(xml_prefix, xml_ns) + xml_name = "{{{}}}{}".format(xml_ns, xml_name) + serialized.set(xml_name, new_attr) # type: ignore + continue + if xml_desc.get("text", False): + serialized.text = new_attr # type: ignore + continue + if isinstance(new_attr, list): + serialized.extend(new_attr) # type: ignore + elif isinstance(new_attr, ET.Element): + # If the down XML has no XML/Name, + # we MUST replace the tag with the local tag. But keeping the namespaces. + if "name" not in getattr(orig_attr, "_xml_map", {}): + splitted_tag = new_attr.tag.split("}") + if len(splitted_tag) == 2: # Namespace + new_attr.tag = "}".join([splitted_tag[0], xml_name]) + else: + new_attr.tag = xml_name + serialized.append(new_attr) # type: ignore + else: # That's a basic type + # Integrate namespace if necessary + local_node = _create_xml_node(xml_name, xml_prefix, xml_ns) + local_node.text = str(new_attr) + serialized.append(local_node) # type: ignore + else: # JSON + for k in reversed(keys): # type: ignore + new_attr = {k: new_attr} + + _new_attr = new_attr + _serialized = serialized + for k in keys: # type: ignore + if k not in _serialized: + _serialized.update(_new_attr) # type: ignore + _new_attr = _new_attr[k] # type: ignore + _serialized = _serialized[k] + except ValueError as err: + if isinstance(err, SerializationError): + raise + + except (AttributeError, KeyError, TypeError) as err: + msg = "Attribute {} in object {} cannot be serialized.\n{}".format(attr_name, class_name, str(target_obj)) + raise SerializationError(msg) from err + return serialized + + def body(self, data, data_type, **kwargs): + """Serialize data intended for a request body. + + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: dict + :raises SerializationError: if serialization fails. + :raises ValueError: if data is None + :returns: The serialized request body + """ + + # Just in case this is a dict + internal_data_type_str = data_type.strip("[]{}") + internal_data_type = self.dependencies.get(internal_data_type_str, None) + try: + is_xml_model_serialization = kwargs["is_xml"] + except KeyError: + if internal_data_type and issubclass(internal_data_type, Model): + is_xml_model_serialization = kwargs.setdefault("is_xml", internal_data_type.is_xml_model()) + else: + is_xml_model_serialization = False + if internal_data_type and not isinstance(internal_data_type, Enum): + try: + deserializer = Deserializer(self.dependencies) + # Since it's on serialization, it's almost sure that format is not JSON REST + # We're not able to deal with additional properties for now. + deserializer.additional_properties_detection = False + if is_xml_model_serialization: + deserializer.key_extractors = [ # type: ignore + attribute_key_case_insensitive_extractor, + ] + else: + deserializer.key_extractors = [ + rest_key_case_insensitive_extractor, + attribute_key_case_insensitive_extractor, + last_rest_key_case_insensitive_extractor, + ] + data = deserializer._deserialize(data_type, data) # pylint: disable=protected-access + except DeserializationError as err: + raise SerializationError("Unable to build a model: " + str(err)) from err + + return self._serialize(data, data_type, **kwargs) + + def url(self, name, data, data_type, **kwargs): + """Serialize data intended for a URL path. + + :param str name: The name of the URL path parameter. + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str + :returns: The serialized URL path + :raises TypeError: if serialization fails. + :raises ValueError: if data is None + """ + try: + output = self.serialize_data(data, data_type, **kwargs) + if data_type == "bool": + output = json.dumps(output) + + if kwargs.get("skip_quote") is True: + output = str(output) + output = output.replace("{", quote("{")).replace("}", quote("}")) + else: + output = quote(str(output), safe="") + except SerializationError as exc: + raise TypeError("{} must be type {}.".format(name, data_type)) from exc + return output + + def query(self, name, data, data_type, **kwargs): + """Serialize data intended for a URL query. + + :param str name: The name of the query parameter. + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str, list + :raises TypeError: if serialization fails. + :raises ValueError: if data is None + :returns: The serialized query parameter + """ + try: + # Treat the list aside, since we don't want to encode the div separator + if data_type.startswith("["): + internal_data_type = data_type[1:-1] + do_quote = not kwargs.get("skip_quote", False) + return self.serialize_iter(data, internal_data_type, do_quote=do_quote, **kwargs) + + # Not a list, regular serialization + output = self.serialize_data(data, data_type, **kwargs) + if data_type == "bool": + output = json.dumps(output) + if kwargs.get("skip_quote") is True: + output = str(output) + else: + output = quote(str(output), safe="") + except SerializationError as exc: + raise TypeError("{} must be type {}.".format(name, data_type)) from exc + return str(output) + + def header(self, name, data, data_type, **kwargs): + """Serialize data intended for a request header. + + :param str name: The name of the header. + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str + :raises TypeError: if serialization fails. + :raises ValueError: if data is None + :returns: The serialized header + """ + try: + if data_type in ["[str]"]: + data = ["" if d is None else d for d in data] + + output = self.serialize_data(data, data_type, **kwargs) + if data_type == "bool": + output = json.dumps(output) + except SerializationError as exc: + raise TypeError("{} must be type {}.".format(name, data_type)) from exc + return str(output) + + def serialize_data(self, data, data_type, **kwargs): + """Serialize generic data according to supplied data type. + + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :raises AttributeError: if required data is None. + :raises ValueError: if data is None + :raises SerializationError: if serialization fails. + :returns: The serialized data. + :rtype: str, int, float, bool, dict, list + """ + if data is None: + raise ValueError("No value for given attribute") + + try: + if data is CoreNull: + return None + if data_type in self.basic_types.values(): + return self.serialize_basic(data, data_type, **kwargs) + + if data_type in self.serialize_type: + return self.serialize_type[data_type](data, **kwargs) + + # If dependencies is empty, try with current data class + # It has to be a subclass of Enum anyway + enum_type = self.dependencies.get(data_type, data.__class__) + if issubclass(enum_type, Enum): + return Serializer.serialize_enum(data, enum_obj=enum_type) + + iter_type = data_type[0] + data_type[-1] + if iter_type in self.serialize_type: + return self.serialize_type[iter_type](data, data_type[1:-1], **kwargs) + + except (ValueError, TypeError) as err: + msg = "Unable to serialize value: {!r} as type: {!r}." + raise SerializationError(msg.format(data, data_type)) from err + return self._serialize(data, **kwargs) + + @classmethod + def _get_custom_serializers(cls, data_type, **kwargs): # pylint: disable=inconsistent-return-statements + custom_serializer = kwargs.get("basic_types_serializers", {}).get(data_type) + if custom_serializer: + return custom_serializer + if kwargs.get("is_xml", False): + return cls._xml_basic_types_serializers.get(data_type) + + @classmethod + def serialize_basic(cls, data, data_type, **kwargs): + """Serialize basic builting data type. + Serializes objects to str, int, float or bool. + + Possible kwargs: + - basic_types_serializers dict[str, callable] : If set, use the callable as serializer + - is_xml bool : If set, use xml_basic_types_serializers + + :param obj data: Object to be serialized. + :param str data_type: Type of object in the iterable. + :rtype: str, int, float, bool + :return: serialized object + """ + custom_serializer = cls._get_custom_serializers(data_type, **kwargs) + if custom_serializer: + return custom_serializer(data) + if data_type == "str": + return cls.serialize_unicode(data) + return eval(data_type)(data) # nosec # pylint: disable=eval-used + + @classmethod + def serialize_unicode(cls, data): + """Special handling for serializing unicode strings in Py2. + Encode to UTF-8 if unicode, otherwise handle as a str. + + :param str data: Object to be serialized. + :rtype: str + :return: serialized object + """ + try: # If I received an enum, return its value + return data.value + except AttributeError: + pass + + try: + if isinstance(data, unicode): # type: ignore + # Don't change it, JSON and XML ElementTree are totally able + # to serialize correctly u'' strings + return data + except NameError: + return str(data) + return str(data) + + def serialize_iter(self, data, iter_type, div=None, **kwargs): + """Serialize iterable. + + Supported kwargs: + - serialization_ctxt dict : The current entry of _attribute_map, or same format. + serialization_ctxt['type'] should be same as data_type. + - is_xml bool : If set, serialize as XML + + :param list data: Object to be serialized. + :param str iter_type: Type of object in the iterable. + :param str div: If set, this str will be used to combine the elements + in the iterable into a combined string. Default is 'None'. + Defaults to False. + :rtype: list, str + :return: serialized iterable + """ + if isinstance(data, str): + raise SerializationError("Refuse str type as a valid iter type.") + + serialization_ctxt = kwargs.get("serialization_ctxt", {}) + is_xml = kwargs.get("is_xml", False) + + serialized = [] + for d in data: + try: + serialized.append(self.serialize_data(d, iter_type, **kwargs)) + except ValueError as err: + if isinstance(err, SerializationError): + raise + serialized.append(None) + + if kwargs.get("do_quote", False): + serialized = ["" if s is None else quote(str(s), safe="") for s in serialized] + + if div: + serialized = ["" if s is None else str(s) for s in serialized] + serialized = div.join(serialized) + + if "xml" in serialization_ctxt or is_xml: + # XML serialization is more complicated + xml_desc = serialization_ctxt.get("xml", {}) + xml_name = xml_desc.get("name") + if not xml_name: + xml_name = serialization_ctxt["key"] + + # Create a wrap node if necessary (use the fact that Element and list have "append") + is_wrapped = xml_desc.get("wrapped", False) + node_name = xml_desc.get("itemsName", xml_name) + if is_wrapped: + final_result = _create_xml_node(xml_name, xml_desc.get("prefix", None), xml_desc.get("ns", None)) + else: + final_result = [] + # All list elements to "local_node" + for el in serialized: + if isinstance(el, ET.Element): + el_node = el + else: + el_node = _create_xml_node(node_name, xml_desc.get("prefix", None), xml_desc.get("ns", None)) + if el is not None: # Otherwise it writes "None" :-p + el_node.text = str(el) + final_result.append(el_node) + return final_result + return serialized + + def serialize_dict(self, attr, dict_type, **kwargs): + """Serialize a dictionary of objects. + + :param dict attr: Object to be serialized. + :param str dict_type: Type of object in the dictionary. + :rtype: dict + :return: serialized dictionary + """ + serialization_ctxt = kwargs.get("serialization_ctxt", {}) + serialized = {} + for key, value in attr.items(): + try: + serialized[self.serialize_unicode(key)] = self.serialize_data(value, dict_type, **kwargs) + except ValueError as err: + if isinstance(err, SerializationError): + raise + serialized[self.serialize_unicode(key)] = None + + if "xml" in serialization_ctxt: + # XML serialization is more complicated + xml_desc = serialization_ctxt["xml"] + xml_name = xml_desc["name"] + + final_result = _create_xml_node(xml_name, xml_desc.get("prefix", None), xml_desc.get("ns", None)) + for key, value in serialized.items(): + ET.SubElement(final_result, key).text = value + return final_result + + return serialized + + def serialize_object(self, attr, **kwargs): # pylint: disable=too-many-return-statements + """Serialize a generic object. + This will be handled as a dictionary. If object passed in is not + a basic type (str, int, float, dict, list) it will simply be + cast to str. + + :param dict attr: Object to be serialized. + :rtype: dict or str + :return: serialized object + """ + if attr is None: + return None + if isinstance(attr, ET.Element): + return attr + obj_type = type(attr) + if obj_type in self.basic_types: + return self.serialize_basic(attr, self.basic_types[obj_type], **kwargs) + if obj_type is _long_type: + return self.serialize_long(attr) + if obj_type is str: + return self.serialize_unicode(attr) + if obj_type is datetime.datetime: + return self.serialize_iso(attr) + if obj_type is datetime.date: + return self.serialize_date(attr) + if obj_type is datetime.time: + return self.serialize_time(attr) + if obj_type is datetime.timedelta: + return self.serialize_duration(attr) + if obj_type is decimal.Decimal: + return self.serialize_decimal(attr) + + # If it's a model or I know this dependency, serialize as a Model + if obj_type in self.dependencies.values() or isinstance(attr, Model): + return self._serialize(attr) + + if obj_type == dict: + serialized = {} + for key, value in attr.items(): + try: + serialized[self.serialize_unicode(key)] = self.serialize_object(value, **kwargs) + except ValueError: + serialized[self.serialize_unicode(key)] = None + return serialized + + if obj_type == list: + serialized = [] + for obj in attr: + try: + serialized.append(self.serialize_object(obj, **kwargs)) + except ValueError: + pass + return serialized + return str(attr) + + @staticmethod + def serialize_enum(attr, enum_obj=None): + try: + result = attr.value + except AttributeError: + result = attr + try: + enum_obj(result) # type: ignore + return result + except ValueError as exc: + for enum_value in enum_obj: # type: ignore + if enum_value.value.lower() == str(attr).lower(): + return enum_value.value + error = "{!r} is not valid value for enum {!r}" + raise SerializationError(error.format(attr, enum_obj)) from exc + + @staticmethod + def serialize_bytearray(attr, **kwargs): # pylint: disable=unused-argument + """Serialize bytearray into base-64 string. + + :param str attr: Object to be serialized. + :rtype: str + :return: serialized base64 + """ + return b64encode(attr).decode() + + @staticmethod + def serialize_base64(attr, **kwargs): # pylint: disable=unused-argument + """Serialize str into base-64 string. + + :param str attr: Object to be serialized. + :rtype: str + :return: serialized base64 + """ + encoded = b64encode(attr).decode("ascii") + return encoded.strip("=").replace("+", "-").replace("/", "_") + + @staticmethod + def serialize_decimal(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Decimal object to float. + + :param decimal attr: Object to be serialized. + :rtype: float + :return: serialized decimal + """ + return float(attr) + + @staticmethod + def serialize_long(attr, **kwargs): # pylint: disable=unused-argument + """Serialize long (Py2) or int (Py3). + + :param int attr: Object to be serialized. + :rtype: int/long + :return: serialized long + """ + return _long_type(attr) + + @staticmethod + def serialize_date(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Date object into ISO-8601 formatted string. + + :param Date attr: Object to be serialized. + :rtype: str + :return: serialized date + """ + if isinstance(attr, str): + attr = isodate.parse_date(attr) + t = "{:04}-{:02}-{:02}".format(attr.year, attr.month, attr.day) + return t + + @staticmethod + def serialize_time(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Time object into ISO-8601 formatted string. + + :param datetime.time attr: Object to be serialized. + :rtype: str + :return: serialized time + """ + if isinstance(attr, str): + attr = isodate.parse_time(attr) + t = "{:02}:{:02}:{:02}".format(attr.hour, attr.minute, attr.second) + if attr.microsecond: + t += ".{:02}".format(attr.microsecond) + return t + + @staticmethod + def serialize_duration(attr, **kwargs): # pylint: disable=unused-argument + """Serialize TimeDelta object into ISO-8601 formatted string. + + :param TimeDelta attr: Object to be serialized. + :rtype: str + :return: serialized duration + """ + if isinstance(attr, str): + attr = isodate.parse_duration(attr) + return isodate.duration_isoformat(attr) + + @staticmethod + def serialize_rfc(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Datetime object into RFC-1123 formatted string. + + :param Datetime attr: Object to be serialized. + :rtype: str + :raises TypeError: if format invalid. + :return: serialized rfc + """ + try: + if not attr.tzinfo: + _LOGGER.warning("Datetime with no tzinfo will be considered UTC.") + utc = attr.utctimetuple() + except AttributeError as exc: + raise TypeError("RFC1123 object must be valid Datetime object.") from exc + + return "{}, {:02} {} {:04} {:02}:{:02}:{:02} GMT".format( + Serializer.days[utc.tm_wday], + utc.tm_mday, + Serializer.months[utc.tm_mon], + utc.tm_year, + utc.tm_hour, + utc.tm_min, + utc.tm_sec, + ) + + @staticmethod + def serialize_iso(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Datetime object into ISO-8601 formatted string. + + :param Datetime attr: Object to be serialized. + :rtype: str + :raises SerializationError: if format invalid. + :return: serialized iso + """ + if isinstance(attr, str): + attr = isodate.parse_datetime(attr) + try: + if not attr.tzinfo: + _LOGGER.warning("Datetime with no tzinfo will be considered UTC.") + utc = attr.utctimetuple() + if utc.tm_year > 9999 or utc.tm_year < 1: + raise OverflowError("Hit max or min date") + + microseconds = str(attr.microsecond).rjust(6, "0").rstrip("0").ljust(3, "0") + if microseconds: + microseconds = "." + microseconds + date = "{:04}-{:02}-{:02}T{:02}:{:02}:{:02}".format( + utc.tm_year, utc.tm_mon, utc.tm_mday, utc.tm_hour, utc.tm_min, utc.tm_sec + ) + return date + microseconds + "Z" + except (ValueError, OverflowError) as err: + msg = "Unable to serialize datetime object." + raise SerializationError(msg) from err + except AttributeError as err: + msg = "ISO-8601 object must be valid Datetime object." + raise TypeError(msg) from err + + @staticmethod + def serialize_unix(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Datetime object into IntTime format. + This is represented as seconds. + + :param Datetime attr: Object to be serialized. + :rtype: int + :raises SerializationError: if format invalid + :return: serialied unix + """ + if isinstance(attr, int): + return attr + try: + if not attr.tzinfo: + _LOGGER.warning("Datetime with no tzinfo will be considered UTC.") + return int(calendar.timegm(attr.utctimetuple())) + except AttributeError as exc: + raise TypeError("Unix time object must be valid Datetime object.") from exc + + +def rest_key_extractor(attr, attr_desc, data): # pylint: disable=unused-argument + key = attr_desc["key"] + working_data = data + + while "." in key: + # Need the cast, as for some reasons "split" is typed as list[str | Any] + dict_keys = cast(List[str], _FLATTEN.split(key)) + if len(dict_keys) == 1: + key = _decode_attribute_map_key(dict_keys[0]) + break + working_key = _decode_attribute_map_key(dict_keys[0]) + working_data = working_data.get(working_key, data) + if working_data is None: + # If at any point while following flatten JSON path see None, it means + # that all properties under are None as well + return None + key = ".".join(dict_keys[1:]) + + return working_data.get(key) + + +def rest_key_case_insensitive_extractor( # pylint: disable=unused-argument, inconsistent-return-statements + attr, attr_desc, data +): + key = attr_desc["key"] + working_data = data + + while "." in key: + dict_keys = _FLATTEN.split(key) + if len(dict_keys) == 1: + key = _decode_attribute_map_key(dict_keys[0]) + break + working_key = _decode_attribute_map_key(dict_keys[0]) + working_data = attribute_key_case_insensitive_extractor(working_key, None, working_data) + if working_data is None: + # If at any point while following flatten JSON path see None, it means + # that all properties under are None as well + return None + key = ".".join(dict_keys[1:]) + + if working_data: + return attribute_key_case_insensitive_extractor(key, None, working_data) + + +def last_rest_key_extractor(attr, attr_desc, data): # pylint: disable=unused-argument + """Extract the attribute in "data" based on the last part of the JSON path key. + + :param str attr: The attribute to extract + :param dict attr_desc: The attribute description + :param dict data: The data to extract from + :rtype: object + :returns: The extracted attribute + """ + key = attr_desc["key"] + dict_keys = _FLATTEN.split(key) + return attribute_key_extractor(dict_keys[-1], None, data) + + +def last_rest_key_case_insensitive_extractor(attr, attr_desc, data): # pylint: disable=unused-argument + """Extract the attribute in "data" based on the last part of the JSON path key. + + This is the case insensitive version of "last_rest_key_extractor" + :param str attr: The attribute to extract + :param dict attr_desc: The attribute description + :param dict data: The data to extract from + :rtype: object + :returns: The extracted attribute + """ + key = attr_desc["key"] + dict_keys = _FLATTEN.split(key) + return attribute_key_case_insensitive_extractor(dict_keys[-1], None, data) + + +def attribute_key_extractor(attr, _, data): + return data.get(attr) + + +def attribute_key_case_insensitive_extractor(attr, _, data): + found_key = None + lower_attr = attr.lower() + for key in data: + if lower_attr == key.lower(): + found_key = key + break + + return data.get(found_key) + + +def _extract_name_from_internal_type(internal_type): + """Given an internal type XML description, extract correct XML name with namespace. + + :param dict internal_type: An model type + :rtype: tuple + :returns: A tuple XML name + namespace dict + """ + internal_type_xml_map = getattr(internal_type, "_xml_map", {}) + xml_name = internal_type_xml_map.get("name", internal_type.__name__) + xml_ns = internal_type_xml_map.get("ns", None) + if xml_ns: + xml_name = "{{{}}}{}".format(xml_ns, xml_name) + return xml_name + + +def xml_key_extractor(attr, attr_desc, data): # pylint: disable=unused-argument,too-many-return-statements + if isinstance(data, dict): + return None + + # Test if this model is XML ready first + if not isinstance(data, ET.Element): + return None + + xml_desc = attr_desc.get("xml", {}) + xml_name = xml_desc.get("name", attr_desc["key"]) + + # Look for a children + is_iter_type = attr_desc["type"].startswith("[") + is_wrapped = xml_desc.get("wrapped", False) + internal_type = attr_desc.get("internalType", None) + internal_type_xml_map = getattr(internal_type, "_xml_map", {}) + + # Integrate namespace if necessary + xml_ns = xml_desc.get("ns", internal_type_xml_map.get("ns", None)) + if xml_ns: + xml_name = "{{{}}}{}".format(xml_ns, xml_name) + + # If it's an attribute, that's simple + if xml_desc.get("attr", False): + return data.get(xml_name) + + # If it's x-ms-text, that's simple too + if xml_desc.get("text", False): + return data.text + + # Scenario where I take the local name: + # - Wrapped node + # - Internal type is an enum (considered basic types) + # - Internal type has no XML/Name node + if is_wrapped or (internal_type and (issubclass(internal_type, Enum) or "name" not in internal_type_xml_map)): + children = data.findall(xml_name) + # If internal type has a local name and it's not a list, I use that name + elif not is_iter_type and internal_type and "name" in internal_type_xml_map: + xml_name = _extract_name_from_internal_type(internal_type) + children = data.findall(xml_name) + # That's an array + else: + if internal_type: # Complex type, ignore itemsName and use the complex type name + items_name = _extract_name_from_internal_type(internal_type) + else: + items_name = xml_desc.get("itemsName", xml_name) + children = data.findall(items_name) + + if len(children) == 0: + if is_iter_type: + if is_wrapped: + return None # is_wrapped no node, we want None + return [] # not wrapped, assume empty list + return None # Assume it's not there, maybe an optional node. + + # If is_iter_type and not wrapped, return all found children + if is_iter_type: + if not is_wrapped: + return children + # Iter and wrapped, should have found one node only (the wrap one) + if len(children) != 1: + raise DeserializationError( + "Tried to deserialize an array not wrapped, and found several nodes '{}'. Maybe you should declare this array as wrapped?".format( + xml_name + ) + ) + return list(children[0]) # Might be empty list and that's ok. + + # Here it's not a itertype, we should have found one element only or empty + if len(children) > 1: + raise DeserializationError("Find several XML '{}' where it was not expected".format(xml_name)) + return children[0] + + +class Deserializer: + """Response object model deserializer. + + :param dict classes: Class type dictionary for deserializing complex types. + :ivar list key_extractors: Ordered list of extractors to be used by this deserializer. + """ + + basic_types = {str: "str", int: "int", bool: "bool", float: "float"} + + valid_date = re.compile(r"\d{4}[-]\d{2}[-]\d{2}T\d{2}:\d{2}:\d{2}\.?\d*Z?[-+]?[\d{2}]?:?[\d{2}]?") + + def __init__(self, classes: Optional[Mapping[str, type]] = None) -> None: + self.deserialize_type = { + "iso-8601": Deserializer.deserialize_iso, + "rfc-1123": Deserializer.deserialize_rfc, + "unix-time": Deserializer.deserialize_unix, + "duration": Deserializer.deserialize_duration, + "date": Deserializer.deserialize_date, + "time": Deserializer.deserialize_time, + "decimal": Deserializer.deserialize_decimal, + "long": Deserializer.deserialize_long, + "bytearray": Deserializer.deserialize_bytearray, + "base64": Deserializer.deserialize_base64, + "object": self.deserialize_object, + "[]": self.deserialize_iter, + "{}": self.deserialize_dict, + } + self.deserialize_expected_types = { + "duration": (isodate.Duration, datetime.timedelta), + "iso-8601": (datetime.datetime), + } + self.dependencies: Dict[str, type] = dict(classes) if classes else {} + self.key_extractors = [rest_key_extractor, xml_key_extractor] + # Additional properties only works if the "rest_key_extractor" is used to + # extract the keys. Making it to work whatever the key extractor is too much + # complicated, with no real scenario for now. + # So adding a flag to disable additional properties detection. This flag should be + # used if your expect the deserialization to NOT come from a JSON REST syntax. + # Otherwise, result are unexpected + self.additional_properties_detection = True + + def __call__(self, target_obj, response_data, content_type=None): + """Call the deserializer to process a REST response. + + :param str target_obj: Target data type to deserialize to. + :param requests.Response response_data: REST response object. + :param str content_type: Swagger "produces" if available. + :raises DeserializationError: if deserialization fails. + :return: Deserialized object. + :rtype: object + """ + data = self._unpack_content(response_data, content_type) + return self._deserialize(target_obj, data) + + def _deserialize(self, target_obj, data): # pylint: disable=inconsistent-return-statements + """Call the deserializer on a model. + + Data needs to be already deserialized as JSON or XML ElementTree + + :param str target_obj: Target data type to deserialize to. + :param object data: Object to deserialize. + :raises DeserializationError: if deserialization fails. + :return: Deserialized object. + :rtype: object + """ + # This is already a model, go recursive just in case + if hasattr(data, "_attribute_map"): + constants = [name for name, config in getattr(data, "_validation", {}).items() if config.get("constant")] + try: + for attr, mapconfig in data._attribute_map.items(): # pylint: disable=protected-access + if attr in constants: + continue + value = getattr(data, attr) + if value is None: + continue + local_type = mapconfig["type"] + internal_data_type = local_type.strip("[]{}") + if internal_data_type not in self.dependencies or isinstance(internal_data_type, Enum): + continue + setattr(data, attr, self._deserialize(local_type, value)) + return data + except AttributeError: + return + + response, class_name = self._classify_target(target_obj, data) + + if isinstance(response, str): + return self.deserialize_data(data, response) + if isinstance(response, type) and issubclass(response, Enum): + return self.deserialize_enum(data, response) + + if data is None or data is CoreNull: + return data + try: + attributes = response._attribute_map # type: ignore # pylint: disable=protected-access + d_attrs = {} + for attr, attr_desc in attributes.items(): + # Check empty string. If it's not empty, someone has a real "additionalProperties"... + if attr == "additional_properties" and attr_desc["key"] == "": + continue + raw_value = None + # Enhance attr_desc with some dynamic data + attr_desc = attr_desc.copy() # Do a copy, do not change the real one + internal_data_type = attr_desc["type"].strip("[]{}") + if internal_data_type in self.dependencies: + attr_desc["internalType"] = self.dependencies[internal_data_type] + + for key_extractor in self.key_extractors: + found_value = key_extractor(attr, attr_desc, data) + if found_value is not None: + if raw_value is not None and raw_value != found_value: + msg = ( + "Ignoring extracted value '%s' from %s for key '%s'" + " (duplicate extraction, follow extractors order)" + ) + _LOGGER.warning(msg, found_value, key_extractor, attr) + continue + raw_value = found_value + + value = self.deserialize_data(raw_value, attr_desc["type"]) + d_attrs[attr] = value + except (AttributeError, TypeError, KeyError) as err: + msg = "Unable to deserialize to object: " + class_name # type: ignore + raise DeserializationError(msg) from err + additional_properties = self._build_additional_properties(attributes, data) + return self._instantiate_model(response, d_attrs, additional_properties) + + def _build_additional_properties(self, attribute_map, data): + if not self.additional_properties_detection: + return None + if "additional_properties" in attribute_map and attribute_map.get("additional_properties", {}).get("key") != "": + # Check empty string. If it's not empty, someone has a real "additionalProperties" + return None + if isinstance(data, ET.Element): + data = {el.tag: el.text for el in data} + + known_keys = { + _decode_attribute_map_key(_FLATTEN.split(desc["key"])[0]) + for desc in attribute_map.values() + if desc["key"] != "" + } + present_keys = set(data.keys()) + missing_keys = present_keys - known_keys + return {key: data[key] for key in missing_keys} + + def _classify_target(self, target, data): + """Check to see whether the deserialization target object can + be classified into a subclass. + Once classification has been determined, initialize object. + + :param str target: The target object type to deserialize to. + :param str/dict data: The response data to deserialize. + :return: The classified target object and its class name. + :rtype: tuple + """ + if target is None: + return None, None + + if isinstance(target, str): + try: + target = self.dependencies[target] + except KeyError: + return target, target + + try: + target = target._classify(data, self.dependencies) # type: ignore # pylint: disable=protected-access + except AttributeError: + pass # Target is not a Model, no classify + return target, target.__class__.__name__ # type: ignore + + def failsafe_deserialize(self, target_obj, data, content_type=None): + """Ignores any errors encountered in deserialization, + and falls back to not deserializing the object. Recommended + for use in error deserialization, as we want to return the + HttpResponseError to users, and not have them deal with + a deserialization error. + + :param str target_obj: The target object type to deserialize to. + :param str/dict data: The response data to deserialize. + :param str content_type: Swagger "produces" if available. + :return: Deserialized object. + :rtype: object + """ + try: + return self(target_obj, data, content_type=content_type) + except: # pylint: disable=bare-except + _LOGGER.debug( + "Ran into a deserialization error. Ignoring since this is failsafe deserialization", exc_info=True + ) + return None + + @staticmethod + def _unpack_content(raw_data, content_type=None): + """Extract the correct structure for deserialization. + + If raw_data is a PipelineResponse, try to extract the result of RawDeserializer. + if we can't, raise. Your Pipeline should have a RawDeserializer. + + If not a pipeline response and raw_data is bytes or string, use content-type + to decode it. If no content-type, try JSON. + + If raw_data is something else, bypass all logic and return it directly. + + :param obj raw_data: Data to be processed. + :param str content_type: How to parse if raw_data is a string/bytes. + :raises JSONDecodeError: If JSON is requested and parsing is impossible. + :raises UnicodeDecodeError: If bytes is not UTF8 + :rtype: object + :return: Unpacked content. + """ + # Assume this is enough to detect a Pipeline Response without importing it + context = getattr(raw_data, "context", {}) + if context: + if RawDeserializer.CONTEXT_NAME in context: + return context[RawDeserializer.CONTEXT_NAME] + raise ValueError("This pipeline didn't have the RawDeserializer policy; can't deserialize") + + # Assume this is enough to recognize universal_http.ClientResponse without importing it + if hasattr(raw_data, "body"): + return RawDeserializer.deserialize_from_http_generics(raw_data.text(), raw_data.headers) + + # Assume this enough to recognize requests.Response without importing it. + if hasattr(raw_data, "_content_consumed"): + return RawDeserializer.deserialize_from_http_generics(raw_data.text, raw_data.headers) + + if isinstance(raw_data, (str, bytes)) or hasattr(raw_data, "read"): + return RawDeserializer.deserialize_from_text(raw_data, content_type) # type: ignore + return raw_data + + def _instantiate_model(self, response, attrs, additional_properties=None): + """Instantiate a response model passing in deserialized args. + + :param Response response: The response model class. + :param dict attrs: The deserialized response attributes. + :param dict additional_properties: Additional properties to be set. + :rtype: Response + :return: The instantiated response model. + """ + if callable(response): + subtype = getattr(response, "_subtype_map", {}) + try: + readonly = [ + k + for k, v in response._validation.items() # pylint: disable=protected-access # type: ignore + if v.get("readonly") + ] + const = [ + k + for k, v in response._validation.items() # pylint: disable=protected-access # type: ignore + if v.get("constant") + ] + kwargs = {k: v for k, v in attrs.items() if k not in subtype and k not in readonly + const} + response_obj = response(**kwargs) + for attr in readonly: + setattr(response_obj, attr, attrs.get(attr)) + if additional_properties: + response_obj.additional_properties = additional_properties # type: ignore + return response_obj + except TypeError as err: + msg = "Unable to deserialize {} into model {}. ".format(kwargs, response) # type: ignore + raise DeserializationError(msg + str(err)) from err + else: + try: + for attr, value in attrs.items(): + setattr(response, attr, value) + return response + except Exception as exp: + msg = "Unable to populate response model. " + msg += "Type: {}, Error: {}".format(type(response), exp) + raise DeserializationError(msg) from exp + + def deserialize_data(self, data, data_type): # pylint: disable=too-many-return-statements + """Process data for deserialization according to data type. + + :param str data: The response string to be deserialized. + :param str data_type: The type to deserialize to. + :raises DeserializationError: if deserialization fails. + :return: Deserialized object. + :rtype: object + """ + if data is None: + return data + + try: + if not data_type: + return data + if data_type in self.basic_types.values(): + return self.deserialize_basic(data, data_type) + if data_type in self.deserialize_type: + if isinstance(data, self.deserialize_expected_types.get(data_type, tuple())): + return data + + is_a_text_parsing_type = lambda x: x not in [ # pylint: disable=unnecessary-lambda-assignment + "object", + "[]", + r"{}", + ] + if isinstance(data, ET.Element) and is_a_text_parsing_type(data_type) and not data.text: + return None + data_val = self.deserialize_type[data_type](data) + return data_val + + iter_type = data_type[0] + data_type[-1] + if iter_type in self.deserialize_type: + return self.deserialize_type[iter_type](data, data_type[1:-1]) + + obj_type = self.dependencies[data_type] + if issubclass(obj_type, Enum): + if isinstance(data, ET.Element): + data = data.text + return self.deserialize_enum(data, obj_type) + + except (ValueError, TypeError, AttributeError) as err: + msg = "Unable to deserialize response data." + msg += " Data: {}, {}".format(data, data_type) + raise DeserializationError(msg) from err + return self._deserialize(obj_type, data) + + def deserialize_iter(self, attr, iter_type): + """Deserialize an iterable. + + :param list attr: Iterable to be deserialized. + :param str iter_type: The type of object in the iterable. + :return: Deserialized iterable. + :rtype: list + """ + if attr is None: + return None + if isinstance(attr, ET.Element): # If I receive an element here, get the children + attr = list(attr) + if not isinstance(attr, (list, set)): + raise DeserializationError("Cannot deserialize as [{}] an object of type {}".format(iter_type, type(attr))) + return [self.deserialize_data(a, iter_type) for a in attr] + + def deserialize_dict(self, attr, dict_type): + """Deserialize a dictionary. + + :param dict/list attr: Dictionary to be deserialized. Also accepts + a list of key, value pairs. + :param str dict_type: The object type of the items in the dictionary. + :return: Deserialized dictionary. + :rtype: dict + """ + if isinstance(attr, list): + return {x["key"]: self.deserialize_data(x["value"], dict_type) for x in attr} + + if isinstance(attr, ET.Element): + # Transform value into {"Key": "value"} + attr = {el.tag: el.text for el in attr} + return {k: self.deserialize_data(v, dict_type) for k, v in attr.items()} + + def deserialize_object(self, attr, **kwargs): # pylint: disable=too-many-return-statements + """Deserialize a generic object. + This will be handled as a dictionary. + + :param dict attr: Dictionary to be deserialized. + :return: Deserialized object. + :rtype: dict + :raises TypeError: if non-builtin datatype encountered. + """ + if attr is None: + return None + if isinstance(attr, ET.Element): + # Do no recurse on XML, just return the tree as-is + return attr + if isinstance(attr, str): + return self.deserialize_basic(attr, "str") + obj_type = type(attr) + if obj_type in self.basic_types: + return self.deserialize_basic(attr, self.basic_types[obj_type]) + if obj_type is _long_type: + return self.deserialize_long(attr) + + if obj_type == dict: + deserialized = {} + for key, value in attr.items(): + try: + deserialized[key] = self.deserialize_object(value, **kwargs) + except ValueError: + deserialized[key] = None + return deserialized + + if obj_type == list: + deserialized = [] + for obj in attr: + try: + deserialized.append(self.deserialize_object(obj, **kwargs)) + except ValueError: + pass + return deserialized + + error = "Cannot deserialize generic object with type: " + raise TypeError(error + str(obj_type)) + + def deserialize_basic(self, attr, data_type): # pylint: disable=too-many-return-statements + """Deserialize basic builtin data type from string. + Will attempt to convert to str, int, float and bool. + This function will also accept '1', '0', 'true' and 'false' as + valid bool values. + + :param str attr: response string to be deserialized. + :param str data_type: deserialization data type. + :return: Deserialized basic type. + :rtype: str, int, float or bool + :raises TypeError: if string format is not valid. + """ + # If we're here, data is supposed to be a basic type. + # If it's still an XML node, take the text + if isinstance(attr, ET.Element): + attr = attr.text + if not attr: + if data_type == "str": + # None or '', node is empty string. + return "" + # None or '', node with a strong type is None. + # Don't try to model "empty bool" or "empty int" + return None + + if data_type == "bool": + if attr in [True, False, 1, 0]: + return bool(attr) + if isinstance(attr, str): + if attr.lower() in ["true", "1"]: + return True + if attr.lower() in ["false", "0"]: + return False + raise TypeError("Invalid boolean value: {}".format(attr)) + + if data_type == "str": + return self.deserialize_unicode(attr) + return eval(data_type)(attr) # nosec # pylint: disable=eval-used + + @staticmethod + def deserialize_unicode(data): + """Preserve unicode objects in Python 2, otherwise return data + as a string. + + :param str data: response string to be deserialized. + :return: Deserialized string. + :rtype: str or unicode + """ + # We might be here because we have an enum modeled as string, + # and we try to deserialize a partial dict with enum inside + if isinstance(data, Enum): + return data + + # Consider this is real string + try: + if isinstance(data, unicode): # type: ignore + return data + except NameError: + return str(data) + return str(data) + + @staticmethod + def deserialize_enum(data, enum_obj): + """Deserialize string into enum object. + + If the string is not a valid enum value it will be returned as-is + and a warning will be logged. + + :param str data: Response string to be deserialized. If this value is + None or invalid it will be returned as-is. + :param Enum enum_obj: Enum object to deserialize to. + :return: Deserialized enum object. + :rtype: Enum + """ + if isinstance(data, enum_obj) or data is None: + return data + if isinstance(data, Enum): + data = data.value + if isinstance(data, int): + # Workaround. We might consider remove it in the future. + try: + return list(enum_obj.__members__.values())[data] + except IndexError as exc: + error = "{!r} is not a valid index for enum {!r}" + raise DeserializationError(error.format(data, enum_obj)) from exc + try: + return enum_obj(str(data)) + except ValueError: + for enum_value in enum_obj: + if enum_value.value.lower() == str(data).lower(): + return enum_value + # We don't fail anymore for unknown value, we deserialize as a string + _LOGGER.warning("Deserializer is not able to find %s as valid enum in %s", data, enum_obj) + return Deserializer.deserialize_unicode(data) + + @staticmethod + def deserialize_bytearray(attr): + """Deserialize string into bytearray. + + :param str attr: response string to be deserialized. + :return: Deserialized bytearray + :rtype: bytearray + :raises TypeError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + return bytearray(b64decode(attr)) # type: ignore + + @staticmethod + def deserialize_base64(attr): + """Deserialize base64 encoded string into string. + + :param str attr: response string to be deserialized. + :return: Deserialized base64 string + :rtype: bytearray + :raises TypeError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + padding = "=" * (3 - (len(attr) + 3) % 4) # type: ignore + attr = attr + padding # type: ignore + encoded = attr.replace("-", "+").replace("_", "/") + return b64decode(encoded) + + @staticmethod + def deserialize_decimal(attr): + """Deserialize string into Decimal object. + + :param str attr: response string to be deserialized. + :return: Deserialized decimal + :raises DeserializationError: if string format invalid. + :rtype: decimal + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + return decimal.Decimal(str(attr)) # type: ignore + except decimal.DecimalException as err: + msg = "Invalid decimal {}".format(attr) + raise DeserializationError(msg) from err + + @staticmethod + def deserialize_long(attr): + """Deserialize string into long (Py2) or int (Py3). + + :param str attr: response string to be deserialized. + :return: Deserialized int + :rtype: long or int + :raises ValueError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + return _long_type(attr) # type: ignore + + @staticmethod + def deserialize_duration(attr): + """Deserialize ISO-8601 formatted string into TimeDelta object. + + :param str attr: response string to be deserialized. + :return: Deserialized duration + :rtype: TimeDelta + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + duration = isodate.parse_duration(attr) + except (ValueError, OverflowError, AttributeError) as err: + msg = "Cannot deserialize duration object." + raise DeserializationError(msg) from err + return duration + + @staticmethod + def deserialize_date(attr): + """Deserialize ISO-8601 formatted string into Date object. + + :param str attr: response string to be deserialized. + :return: Deserialized date + :rtype: Date + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + if re.search(r"[^\W\d_]", attr, re.I + re.U): # type: ignore + raise DeserializationError("Date must have only digits and -. Received: %s" % attr) + # This must NOT use defaultmonth/defaultday. Using None ensure this raises an exception. + return isodate.parse_date(attr, defaultmonth=0, defaultday=0) + + @staticmethod + def deserialize_time(attr): + """Deserialize ISO-8601 formatted string into time object. + + :param str attr: response string to be deserialized. + :return: Deserialized time + :rtype: datetime.time + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + if re.search(r"[^\W\d_]", attr, re.I + re.U): # type: ignore + raise DeserializationError("Date must have only digits and -. Received: %s" % attr) + return isodate.parse_time(attr) + + @staticmethod + def deserialize_rfc(attr): + """Deserialize RFC-1123 formatted string into Datetime object. + + :param str attr: response string to be deserialized. + :return: Deserialized RFC datetime + :rtype: Datetime + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + parsed_date = email.utils.parsedate_tz(attr) # type: ignore + date_obj = datetime.datetime( + *parsed_date[:6], tzinfo=datetime.timezone(datetime.timedelta(minutes=(parsed_date[9] or 0) / 60)) + ) + if not date_obj.tzinfo: + date_obj = date_obj.astimezone(tz=TZ_UTC) + except ValueError as err: + msg = "Cannot deserialize to rfc datetime object." + raise DeserializationError(msg) from err + return date_obj + + @staticmethod + def deserialize_iso(attr): + """Deserialize ISO-8601 formatted string into Datetime object. + + :param str attr: response string to be deserialized. + :return: Deserialized ISO datetime + :rtype: Datetime + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + attr = attr.upper() # type: ignore + match = Deserializer.valid_date.match(attr) + if not match: + raise ValueError("Invalid datetime string: " + attr) + + check_decimal = attr.split(".") + if len(check_decimal) > 1: + decimal_str = "" + for digit in check_decimal[1]: + if digit.isdigit(): + decimal_str += digit + else: + break + if len(decimal_str) > 6: + attr = attr.replace(decimal_str, decimal_str[0:6]) + + date_obj = isodate.parse_datetime(attr) + test_utc = date_obj.utctimetuple() + if test_utc.tm_year > 9999 or test_utc.tm_year < 1: + raise OverflowError("Hit max or min date") + except (ValueError, OverflowError, AttributeError) as err: + msg = "Cannot deserialize datetime object." + raise DeserializationError(msg) from err + return date_obj + + @staticmethod + def deserialize_unix(attr): + """Serialize Datetime object into IntTime format. + This is represented as seconds. + + :param int attr: Object to be serialized. + :return: Deserialized datetime + :rtype: Datetime + :raises DeserializationError: if format invalid + """ + if isinstance(attr, ET.Element): + attr = int(attr.text) # type: ignore + try: + attr = int(attr) + date_obj = datetime.datetime.fromtimestamp(attr, TZ_UTC) + except ValueError as err: + msg = "Cannot deserialize to unix datetime object." + raise DeserializationError(msg) from err + return date_obj diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/RequiredOptionalVersionTolerant/requiredoptionalversiontolerant/aio/_client.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/RequiredOptionalVersionTolerant/requiredoptionalversiontolerant/aio/_client.py index 986bfad56fb..5a821bcb88b 100644 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/RequiredOptionalVersionTolerant/requiredoptionalversiontolerant/aio/_client.py +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/RequiredOptionalVersionTolerant/requiredoptionalversiontolerant/aio/_client.py @@ -14,7 +14,7 @@ from azure.core.pipeline import policies from azure.core.rest import AsyncHttpResponse, HttpRequest -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import AutoRestRequiredOptionalTestServiceConfiguration from .operations import ExplicitOperations, ImplicitOperations diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/RequiredOptionalVersionTolerant/requiredoptionalversiontolerant/aio/operations/_operations.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/RequiredOptionalVersionTolerant/requiredoptionalversiontolerant/aio/operations/_operations.py index 66c6a66330a..decb4f3df69 100644 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/RequiredOptionalVersionTolerant/requiredoptionalversiontolerant/aio/operations/_operations.py +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/RequiredOptionalVersionTolerant/requiredoptionalversiontolerant/aio/operations/_operations.py @@ -24,7 +24,7 @@ from azure.core.tracing.decorator_async import distributed_trace_async from azure.core.utils import case_insensitive_dict -from ..._serialization import Deserializer, Serializer +from ..._utils.serialization import Deserializer, Serializer from ...operations._operations import ( build_explicit_post_optional_array_header_request, build_explicit_post_optional_array_parameter_request, diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/RequiredOptionalVersionTolerant/requiredoptionalversiontolerant/operations/_operations.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/RequiredOptionalVersionTolerant/requiredoptionalversiontolerant/operations/_operations.py index 6ae42e7b08c..eef0eeb1e03 100644 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/RequiredOptionalVersionTolerant/requiredoptionalversiontolerant/operations/_operations.py +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/RequiredOptionalVersionTolerant/requiredoptionalversiontolerant/operations/_operations.py @@ -25,7 +25,7 @@ from azure.core.utils import case_insensitive_dict from .._configuration import AutoRestRequiredOptionalTestServiceConfiguration -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ReservedWordsVersionTolerant/reservedwordsversiontolerant/_client.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ReservedWordsVersionTolerant/reservedwordsversiontolerant/_client.py index fd5e420e426..b504e70e4df 100644 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ReservedWordsVersionTolerant/reservedwordsversiontolerant/_client.py +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ReservedWordsVersionTolerant/reservedwordsversiontolerant/_client.py @@ -15,7 +15,7 @@ from azure.core.rest import HttpRequest, HttpResponse from ._configuration import ReservedWordsClientConfiguration -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer from .operations import ImportOperations, ReservedWordsClientOperationsMixin diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ReservedWordsVersionTolerant/reservedwordsversiontolerant/_utils/__init__.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ReservedWordsVersionTolerant/reservedwordsversiontolerant/_utils/__init__.py new file mode 100644 index 00000000000..0af9b28f660 --- /dev/null +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ReservedWordsVersionTolerant/reservedwordsversiontolerant/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ReservedWordsVersionTolerant/reservedwordsversiontolerant/_utils/serialization.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ReservedWordsVersionTolerant/reservedwordsversiontolerant/_utils/serialization.py new file mode 100644 index 00000000000..f5187701d7b --- /dev/null +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ReservedWordsVersionTolerant/reservedwordsversiontolerant/_utils/serialization.py @@ -0,0 +1,2032 @@ +# pylint: disable=line-too-long,useless-suppression,too-many-lines +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +# pyright: reportUnnecessaryTypeIgnoreComment=false + +from base64 import b64decode, b64encode +import calendar +import datetime +import decimal +import email +from enum import Enum +import json +import logging +import re +import sys +import codecs +from typing import ( + Dict, + Any, + cast, + Optional, + Union, + AnyStr, + IO, + Mapping, + Callable, + MutableMapping, + List, +) + +try: + from urllib import quote # type: ignore +except ImportError: + from urllib.parse import quote +import xml.etree.ElementTree as ET + +import isodate # type: ignore +from typing_extensions import Self + +from azure.core.exceptions import DeserializationError, SerializationError +from azure.core.serialization import NULL as CoreNull + +_BOM = codecs.BOM_UTF8.decode(encoding="utf-8") + +JSON = MutableMapping[str, Any] + + +class RawDeserializer: + + # Accept "text" because we're open minded people... + JSON_REGEXP = re.compile(r"^(application|text)/([a-z+.]+\+)?json$") + + # Name used in context + CONTEXT_NAME = "deserialized_data" + + @classmethod + def deserialize_from_text(cls, data: Optional[Union[AnyStr, IO]], content_type: Optional[str] = None) -> Any: + """Decode data according to content-type. + + Accept a stream of data as well, but will be load at once in memory for now. + + If no content-type, will return the string version (not bytes, not stream) + + :param data: Input, could be bytes or stream (will be decoded with UTF8) or text + :type data: str or bytes or IO + :param str content_type: The content type. + :return: The deserialized data. + :rtype: object + """ + if hasattr(data, "read"): + # Assume a stream + data = cast(IO, data).read() + + if isinstance(data, bytes): + data_as_str = data.decode(encoding="utf-8-sig") + else: + # Explain to mypy the correct type. + data_as_str = cast(str, data) + + # Remove Byte Order Mark if present in string + data_as_str = data_as_str.lstrip(_BOM) + + if content_type is None: + return data + + if cls.JSON_REGEXP.match(content_type): + try: + return json.loads(data_as_str) + except ValueError as err: + raise DeserializationError("JSON is invalid: {}".format(err), err) from err + elif "xml" in (content_type or []): + try: + + try: + if isinstance(data, unicode): # type: ignore + # If I'm Python 2.7 and unicode XML will scream if I try a "fromstring" on unicode string + data_as_str = data_as_str.encode(encoding="utf-8") # type: ignore + except NameError: + pass + + return ET.fromstring(data_as_str) # nosec + except ET.ParseError as err: + # It might be because the server has an issue, and returned JSON with + # content-type XML.... + # So let's try a JSON load, and if it's still broken + # let's flow the initial exception + def _json_attemp(data): + try: + return True, json.loads(data) + except ValueError: + return False, None # Don't care about this one + + success, json_result = _json_attemp(data) + if success: + return json_result + # If i'm here, it's not JSON, it's not XML, let's scream + # and raise the last context in this block (the XML exception) + # The function hack is because Py2.7 messes up with exception + # context otherwise. + _LOGGER.critical("Wasn't XML not JSON, failing") + raise DeserializationError("XML is invalid") from err + elif content_type.startswith("text/"): + return data_as_str + raise DeserializationError("Cannot deserialize content-type: {}".format(content_type)) + + @classmethod + def deserialize_from_http_generics(cls, body_bytes: Optional[Union[AnyStr, IO]], headers: Mapping) -> Any: + """Deserialize from HTTP response. + + Use bytes and headers to NOT use any requests/aiohttp or whatever + specific implementation. + Headers will tested for "content-type" + + :param bytes body_bytes: The body of the response. + :param dict headers: The headers of the response. + :returns: The deserialized data. + :rtype: object + """ + # Try to use content-type from headers if available + content_type = None + if "content-type" in headers: + content_type = headers["content-type"].split(";")[0].strip().lower() + # Ouch, this server did not declare what it sent... + # Let's guess it's JSON... + # Also, since Autorest was considering that an empty body was a valid JSON, + # need that test as well.... + else: + content_type = "application/json" + + if body_bytes: + return cls.deserialize_from_text(body_bytes, content_type) + return None + + +_LOGGER = logging.getLogger(__name__) + +try: + _long_type = long # type: ignore +except NameError: + _long_type = int + +TZ_UTC = datetime.timezone.utc + +_FLATTEN = re.compile(r"(? None: + self.additional_properties: Optional[Dict[str, Any]] = {} + for k in kwargs: # pylint: disable=consider-using-dict-items + if k not in self._attribute_map: + _LOGGER.warning("%s is not a known attribute of class %s and will be ignored", k, self.__class__) + elif k in self._validation and self._validation[k].get("readonly", False): + _LOGGER.warning("Readonly attribute %s will be ignored in class %s", k, self.__class__) + else: + setattr(self, k, kwargs[k]) + + def __eq__(self, other: Any) -> bool: + """Compare objects by comparing all attributes. + + :param object other: The object to compare + :returns: True if objects are equal + :rtype: bool + """ + if isinstance(other, self.__class__): + return self.__dict__ == other.__dict__ + return False + + def __ne__(self, other: Any) -> bool: + """Compare objects by comparing all attributes. + + :param object other: The object to compare + :returns: True if objects are not equal + :rtype: bool + """ + return not self.__eq__(other) + + def __str__(self) -> str: + return str(self.__dict__) + + @classmethod + def enable_additional_properties_sending(cls) -> None: + cls._attribute_map["additional_properties"] = {"key": "", "type": "{object}"} + + @classmethod + def is_xml_model(cls) -> bool: + try: + cls._xml_map # type: ignore + except AttributeError: + return False + return True + + @classmethod + def _create_xml_node(cls): + """Create XML node. + + :returns: The XML node + :rtype: xml.etree.ElementTree.Element + """ + try: + xml_map = cls._xml_map # type: ignore + except AttributeError: + xml_map = {} + + return _create_xml_node(xml_map.get("name", cls.__name__), xml_map.get("prefix", None), xml_map.get("ns", None)) + + def serialize(self, keep_readonly: bool = False, **kwargs: Any) -> JSON: + """Return the JSON that would be sent to server from this model. + + This is an alias to `as_dict(full_restapi_key_transformer, keep_readonly=False)`. + + If you want XML serialization, you can pass the kwargs is_xml=True. + + :param bool keep_readonly: If you want to serialize the readonly attributes + :returns: A dict JSON compatible object + :rtype: dict + """ + serializer = Serializer(self._infer_class_models()) + return serializer._serialize( # type: ignore # pylint: disable=protected-access + self, keep_readonly=keep_readonly, **kwargs + ) + + def as_dict( + self, + keep_readonly: bool = True, + key_transformer: Callable[[str, Dict[str, Any], Any], Any] = attribute_transformer, + **kwargs: Any + ) -> JSON: + """Return a dict that can be serialized using json.dump. + + Advanced usage might optionally use a callback as parameter: + + .. code::python + + def my_key_transformer(key, attr_desc, value): + return key + + Key is the attribute name used in Python. Attr_desc + is a dict of metadata. Currently contains 'type' with the + msrest type and 'key' with the RestAPI encoded key. + Value is the current value in this object. + + The string returned will be used to serialize the key. + If the return type is a list, this is considered hierarchical + result dict. + + See the three examples in this file: + + - attribute_transformer + - full_restapi_key_transformer + - last_restapi_key_transformer + + If you want XML serialization, you can pass the kwargs is_xml=True. + + :param bool keep_readonly: If you want to serialize the readonly attributes + :param function key_transformer: A key transformer function. + :returns: A dict JSON compatible object + :rtype: dict + """ + serializer = Serializer(self._infer_class_models()) + return serializer._serialize( # type: ignore # pylint: disable=protected-access + self, key_transformer=key_transformer, keep_readonly=keep_readonly, **kwargs + ) + + @classmethod + def _infer_class_models(cls): + try: + str_models = cls.__module__.rsplit(".", 1)[0] + models = sys.modules[str_models] + client_models = {k: v for k, v in models.__dict__.items() if isinstance(v, type)} + if cls.__name__ not in client_models: + raise ValueError("Not Autorest generated code") + except Exception: # pylint: disable=broad-exception-caught + # Assume it's not Autorest generated (tests?). Add ourselves as dependencies. + client_models = {cls.__name__: cls} + return client_models + + @classmethod + def deserialize(cls, data: Any, content_type: Optional[str] = None) -> Self: + """Parse a str using the RestAPI syntax and return a model. + + :param str data: A str using RestAPI structure. JSON by default. + :param str content_type: JSON by default, set application/xml if XML. + :returns: An instance of this model + :raises DeserializationError: if something went wrong + :rtype: Self + """ + deserializer = Deserializer(cls._infer_class_models()) + return deserializer(cls.__name__, data, content_type=content_type) # type: ignore + + @classmethod + def from_dict( + cls, + data: Any, + key_extractors: Optional[Callable[[str, Dict[str, Any], Any], Any]] = None, + content_type: Optional[str] = None, + ) -> Self: + """Parse a dict using given key extractor return a model. + + By default consider key + extractors (rest_key_case_insensitive_extractor, attribute_key_case_insensitive_extractor + and last_rest_key_case_insensitive_extractor) + + :param dict data: A dict using RestAPI structure + :param function key_extractors: A key extractor function. + :param str content_type: JSON by default, set application/xml if XML. + :returns: An instance of this model + :raises DeserializationError: if something went wrong + :rtype: Self + """ + deserializer = Deserializer(cls._infer_class_models()) + deserializer.key_extractors = ( # type: ignore + [ # type: ignore + attribute_key_case_insensitive_extractor, + rest_key_case_insensitive_extractor, + last_rest_key_case_insensitive_extractor, + ] + if key_extractors is None + else key_extractors + ) + return deserializer(cls.__name__, data, content_type=content_type) # type: ignore + + @classmethod + def _flatten_subtype(cls, key, objects): + if "_subtype_map" not in cls.__dict__: + return {} + result = dict(cls._subtype_map[key]) + for valuetype in cls._subtype_map[key].values(): + result.update(objects[valuetype]._flatten_subtype(key, objects)) # pylint: disable=protected-access + return result + + @classmethod + def _classify(cls, response, objects): + """Check the class _subtype_map for any child classes. + We want to ignore any inherited _subtype_maps. + + :param dict response: The initial data + :param dict objects: The class objects + :returns: The class to be used + :rtype: class + """ + for subtype_key in cls.__dict__.get("_subtype_map", {}).keys(): + subtype_value = None + + if not isinstance(response, ET.Element): + rest_api_response_key = cls._get_rest_key_parts(subtype_key)[-1] + subtype_value = response.get(rest_api_response_key, None) or response.get(subtype_key, None) + else: + subtype_value = xml_key_extractor(subtype_key, cls._attribute_map[subtype_key], response) + if subtype_value: + # Try to match base class. Can be class name only + # (bug to fix in Autorest to support x-ms-discriminator-name) + if cls.__name__ == subtype_value: + return cls + flatten_mapping_type = cls._flatten_subtype(subtype_key, objects) + try: + return objects[flatten_mapping_type[subtype_value]] # type: ignore + except KeyError: + _LOGGER.warning( + "Subtype value %s has no mapping, use base class %s.", + subtype_value, + cls.__name__, + ) + break + else: + _LOGGER.warning("Discriminator %s is absent or null, use base class %s.", subtype_key, cls.__name__) + break + return cls + + @classmethod + def _get_rest_key_parts(cls, attr_key): + """Get the RestAPI key of this attr, split it and decode part + :param str attr_key: Attribute key must be in attribute_map. + :returns: A list of RestAPI part + :rtype: list + """ + rest_split_key = _FLATTEN.split(cls._attribute_map[attr_key]["key"]) + return [_decode_attribute_map_key(key_part) for key_part in rest_split_key] + + +def _decode_attribute_map_key(key): + """This decode a key in an _attribute_map to the actual key we want to look at + inside the received data. + + :param str key: A key string from the generated code + :returns: The decoded key + :rtype: str + """ + return key.replace("\\.", ".") + + +class Serializer: # pylint: disable=too-many-public-methods + """Request object model serializer.""" + + basic_types = {str: "str", int: "int", bool: "bool", float: "float"} + + _xml_basic_types_serializers = {"bool": lambda x: str(x).lower()} + days = {0: "Mon", 1: "Tue", 2: "Wed", 3: "Thu", 4: "Fri", 5: "Sat", 6: "Sun"} + months = { + 1: "Jan", + 2: "Feb", + 3: "Mar", + 4: "Apr", + 5: "May", + 6: "Jun", + 7: "Jul", + 8: "Aug", + 9: "Sep", + 10: "Oct", + 11: "Nov", + 12: "Dec", + } + validation = { + "min_length": lambda x, y: len(x) < y, + "max_length": lambda x, y: len(x) > y, + "minimum": lambda x, y: x < y, + "maximum": lambda x, y: x > y, + "minimum_ex": lambda x, y: x <= y, + "maximum_ex": lambda x, y: x >= y, + "min_items": lambda x, y: len(x) < y, + "max_items": lambda x, y: len(x) > y, + "pattern": lambda x, y: not re.match(y, x, re.UNICODE), + "unique": lambda x, y: len(x) != len(set(x)), + "multiple": lambda x, y: x % y != 0, + } + + def __init__(self, classes: Optional[Mapping[str, type]] = None) -> None: + self.serialize_type = { + "iso-8601": Serializer.serialize_iso, + "rfc-1123": Serializer.serialize_rfc, + "unix-time": Serializer.serialize_unix, + "duration": Serializer.serialize_duration, + "date": Serializer.serialize_date, + "time": Serializer.serialize_time, + "decimal": Serializer.serialize_decimal, + "long": Serializer.serialize_long, + "bytearray": Serializer.serialize_bytearray, + "base64": Serializer.serialize_base64, + "object": self.serialize_object, + "[]": self.serialize_iter, + "{}": self.serialize_dict, + } + self.dependencies: Dict[str, type] = dict(classes) if classes else {} + self.key_transformer = full_restapi_key_transformer + self.client_side_validation = True + + def _serialize( # pylint: disable=too-many-nested-blocks, too-many-branches, too-many-statements, too-many-locals + self, target_obj, data_type=None, **kwargs + ): + """Serialize data into a string according to type. + + :param object target_obj: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str, dict + :raises SerializationError: if serialization fails. + :returns: The serialized data. + """ + key_transformer = kwargs.get("key_transformer", self.key_transformer) + keep_readonly = kwargs.get("keep_readonly", False) + if target_obj is None: + return None + + attr_name = None + class_name = target_obj.__class__.__name__ + + if data_type: + return self.serialize_data(target_obj, data_type, **kwargs) + + if not hasattr(target_obj, "_attribute_map"): + data_type = type(target_obj).__name__ + if data_type in self.basic_types.values(): + return self.serialize_data(target_obj, data_type, **kwargs) + + # Force "is_xml" kwargs if we detect a XML model + try: + is_xml_model_serialization = kwargs["is_xml"] + except KeyError: + is_xml_model_serialization = kwargs.setdefault("is_xml", target_obj.is_xml_model()) + + serialized = {} + if is_xml_model_serialization: + serialized = target_obj._create_xml_node() # pylint: disable=protected-access + try: + attributes = target_obj._attribute_map # pylint: disable=protected-access + for attr, attr_desc in attributes.items(): + attr_name = attr + if not keep_readonly and target_obj._validation.get( # pylint: disable=protected-access + attr_name, {} + ).get("readonly", False): + continue + + if attr_name == "additional_properties" and attr_desc["key"] == "": + if target_obj.additional_properties is not None: + serialized.update(target_obj.additional_properties) + continue + try: + + orig_attr = getattr(target_obj, attr) + if is_xml_model_serialization: + pass # Don't provide "transformer" for XML for now. Keep "orig_attr" + else: # JSON + keys, orig_attr = key_transformer(attr, attr_desc.copy(), orig_attr) + keys = keys if isinstance(keys, list) else [keys] + + kwargs["serialization_ctxt"] = attr_desc + new_attr = self.serialize_data(orig_attr, attr_desc["type"], **kwargs) + + if is_xml_model_serialization: + xml_desc = attr_desc.get("xml", {}) + xml_name = xml_desc.get("name", attr_desc["key"]) + xml_prefix = xml_desc.get("prefix", None) + xml_ns = xml_desc.get("ns", None) + if xml_desc.get("attr", False): + if xml_ns: + ET.register_namespace(xml_prefix, xml_ns) + xml_name = "{{{}}}{}".format(xml_ns, xml_name) + serialized.set(xml_name, new_attr) # type: ignore + continue + if xml_desc.get("text", False): + serialized.text = new_attr # type: ignore + continue + if isinstance(new_attr, list): + serialized.extend(new_attr) # type: ignore + elif isinstance(new_attr, ET.Element): + # If the down XML has no XML/Name, + # we MUST replace the tag with the local tag. But keeping the namespaces. + if "name" not in getattr(orig_attr, "_xml_map", {}): + splitted_tag = new_attr.tag.split("}") + if len(splitted_tag) == 2: # Namespace + new_attr.tag = "}".join([splitted_tag[0], xml_name]) + else: + new_attr.tag = xml_name + serialized.append(new_attr) # type: ignore + else: # That's a basic type + # Integrate namespace if necessary + local_node = _create_xml_node(xml_name, xml_prefix, xml_ns) + local_node.text = str(new_attr) + serialized.append(local_node) # type: ignore + else: # JSON + for k in reversed(keys): # type: ignore + new_attr = {k: new_attr} + + _new_attr = new_attr + _serialized = serialized + for k in keys: # type: ignore + if k not in _serialized: + _serialized.update(_new_attr) # type: ignore + _new_attr = _new_attr[k] # type: ignore + _serialized = _serialized[k] + except ValueError as err: + if isinstance(err, SerializationError): + raise + + except (AttributeError, KeyError, TypeError) as err: + msg = "Attribute {} in object {} cannot be serialized.\n{}".format(attr_name, class_name, str(target_obj)) + raise SerializationError(msg) from err + return serialized + + def body(self, data, data_type, **kwargs): + """Serialize data intended for a request body. + + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: dict + :raises SerializationError: if serialization fails. + :raises ValueError: if data is None + :returns: The serialized request body + """ + + # Just in case this is a dict + internal_data_type_str = data_type.strip("[]{}") + internal_data_type = self.dependencies.get(internal_data_type_str, None) + try: + is_xml_model_serialization = kwargs["is_xml"] + except KeyError: + if internal_data_type and issubclass(internal_data_type, Model): + is_xml_model_serialization = kwargs.setdefault("is_xml", internal_data_type.is_xml_model()) + else: + is_xml_model_serialization = False + if internal_data_type and not isinstance(internal_data_type, Enum): + try: + deserializer = Deserializer(self.dependencies) + # Since it's on serialization, it's almost sure that format is not JSON REST + # We're not able to deal with additional properties for now. + deserializer.additional_properties_detection = False + if is_xml_model_serialization: + deserializer.key_extractors = [ # type: ignore + attribute_key_case_insensitive_extractor, + ] + else: + deserializer.key_extractors = [ + rest_key_case_insensitive_extractor, + attribute_key_case_insensitive_extractor, + last_rest_key_case_insensitive_extractor, + ] + data = deserializer._deserialize(data_type, data) # pylint: disable=protected-access + except DeserializationError as err: + raise SerializationError("Unable to build a model: " + str(err)) from err + + return self._serialize(data, data_type, **kwargs) + + def url(self, name, data, data_type, **kwargs): + """Serialize data intended for a URL path. + + :param str name: The name of the URL path parameter. + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str + :returns: The serialized URL path + :raises TypeError: if serialization fails. + :raises ValueError: if data is None + """ + try: + output = self.serialize_data(data, data_type, **kwargs) + if data_type == "bool": + output = json.dumps(output) + + if kwargs.get("skip_quote") is True: + output = str(output) + output = output.replace("{", quote("{")).replace("}", quote("}")) + else: + output = quote(str(output), safe="") + except SerializationError as exc: + raise TypeError("{} must be type {}.".format(name, data_type)) from exc + return output + + def query(self, name, data, data_type, **kwargs): + """Serialize data intended for a URL query. + + :param str name: The name of the query parameter. + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str, list + :raises TypeError: if serialization fails. + :raises ValueError: if data is None + :returns: The serialized query parameter + """ + try: + # Treat the list aside, since we don't want to encode the div separator + if data_type.startswith("["): + internal_data_type = data_type[1:-1] + do_quote = not kwargs.get("skip_quote", False) + return self.serialize_iter(data, internal_data_type, do_quote=do_quote, **kwargs) + + # Not a list, regular serialization + output = self.serialize_data(data, data_type, **kwargs) + if data_type == "bool": + output = json.dumps(output) + if kwargs.get("skip_quote") is True: + output = str(output) + else: + output = quote(str(output), safe="") + except SerializationError as exc: + raise TypeError("{} must be type {}.".format(name, data_type)) from exc + return str(output) + + def header(self, name, data, data_type, **kwargs): + """Serialize data intended for a request header. + + :param str name: The name of the header. + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str + :raises TypeError: if serialization fails. + :raises ValueError: if data is None + :returns: The serialized header + """ + try: + if data_type in ["[str]"]: + data = ["" if d is None else d for d in data] + + output = self.serialize_data(data, data_type, **kwargs) + if data_type == "bool": + output = json.dumps(output) + except SerializationError as exc: + raise TypeError("{} must be type {}.".format(name, data_type)) from exc + return str(output) + + def serialize_data(self, data, data_type, **kwargs): + """Serialize generic data according to supplied data type. + + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :raises AttributeError: if required data is None. + :raises ValueError: if data is None + :raises SerializationError: if serialization fails. + :returns: The serialized data. + :rtype: str, int, float, bool, dict, list + """ + if data is None: + raise ValueError("No value for given attribute") + + try: + if data is CoreNull: + return None + if data_type in self.basic_types.values(): + return self.serialize_basic(data, data_type, **kwargs) + + if data_type in self.serialize_type: + return self.serialize_type[data_type](data, **kwargs) + + # If dependencies is empty, try with current data class + # It has to be a subclass of Enum anyway + enum_type = self.dependencies.get(data_type, data.__class__) + if issubclass(enum_type, Enum): + return Serializer.serialize_enum(data, enum_obj=enum_type) + + iter_type = data_type[0] + data_type[-1] + if iter_type in self.serialize_type: + return self.serialize_type[iter_type](data, data_type[1:-1], **kwargs) + + except (ValueError, TypeError) as err: + msg = "Unable to serialize value: {!r} as type: {!r}." + raise SerializationError(msg.format(data, data_type)) from err + return self._serialize(data, **kwargs) + + @classmethod + def _get_custom_serializers(cls, data_type, **kwargs): # pylint: disable=inconsistent-return-statements + custom_serializer = kwargs.get("basic_types_serializers", {}).get(data_type) + if custom_serializer: + return custom_serializer + if kwargs.get("is_xml", False): + return cls._xml_basic_types_serializers.get(data_type) + + @classmethod + def serialize_basic(cls, data, data_type, **kwargs): + """Serialize basic builting data type. + Serializes objects to str, int, float or bool. + + Possible kwargs: + - basic_types_serializers dict[str, callable] : If set, use the callable as serializer + - is_xml bool : If set, use xml_basic_types_serializers + + :param obj data: Object to be serialized. + :param str data_type: Type of object in the iterable. + :rtype: str, int, float, bool + :return: serialized object + """ + custom_serializer = cls._get_custom_serializers(data_type, **kwargs) + if custom_serializer: + return custom_serializer(data) + if data_type == "str": + return cls.serialize_unicode(data) + return eval(data_type)(data) # nosec # pylint: disable=eval-used + + @classmethod + def serialize_unicode(cls, data): + """Special handling for serializing unicode strings in Py2. + Encode to UTF-8 if unicode, otherwise handle as a str. + + :param str data: Object to be serialized. + :rtype: str + :return: serialized object + """ + try: # If I received an enum, return its value + return data.value + except AttributeError: + pass + + try: + if isinstance(data, unicode): # type: ignore + # Don't change it, JSON and XML ElementTree are totally able + # to serialize correctly u'' strings + return data + except NameError: + return str(data) + return str(data) + + def serialize_iter(self, data, iter_type, div=None, **kwargs): + """Serialize iterable. + + Supported kwargs: + - serialization_ctxt dict : The current entry of _attribute_map, or same format. + serialization_ctxt['type'] should be same as data_type. + - is_xml bool : If set, serialize as XML + + :param list data: Object to be serialized. + :param str iter_type: Type of object in the iterable. + :param str div: If set, this str will be used to combine the elements + in the iterable into a combined string. Default is 'None'. + Defaults to False. + :rtype: list, str + :return: serialized iterable + """ + if isinstance(data, str): + raise SerializationError("Refuse str type as a valid iter type.") + + serialization_ctxt = kwargs.get("serialization_ctxt", {}) + is_xml = kwargs.get("is_xml", False) + + serialized = [] + for d in data: + try: + serialized.append(self.serialize_data(d, iter_type, **kwargs)) + except ValueError as err: + if isinstance(err, SerializationError): + raise + serialized.append(None) + + if kwargs.get("do_quote", False): + serialized = ["" if s is None else quote(str(s), safe="") for s in serialized] + + if div: + serialized = ["" if s is None else str(s) for s in serialized] + serialized = div.join(serialized) + + if "xml" in serialization_ctxt or is_xml: + # XML serialization is more complicated + xml_desc = serialization_ctxt.get("xml", {}) + xml_name = xml_desc.get("name") + if not xml_name: + xml_name = serialization_ctxt["key"] + + # Create a wrap node if necessary (use the fact that Element and list have "append") + is_wrapped = xml_desc.get("wrapped", False) + node_name = xml_desc.get("itemsName", xml_name) + if is_wrapped: + final_result = _create_xml_node(xml_name, xml_desc.get("prefix", None), xml_desc.get("ns", None)) + else: + final_result = [] + # All list elements to "local_node" + for el in serialized: + if isinstance(el, ET.Element): + el_node = el + else: + el_node = _create_xml_node(node_name, xml_desc.get("prefix", None), xml_desc.get("ns", None)) + if el is not None: # Otherwise it writes "None" :-p + el_node.text = str(el) + final_result.append(el_node) + return final_result + return serialized + + def serialize_dict(self, attr, dict_type, **kwargs): + """Serialize a dictionary of objects. + + :param dict attr: Object to be serialized. + :param str dict_type: Type of object in the dictionary. + :rtype: dict + :return: serialized dictionary + """ + serialization_ctxt = kwargs.get("serialization_ctxt", {}) + serialized = {} + for key, value in attr.items(): + try: + serialized[self.serialize_unicode(key)] = self.serialize_data(value, dict_type, **kwargs) + except ValueError as err: + if isinstance(err, SerializationError): + raise + serialized[self.serialize_unicode(key)] = None + + if "xml" in serialization_ctxt: + # XML serialization is more complicated + xml_desc = serialization_ctxt["xml"] + xml_name = xml_desc["name"] + + final_result = _create_xml_node(xml_name, xml_desc.get("prefix", None), xml_desc.get("ns", None)) + for key, value in serialized.items(): + ET.SubElement(final_result, key).text = value + return final_result + + return serialized + + def serialize_object(self, attr, **kwargs): # pylint: disable=too-many-return-statements + """Serialize a generic object. + This will be handled as a dictionary. If object passed in is not + a basic type (str, int, float, dict, list) it will simply be + cast to str. + + :param dict attr: Object to be serialized. + :rtype: dict or str + :return: serialized object + """ + if attr is None: + return None + if isinstance(attr, ET.Element): + return attr + obj_type = type(attr) + if obj_type in self.basic_types: + return self.serialize_basic(attr, self.basic_types[obj_type], **kwargs) + if obj_type is _long_type: + return self.serialize_long(attr) + if obj_type is str: + return self.serialize_unicode(attr) + if obj_type is datetime.datetime: + return self.serialize_iso(attr) + if obj_type is datetime.date: + return self.serialize_date(attr) + if obj_type is datetime.time: + return self.serialize_time(attr) + if obj_type is datetime.timedelta: + return self.serialize_duration(attr) + if obj_type is decimal.Decimal: + return self.serialize_decimal(attr) + + # If it's a model or I know this dependency, serialize as a Model + if obj_type in self.dependencies.values() or isinstance(attr, Model): + return self._serialize(attr) + + if obj_type == dict: + serialized = {} + for key, value in attr.items(): + try: + serialized[self.serialize_unicode(key)] = self.serialize_object(value, **kwargs) + except ValueError: + serialized[self.serialize_unicode(key)] = None + return serialized + + if obj_type == list: + serialized = [] + for obj in attr: + try: + serialized.append(self.serialize_object(obj, **kwargs)) + except ValueError: + pass + return serialized + return str(attr) + + @staticmethod + def serialize_enum(attr, enum_obj=None): + try: + result = attr.value + except AttributeError: + result = attr + try: + enum_obj(result) # type: ignore + return result + except ValueError as exc: + for enum_value in enum_obj: # type: ignore + if enum_value.value.lower() == str(attr).lower(): + return enum_value.value + error = "{!r} is not valid value for enum {!r}" + raise SerializationError(error.format(attr, enum_obj)) from exc + + @staticmethod + def serialize_bytearray(attr, **kwargs): # pylint: disable=unused-argument + """Serialize bytearray into base-64 string. + + :param str attr: Object to be serialized. + :rtype: str + :return: serialized base64 + """ + return b64encode(attr).decode() + + @staticmethod + def serialize_base64(attr, **kwargs): # pylint: disable=unused-argument + """Serialize str into base-64 string. + + :param str attr: Object to be serialized. + :rtype: str + :return: serialized base64 + """ + encoded = b64encode(attr).decode("ascii") + return encoded.strip("=").replace("+", "-").replace("/", "_") + + @staticmethod + def serialize_decimal(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Decimal object to float. + + :param decimal attr: Object to be serialized. + :rtype: float + :return: serialized decimal + """ + return float(attr) + + @staticmethod + def serialize_long(attr, **kwargs): # pylint: disable=unused-argument + """Serialize long (Py2) or int (Py3). + + :param int attr: Object to be serialized. + :rtype: int/long + :return: serialized long + """ + return _long_type(attr) + + @staticmethod + def serialize_date(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Date object into ISO-8601 formatted string. + + :param Date attr: Object to be serialized. + :rtype: str + :return: serialized date + """ + if isinstance(attr, str): + attr = isodate.parse_date(attr) + t = "{:04}-{:02}-{:02}".format(attr.year, attr.month, attr.day) + return t + + @staticmethod + def serialize_time(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Time object into ISO-8601 formatted string. + + :param datetime.time attr: Object to be serialized. + :rtype: str + :return: serialized time + """ + if isinstance(attr, str): + attr = isodate.parse_time(attr) + t = "{:02}:{:02}:{:02}".format(attr.hour, attr.minute, attr.second) + if attr.microsecond: + t += ".{:02}".format(attr.microsecond) + return t + + @staticmethod + def serialize_duration(attr, **kwargs): # pylint: disable=unused-argument + """Serialize TimeDelta object into ISO-8601 formatted string. + + :param TimeDelta attr: Object to be serialized. + :rtype: str + :return: serialized duration + """ + if isinstance(attr, str): + attr = isodate.parse_duration(attr) + return isodate.duration_isoformat(attr) + + @staticmethod + def serialize_rfc(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Datetime object into RFC-1123 formatted string. + + :param Datetime attr: Object to be serialized. + :rtype: str + :raises TypeError: if format invalid. + :return: serialized rfc + """ + try: + if not attr.tzinfo: + _LOGGER.warning("Datetime with no tzinfo will be considered UTC.") + utc = attr.utctimetuple() + except AttributeError as exc: + raise TypeError("RFC1123 object must be valid Datetime object.") from exc + + return "{}, {:02} {} {:04} {:02}:{:02}:{:02} GMT".format( + Serializer.days[utc.tm_wday], + utc.tm_mday, + Serializer.months[utc.tm_mon], + utc.tm_year, + utc.tm_hour, + utc.tm_min, + utc.tm_sec, + ) + + @staticmethod + def serialize_iso(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Datetime object into ISO-8601 formatted string. + + :param Datetime attr: Object to be serialized. + :rtype: str + :raises SerializationError: if format invalid. + :return: serialized iso + """ + if isinstance(attr, str): + attr = isodate.parse_datetime(attr) + try: + if not attr.tzinfo: + _LOGGER.warning("Datetime with no tzinfo will be considered UTC.") + utc = attr.utctimetuple() + if utc.tm_year > 9999 or utc.tm_year < 1: + raise OverflowError("Hit max or min date") + + microseconds = str(attr.microsecond).rjust(6, "0").rstrip("0").ljust(3, "0") + if microseconds: + microseconds = "." + microseconds + date = "{:04}-{:02}-{:02}T{:02}:{:02}:{:02}".format( + utc.tm_year, utc.tm_mon, utc.tm_mday, utc.tm_hour, utc.tm_min, utc.tm_sec + ) + return date + microseconds + "Z" + except (ValueError, OverflowError) as err: + msg = "Unable to serialize datetime object." + raise SerializationError(msg) from err + except AttributeError as err: + msg = "ISO-8601 object must be valid Datetime object." + raise TypeError(msg) from err + + @staticmethod + def serialize_unix(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Datetime object into IntTime format. + This is represented as seconds. + + :param Datetime attr: Object to be serialized. + :rtype: int + :raises SerializationError: if format invalid + :return: serialied unix + """ + if isinstance(attr, int): + return attr + try: + if not attr.tzinfo: + _LOGGER.warning("Datetime with no tzinfo will be considered UTC.") + return int(calendar.timegm(attr.utctimetuple())) + except AttributeError as exc: + raise TypeError("Unix time object must be valid Datetime object.") from exc + + +def rest_key_extractor(attr, attr_desc, data): # pylint: disable=unused-argument + key = attr_desc["key"] + working_data = data + + while "." in key: + # Need the cast, as for some reasons "split" is typed as list[str | Any] + dict_keys = cast(List[str], _FLATTEN.split(key)) + if len(dict_keys) == 1: + key = _decode_attribute_map_key(dict_keys[0]) + break + working_key = _decode_attribute_map_key(dict_keys[0]) + working_data = working_data.get(working_key, data) + if working_data is None: + # If at any point while following flatten JSON path see None, it means + # that all properties under are None as well + return None + key = ".".join(dict_keys[1:]) + + return working_data.get(key) + + +def rest_key_case_insensitive_extractor( # pylint: disable=unused-argument, inconsistent-return-statements + attr, attr_desc, data +): + key = attr_desc["key"] + working_data = data + + while "." in key: + dict_keys = _FLATTEN.split(key) + if len(dict_keys) == 1: + key = _decode_attribute_map_key(dict_keys[0]) + break + working_key = _decode_attribute_map_key(dict_keys[0]) + working_data = attribute_key_case_insensitive_extractor(working_key, None, working_data) + if working_data is None: + # If at any point while following flatten JSON path see None, it means + # that all properties under are None as well + return None + key = ".".join(dict_keys[1:]) + + if working_data: + return attribute_key_case_insensitive_extractor(key, None, working_data) + + +def last_rest_key_extractor(attr, attr_desc, data): # pylint: disable=unused-argument + """Extract the attribute in "data" based on the last part of the JSON path key. + + :param str attr: The attribute to extract + :param dict attr_desc: The attribute description + :param dict data: The data to extract from + :rtype: object + :returns: The extracted attribute + """ + key = attr_desc["key"] + dict_keys = _FLATTEN.split(key) + return attribute_key_extractor(dict_keys[-1], None, data) + + +def last_rest_key_case_insensitive_extractor(attr, attr_desc, data): # pylint: disable=unused-argument + """Extract the attribute in "data" based on the last part of the JSON path key. + + This is the case insensitive version of "last_rest_key_extractor" + :param str attr: The attribute to extract + :param dict attr_desc: The attribute description + :param dict data: The data to extract from + :rtype: object + :returns: The extracted attribute + """ + key = attr_desc["key"] + dict_keys = _FLATTEN.split(key) + return attribute_key_case_insensitive_extractor(dict_keys[-1], None, data) + + +def attribute_key_extractor(attr, _, data): + return data.get(attr) + + +def attribute_key_case_insensitive_extractor(attr, _, data): + found_key = None + lower_attr = attr.lower() + for key in data: + if lower_attr == key.lower(): + found_key = key + break + + return data.get(found_key) + + +def _extract_name_from_internal_type(internal_type): + """Given an internal type XML description, extract correct XML name with namespace. + + :param dict internal_type: An model type + :rtype: tuple + :returns: A tuple XML name + namespace dict + """ + internal_type_xml_map = getattr(internal_type, "_xml_map", {}) + xml_name = internal_type_xml_map.get("name", internal_type.__name__) + xml_ns = internal_type_xml_map.get("ns", None) + if xml_ns: + xml_name = "{{{}}}{}".format(xml_ns, xml_name) + return xml_name + + +def xml_key_extractor(attr, attr_desc, data): # pylint: disable=unused-argument,too-many-return-statements + if isinstance(data, dict): + return None + + # Test if this model is XML ready first + if not isinstance(data, ET.Element): + return None + + xml_desc = attr_desc.get("xml", {}) + xml_name = xml_desc.get("name", attr_desc["key"]) + + # Look for a children + is_iter_type = attr_desc["type"].startswith("[") + is_wrapped = xml_desc.get("wrapped", False) + internal_type = attr_desc.get("internalType", None) + internal_type_xml_map = getattr(internal_type, "_xml_map", {}) + + # Integrate namespace if necessary + xml_ns = xml_desc.get("ns", internal_type_xml_map.get("ns", None)) + if xml_ns: + xml_name = "{{{}}}{}".format(xml_ns, xml_name) + + # If it's an attribute, that's simple + if xml_desc.get("attr", False): + return data.get(xml_name) + + # If it's x-ms-text, that's simple too + if xml_desc.get("text", False): + return data.text + + # Scenario where I take the local name: + # - Wrapped node + # - Internal type is an enum (considered basic types) + # - Internal type has no XML/Name node + if is_wrapped or (internal_type and (issubclass(internal_type, Enum) or "name" not in internal_type_xml_map)): + children = data.findall(xml_name) + # If internal type has a local name and it's not a list, I use that name + elif not is_iter_type and internal_type and "name" in internal_type_xml_map: + xml_name = _extract_name_from_internal_type(internal_type) + children = data.findall(xml_name) + # That's an array + else: + if internal_type: # Complex type, ignore itemsName and use the complex type name + items_name = _extract_name_from_internal_type(internal_type) + else: + items_name = xml_desc.get("itemsName", xml_name) + children = data.findall(items_name) + + if len(children) == 0: + if is_iter_type: + if is_wrapped: + return None # is_wrapped no node, we want None + return [] # not wrapped, assume empty list + return None # Assume it's not there, maybe an optional node. + + # If is_iter_type and not wrapped, return all found children + if is_iter_type: + if not is_wrapped: + return children + # Iter and wrapped, should have found one node only (the wrap one) + if len(children) != 1: + raise DeserializationError( + "Tried to deserialize an array not wrapped, and found several nodes '{}'. Maybe you should declare this array as wrapped?".format( + xml_name + ) + ) + return list(children[0]) # Might be empty list and that's ok. + + # Here it's not a itertype, we should have found one element only or empty + if len(children) > 1: + raise DeserializationError("Find several XML '{}' where it was not expected".format(xml_name)) + return children[0] + + +class Deserializer: + """Response object model deserializer. + + :param dict classes: Class type dictionary for deserializing complex types. + :ivar list key_extractors: Ordered list of extractors to be used by this deserializer. + """ + + basic_types = {str: "str", int: "int", bool: "bool", float: "float"} + + valid_date = re.compile(r"\d{4}[-]\d{2}[-]\d{2}T\d{2}:\d{2}:\d{2}\.?\d*Z?[-+]?[\d{2}]?:?[\d{2}]?") + + def __init__(self, classes: Optional[Mapping[str, type]] = None) -> None: + self.deserialize_type = { + "iso-8601": Deserializer.deserialize_iso, + "rfc-1123": Deserializer.deserialize_rfc, + "unix-time": Deserializer.deserialize_unix, + "duration": Deserializer.deserialize_duration, + "date": Deserializer.deserialize_date, + "time": Deserializer.deserialize_time, + "decimal": Deserializer.deserialize_decimal, + "long": Deserializer.deserialize_long, + "bytearray": Deserializer.deserialize_bytearray, + "base64": Deserializer.deserialize_base64, + "object": self.deserialize_object, + "[]": self.deserialize_iter, + "{}": self.deserialize_dict, + } + self.deserialize_expected_types = { + "duration": (isodate.Duration, datetime.timedelta), + "iso-8601": (datetime.datetime), + } + self.dependencies: Dict[str, type] = dict(classes) if classes else {} + self.key_extractors = [rest_key_extractor, xml_key_extractor] + # Additional properties only works if the "rest_key_extractor" is used to + # extract the keys. Making it to work whatever the key extractor is too much + # complicated, with no real scenario for now. + # So adding a flag to disable additional properties detection. This flag should be + # used if your expect the deserialization to NOT come from a JSON REST syntax. + # Otherwise, result are unexpected + self.additional_properties_detection = True + + def __call__(self, target_obj, response_data, content_type=None): + """Call the deserializer to process a REST response. + + :param str target_obj: Target data type to deserialize to. + :param requests.Response response_data: REST response object. + :param str content_type: Swagger "produces" if available. + :raises DeserializationError: if deserialization fails. + :return: Deserialized object. + :rtype: object + """ + data = self._unpack_content(response_data, content_type) + return self._deserialize(target_obj, data) + + def _deserialize(self, target_obj, data): # pylint: disable=inconsistent-return-statements + """Call the deserializer on a model. + + Data needs to be already deserialized as JSON or XML ElementTree + + :param str target_obj: Target data type to deserialize to. + :param object data: Object to deserialize. + :raises DeserializationError: if deserialization fails. + :return: Deserialized object. + :rtype: object + """ + # This is already a model, go recursive just in case + if hasattr(data, "_attribute_map"): + constants = [name for name, config in getattr(data, "_validation", {}).items() if config.get("constant")] + try: + for attr, mapconfig in data._attribute_map.items(): # pylint: disable=protected-access + if attr in constants: + continue + value = getattr(data, attr) + if value is None: + continue + local_type = mapconfig["type"] + internal_data_type = local_type.strip("[]{}") + if internal_data_type not in self.dependencies or isinstance(internal_data_type, Enum): + continue + setattr(data, attr, self._deserialize(local_type, value)) + return data + except AttributeError: + return + + response, class_name = self._classify_target(target_obj, data) + + if isinstance(response, str): + return self.deserialize_data(data, response) + if isinstance(response, type) and issubclass(response, Enum): + return self.deserialize_enum(data, response) + + if data is None or data is CoreNull: + return data + try: + attributes = response._attribute_map # type: ignore # pylint: disable=protected-access + d_attrs = {} + for attr, attr_desc in attributes.items(): + # Check empty string. If it's not empty, someone has a real "additionalProperties"... + if attr == "additional_properties" and attr_desc["key"] == "": + continue + raw_value = None + # Enhance attr_desc with some dynamic data + attr_desc = attr_desc.copy() # Do a copy, do not change the real one + internal_data_type = attr_desc["type"].strip("[]{}") + if internal_data_type in self.dependencies: + attr_desc["internalType"] = self.dependencies[internal_data_type] + + for key_extractor in self.key_extractors: + found_value = key_extractor(attr, attr_desc, data) + if found_value is not None: + if raw_value is not None and raw_value != found_value: + msg = ( + "Ignoring extracted value '%s' from %s for key '%s'" + " (duplicate extraction, follow extractors order)" + ) + _LOGGER.warning(msg, found_value, key_extractor, attr) + continue + raw_value = found_value + + value = self.deserialize_data(raw_value, attr_desc["type"]) + d_attrs[attr] = value + except (AttributeError, TypeError, KeyError) as err: + msg = "Unable to deserialize to object: " + class_name # type: ignore + raise DeserializationError(msg) from err + additional_properties = self._build_additional_properties(attributes, data) + return self._instantiate_model(response, d_attrs, additional_properties) + + def _build_additional_properties(self, attribute_map, data): + if not self.additional_properties_detection: + return None + if "additional_properties" in attribute_map and attribute_map.get("additional_properties", {}).get("key") != "": + # Check empty string. If it's not empty, someone has a real "additionalProperties" + return None + if isinstance(data, ET.Element): + data = {el.tag: el.text for el in data} + + known_keys = { + _decode_attribute_map_key(_FLATTEN.split(desc["key"])[0]) + for desc in attribute_map.values() + if desc["key"] != "" + } + present_keys = set(data.keys()) + missing_keys = present_keys - known_keys + return {key: data[key] for key in missing_keys} + + def _classify_target(self, target, data): + """Check to see whether the deserialization target object can + be classified into a subclass. + Once classification has been determined, initialize object. + + :param str target: The target object type to deserialize to. + :param str/dict data: The response data to deserialize. + :return: The classified target object and its class name. + :rtype: tuple + """ + if target is None: + return None, None + + if isinstance(target, str): + try: + target = self.dependencies[target] + except KeyError: + return target, target + + try: + target = target._classify(data, self.dependencies) # type: ignore # pylint: disable=protected-access + except AttributeError: + pass # Target is not a Model, no classify + return target, target.__class__.__name__ # type: ignore + + def failsafe_deserialize(self, target_obj, data, content_type=None): + """Ignores any errors encountered in deserialization, + and falls back to not deserializing the object. Recommended + for use in error deserialization, as we want to return the + HttpResponseError to users, and not have them deal with + a deserialization error. + + :param str target_obj: The target object type to deserialize to. + :param str/dict data: The response data to deserialize. + :param str content_type: Swagger "produces" if available. + :return: Deserialized object. + :rtype: object + """ + try: + return self(target_obj, data, content_type=content_type) + except: # pylint: disable=bare-except + _LOGGER.debug( + "Ran into a deserialization error. Ignoring since this is failsafe deserialization", exc_info=True + ) + return None + + @staticmethod + def _unpack_content(raw_data, content_type=None): + """Extract the correct structure for deserialization. + + If raw_data is a PipelineResponse, try to extract the result of RawDeserializer. + if we can't, raise. Your Pipeline should have a RawDeserializer. + + If not a pipeline response and raw_data is bytes or string, use content-type + to decode it. If no content-type, try JSON. + + If raw_data is something else, bypass all logic and return it directly. + + :param obj raw_data: Data to be processed. + :param str content_type: How to parse if raw_data is a string/bytes. + :raises JSONDecodeError: If JSON is requested and parsing is impossible. + :raises UnicodeDecodeError: If bytes is not UTF8 + :rtype: object + :return: Unpacked content. + """ + # Assume this is enough to detect a Pipeline Response without importing it + context = getattr(raw_data, "context", {}) + if context: + if RawDeserializer.CONTEXT_NAME in context: + return context[RawDeserializer.CONTEXT_NAME] + raise ValueError("This pipeline didn't have the RawDeserializer policy; can't deserialize") + + # Assume this is enough to recognize universal_http.ClientResponse without importing it + if hasattr(raw_data, "body"): + return RawDeserializer.deserialize_from_http_generics(raw_data.text(), raw_data.headers) + + # Assume this enough to recognize requests.Response without importing it. + if hasattr(raw_data, "_content_consumed"): + return RawDeserializer.deserialize_from_http_generics(raw_data.text, raw_data.headers) + + if isinstance(raw_data, (str, bytes)) or hasattr(raw_data, "read"): + return RawDeserializer.deserialize_from_text(raw_data, content_type) # type: ignore + return raw_data + + def _instantiate_model(self, response, attrs, additional_properties=None): + """Instantiate a response model passing in deserialized args. + + :param Response response: The response model class. + :param dict attrs: The deserialized response attributes. + :param dict additional_properties: Additional properties to be set. + :rtype: Response + :return: The instantiated response model. + """ + if callable(response): + subtype = getattr(response, "_subtype_map", {}) + try: + readonly = [ + k + for k, v in response._validation.items() # pylint: disable=protected-access # type: ignore + if v.get("readonly") + ] + const = [ + k + for k, v in response._validation.items() # pylint: disable=protected-access # type: ignore + if v.get("constant") + ] + kwargs = {k: v for k, v in attrs.items() if k not in subtype and k not in readonly + const} + response_obj = response(**kwargs) + for attr in readonly: + setattr(response_obj, attr, attrs.get(attr)) + if additional_properties: + response_obj.additional_properties = additional_properties # type: ignore + return response_obj + except TypeError as err: + msg = "Unable to deserialize {} into model {}. ".format(kwargs, response) # type: ignore + raise DeserializationError(msg + str(err)) from err + else: + try: + for attr, value in attrs.items(): + setattr(response, attr, value) + return response + except Exception as exp: + msg = "Unable to populate response model. " + msg += "Type: {}, Error: {}".format(type(response), exp) + raise DeserializationError(msg) from exp + + def deserialize_data(self, data, data_type): # pylint: disable=too-many-return-statements + """Process data for deserialization according to data type. + + :param str data: The response string to be deserialized. + :param str data_type: The type to deserialize to. + :raises DeserializationError: if deserialization fails. + :return: Deserialized object. + :rtype: object + """ + if data is None: + return data + + try: + if not data_type: + return data + if data_type in self.basic_types.values(): + return self.deserialize_basic(data, data_type) + if data_type in self.deserialize_type: + if isinstance(data, self.deserialize_expected_types.get(data_type, tuple())): + return data + + is_a_text_parsing_type = lambda x: x not in [ # pylint: disable=unnecessary-lambda-assignment + "object", + "[]", + r"{}", + ] + if isinstance(data, ET.Element) and is_a_text_parsing_type(data_type) and not data.text: + return None + data_val = self.deserialize_type[data_type](data) + return data_val + + iter_type = data_type[0] + data_type[-1] + if iter_type in self.deserialize_type: + return self.deserialize_type[iter_type](data, data_type[1:-1]) + + obj_type = self.dependencies[data_type] + if issubclass(obj_type, Enum): + if isinstance(data, ET.Element): + data = data.text + return self.deserialize_enum(data, obj_type) + + except (ValueError, TypeError, AttributeError) as err: + msg = "Unable to deserialize response data." + msg += " Data: {}, {}".format(data, data_type) + raise DeserializationError(msg) from err + return self._deserialize(obj_type, data) + + def deserialize_iter(self, attr, iter_type): + """Deserialize an iterable. + + :param list attr: Iterable to be deserialized. + :param str iter_type: The type of object in the iterable. + :return: Deserialized iterable. + :rtype: list + """ + if attr is None: + return None + if isinstance(attr, ET.Element): # If I receive an element here, get the children + attr = list(attr) + if not isinstance(attr, (list, set)): + raise DeserializationError("Cannot deserialize as [{}] an object of type {}".format(iter_type, type(attr))) + return [self.deserialize_data(a, iter_type) for a in attr] + + def deserialize_dict(self, attr, dict_type): + """Deserialize a dictionary. + + :param dict/list attr: Dictionary to be deserialized. Also accepts + a list of key, value pairs. + :param str dict_type: The object type of the items in the dictionary. + :return: Deserialized dictionary. + :rtype: dict + """ + if isinstance(attr, list): + return {x["key"]: self.deserialize_data(x["value"], dict_type) for x in attr} + + if isinstance(attr, ET.Element): + # Transform value into {"Key": "value"} + attr = {el.tag: el.text for el in attr} + return {k: self.deserialize_data(v, dict_type) for k, v in attr.items()} + + def deserialize_object(self, attr, **kwargs): # pylint: disable=too-many-return-statements + """Deserialize a generic object. + This will be handled as a dictionary. + + :param dict attr: Dictionary to be deserialized. + :return: Deserialized object. + :rtype: dict + :raises TypeError: if non-builtin datatype encountered. + """ + if attr is None: + return None + if isinstance(attr, ET.Element): + # Do no recurse on XML, just return the tree as-is + return attr + if isinstance(attr, str): + return self.deserialize_basic(attr, "str") + obj_type = type(attr) + if obj_type in self.basic_types: + return self.deserialize_basic(attr, self.basic_types[obj_type]) + if obj_type is _long_type: + return self.deserialize_long(attr) + + if obj_type == dict: + deserialized = {} + for key, value in attr.items(): + try: + deserialized[key] = self.deserialize_object(value, **kwargs) + except ValueError: + deserialized[key] = None + return deserialized + + if obj_type == list: + deserialized = [] + for obj in attr: + try: + deserialized.append(self.deserialize_object(obj, **kwargs)) + except ValueError: + pass + return deserialized + + error = "Cannot deserialize generic object with type: " + raise TypeError(error + str(obj_type)) + + def deserialize_basic(self, attr, data_type): # pylint: disable=too-many-return-statements + """Deserialize basic builtin data type from string. + Will attempt to convert to str, int, float and bool. + This function will also accept '1', '0', 'true' and 'false' as + valid bool values. + + :param str attr: response string to be deserialized. + :param str data_type: deserialization data type. + :return: Deserialized basic type. + :rtype: str, int, float or bool + :raises TypeError: if string format is not valid. + """ + # If we're here, data is supposed to be a basic type. + # If it's still an XML node, take the text + if isinstance(attr, ET.Element): + attr = attr.text + if not attr: + if data_type == "str": + # None or '', node is empty string. + return "" + # None or '', node with a strong type is None. + # Don't try to model "empty bool" or "empty int" + return None + + if data_type == "bool": + if attr in [True, False, 1, 0]: + return bool(attr) + if isinstance(attr, str): + if attr.lower() in ["true", "1"]: + return True + if attr.lower() in ["false", "0"]: + return False + raise TypeError("Invalid boolean value: {}".format(attr)) + + if data_type == "str": + return self.deserialize_unicode(attr) + return eval(data_type)(attr) # nosec # pylint: disable=eval-used + + @staticmethod + def deserialize_unicode(data): + """Preserve unicode objects in Python 2, otherwise return data + as a string. + + :param str data: response string to be deserialized. + :return: Deserialized string. + :rtype: str or unicode + """ + # We might be here because we have an enum modeled as string, + # and we try to deserialize a partial dict with enum inside + if isinstance(data, Enum): + return data + + # Consider this is real string + try: + if isinstance(data, unicode): # type: ignore + return data + except NameError: + return str(data) + return str(data) + + @staticmethod + def deserialize_enum(data, enum_obj): + """Deserialize string into enum object. + + If the string is not a valid enum value it will be returned as-is + and a warning will be logged. + + :param str data: Response string to be deserialized. If this value is + None or invalid it will be returned as-is. + :param Enum enum_obj: Enum object to deserialize to. + :return: Deserialized enum object. + :rtype: Enum + """ + if isinstance(data, enum_obj) or data is None: + return data + if isinstance(data, Enum): + data = data.value + if isinstance(data, int): + # Workaround. We might consider remove it in the future. + try: + return list(enum_obj.__members__.values())[data] + except IndexError as exc: + error = "{!r} is not a valid index for enum {!r}" + raise DeserializationError(error.format(data, enum_obj)) from exc + try: + return enum_obj(str(data)) + except ValueError: + for enum_value in enum_obj: + if enum_value.value.lower() == str(data).lower(): + return enum_value + # We don't fail anymore for unknown value, we deserialize as a string + _LOGGER.warning("Deserializer is not able to find %s as valid enum in %s", data, enum_obj) + return Deserializer.deserialize_unicode(data) + + @staticmethod + def deserialize_bytearray(attr): + """Deserialize string into bytearray. + + :param str attr: response string to be deserialized. + :return: Deserialized bytearray + :rtype: bytearray + :raises TypeError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + return bytearray(b64decode(attr)) # type: ignore + + @staticmethod + def deserialize_base64(attr): + """Deserialize base64 encoded string into string. + + :param str attr: response string to be deserialized. + :return: Deserialized base64 string + :rtype: bytearray + :raises TypeError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + padding = "=" * (3 - (len(attr) + 3) % 4) # type: ignore + attr = attr + padding # type: ignore + encoded = attr.replace("-", "+").replace("_", "/") + return b64decode(encoded) + + @staticmethod + def deserialize_decimal(attr): + """Deserialize string into Decimal object. + + :param str attr: response string to be deserialized. + :return: Deserialized decimal + :raises DeserializationError: if string format invalid. + :rtype: decimal + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + return decimal.Decimal(str(attr)) # type: ignore + except decimal.DecimalException as err: + msg = "Invalid decimal {}".format(attr) + raise DeserializationError(msg) from err + + @staticmethod + def deserialize_long(attr): + """Deserialize string into long (Py2) or int (Py3). + + :param str attr: response string to be deserialized. + :return: Deserialized int + :rtype: long or int + :raises ValueError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + return _long_type(attr) # type: ignore + + @staticmethod + def deserialize_duration(attr): + """Deserialize ISO-8601 formatted string into TimeDelta object. + + :param str attr: response string to be deserialized. + :return: Deserialized duration + :rtype: TimeDelta + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + duration = isodate.parse_duration(attr) + except (ValueError, OverflowError, AttributeError) as err: + msg = "Cannot deserialize duration object." + raise DeserializationError(msg) from err + return duration + + @staticmethod + def deserialize_date(attr): + """Deserialize ISO-8601 formatted string into Date object. + + :param str attr: response string to be deserialized. + :return: Deserialized date + :rtype: Date + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + if re.search(r"[^\W\d_]", attr, re.I + re.U): # type: ignore + raise DeserializationError("Date must have only digits and -. Received: %s" % attr) + # This must NOT use defaultmonth/defaultday. Using None ensure this raises an exception. + return isodate.parse_date(attr, defaultmonth=0, defaultday=0) + + @staticmethod + def deserialize_time(attr): + """Deserialize ISO-8601 formatted string into time object. + + :param str attr: response string to be deserialized. + :return: Deserialized time + :rtype: datetime.time + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + if re.search(r"[^\W\d_]", attr, re.I + re.U): # type: ignore + raise DeserializationError("Date must have only digits and -. Received: %s" % attr) + return isodate.parse_time(attr) + + @staticmethod + def deserialize_rfc(attr): + """Deserialize RFC-1123 formatted string into Datetime object. + + :param str attr: response string to be deserialized. + :return: Deserialized RFC datetime + :rtype: Datetime + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + parsed_date = email.utils.parsedate_tz(attr) # type: ignore + date_obj = datetime.datetime( + *parsed_date[:6], tzinfo=datetime.timezone(datetime.timedelta(minutes=(parsed_date[9] or 0) / 60)) + ) + if not date_obj.tzinfo: + date_obj = date_obj.astimezone(tz=TZ_UTC) + except ValueError as err: + msg = "Cannot deserialize to rfc datetime object." + raise DeserializationError(msg) from err + return date_obj + + @staticmethod + def deserialize_iso(attr): + """Deserialize ISO-8601 formatted string into Datetime object. + + :param str attr: response string to be deserialized. + :return: Deserialized ISO datetime + :rtype: Datetime + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + attr = attr.upper() # type: ignore + match = Deserializer.valid_date.match(attr) + if not match: + raise ValueError("Invalid datetime string: " + attr) + + check_decimal = attr.split(".") + if len(check_decimal) > 1: + decimal_str = "" + for digit in check_decimal[1]: + if digit.isdigit(): + decimal_str += digit + else: + break + if len(decimal_str) > 6: + attr = attr.replace(decimal_str, decimal_str[0:6]) + + date_obj = isodate.parse_datetime(attr) + test_utc = date_obj.utctimetuple() + if test_utc.tm_year > 9999 or test_utc.tm_year < 1: + raise OverflowError("Hit max or min date") + except (ValueError, OverflowError, AttributeError) as err: + msg = "Cannot deserialize datetime object." + raise DeserializationError(msg) from err + return date_obj + + @staticmethod + def deserialize_unix(attr): + """Serialize Datetime object into IntTime format. + This is represented as seconds. + + :param int attr: Object to be serialized. + :return: Deserialized datetime + :rtype: Datetime + :raises DeserializationError: if format invalid + """ + if isinstance(attr, ET.Element): + attr = int(attr.text) # type: ignore + try: + attr = int(attr) + date_obj = datetime.datetime.fromtimestamp(attr, TZ_UTC) + except ValueError as err: + msg = "Cannot deserialize to unix datetime object." + raise DeserializationError(msg) from err + return date_obj diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ReservedWordsVersionTolerant/reservedwordsversiontolerant/_utils/utils.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ReservedWordsVersionTolerant/reservedwordsversiontolerant/_utils/utils.py new file mode 100644 index 00000000000..d1f895895c6 --- /dev/null +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ReservedWordsVersionTolerant/reservedwordsversiontolerant/_utils/utils.py @@ -0,0 +1,36 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from abc import ABC +from typing import Generic, TYPE_CHECKING, TypeVar + +if TYPE_CHECKING: + from .serialization import Deserializer, Serializer + + +TClient = TypeVar("TClient") +TConfig = TypeVar("TConfig") + + +class ClientMixinABC(ABC, Generic[TClient, TConfig]): + """DO NOT use this class. It is for internal typing use only.""" + + _client: TClient + _config: TConfig + _serialize: "Serializer" + _deserialize: "Deserializer" + + +def raise_if_not_implemented(cls, abstract_methods): + not_implemented = [f for f in abstract_methods if not callable(getattr(cls, f, None))] + if not_implemented: + raise NotImplementedError( + "The following methods on operation group '{}' are not implemented: '{}'." + " Please refer to https://aka.ms/azsdk/python/dpcodegen/python/customize to learn how to customize.".format( + cls.__name__, "', '".join(not_implemented) + ) + ) diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ReservedWordsVersionTolerant/reservedwordsversiontolerant/_vendor.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ReservedWordsVersionTolerant/reservedwordsversiontolerant/_vendor.py deleted file mode 100644 index fbd2879d4ef..00000000000 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ReservedWordsVersionTolerant/reservedwordsversiontolerant/_vendor.py +++ /dev/null @@ -1,36 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) AutoRest Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import ReservedWordsClientConfiguration - -if TYPE_CHECKING: - from azure.core import PipelineClient - - from ._serialization import Deserializer, Serializer - - -class ReservedWordsClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "PipelineClient" - _config: ReservedWordsClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" - - -def raise_if_not_implemented(cls, abstract_methods): - not_implemented = [f for f in abstract_methods if not callable(getattr(cls, f, None))] - if not_implemented: - raise NotImplementedError( - "The following methods on operation group '{}' are not implemented: '{}'." - " Please refer to https://aka.ms/azsdk/python/dpcodegen/python/customize to learn how to customize.".format( - cls.__name__, "', '".join(not_implemented) - ) - ) diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ReservedWordsVersionTolerant/reservedwordsversiontolerant/aio/_client.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ReservedWordsVersionTolerant/reservedwordsversiontolerant/aio/_client.py index 16bf6f363c8..22b2ec475e0 100644 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ReservedWordsVersionTolerant/reservedwordsversiontolerant/aio/_client.py +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ReservedWordsVersionTolerant/reservedwordsversiontolerant/aio/_client.py @@ -14,7 +14,7 @@ from azure.core.pipeline import policies from azure.core.rest import AsyncHttpResponse, HttpRequest -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import ReservedWordsClientConfiguration from .operations import ImportOperations, ReservedWordsClientOperationsMixin diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ReservedWordsVersionTolerant/reservedwordsversiontolerant/aio/_vendor.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ReservedWordsVersionTolerant/reservedwordsversiontolerant/aio/_vendor.py deleted file mode 100644 index bed55c1ad80..00000000000 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ReservedWordsVersionTolerant/reservedwordsversiontolerant/aio/_vendor.py +++ /dev/null @@ -1,36 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) AutoRest Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import ReservedWordsClientConfiguration - -if TYPE_CHECKING: - from azure.core import AsyncPipelineClient - - from .._serialization import Deserializer, Serializer - - -class ReservedWordsClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "AsyncPipelineClient" - _config: ReservedWordsClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" - - -def raise_if_not_implemented(cls, abstract_methods): - not_implemented = [f for f in abstract_methods if not callable(getattr(cls, f, None))] - if not_implemented: - raise NotImplementedError( - "The following methods on operation group '{}' are not implemented: '{}'." - " Please refer to https://aka.ms/azsdk/python/dpcodegen/python/customize to learn how to customize.".format( - cls.__name__, "', '".join(not_implemented) - ) - ) diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ReservedWordsVersionTolerant/reservedwordsversiontolerant/aio/operations/_operations.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ReservedWordsVersionTolerant/reservedwordsversiontolerant/aio/operations/_operations.py index 18e33008809..86a08e28f45 100644 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ReservedWordsVersionTolerant/reservedwordsversiontolerant/aio/operations/_operations.py +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ReservedWordsVersionTolerant/reservedwordsversiontolerant/aio/operations/_operations.py @@ -23,7 +23,8 @@ from azure.core.tracing.decorator_async import distributed_trace_async from azure.core.utils import case_insensitive_dict -from ..._serialization import Deserializer, Serializer +from ..._utils.serialization import Deserializer, Serializer +from ..._utils.utils import ClientMixinABC, raise_if_not_implemented from ...operations._operations import ( build_import_operations_operation_one_request, build_reserved_words_operation_with_content_param_request, @@ -32,7 +33,6 @@ build_reserved_words_reserved_enum_request, ) from .._configuration import ReservedWordsClientConfiguration -from .._vendor import ReservedWordsClientMixinABC, raise_if_not_implemented JSON = MutableMapping[str, Any] T = TypeVar("T") @@ -108,7 +108,9 @@ async def operation_one(self, *, parameter1: str, **kwargs: Any) -> JSON: return cast(JSON, deserialized) # type: ignore -class ReservedWordsClientOperationsMixin(ReservedWordsClientMixinABC): # pylint: disable=abstract-class-instantiated +class ReservedWordsClientOperationsMixin( # pylint: disable=abstract-class-instantiated + ClientMixinABC[AsyncPipelineClient, ReservedWordsClientConfiguration] +): def __init__(self) -> None: raise_if_not_implemented( diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ReservedWordsVersionTolerant/reservedwordsversiontolerant/operations/_operations.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ReservedWordsVersionTolerant/reservedwordsversiontolerant/operations/_operations.py index 7827b7f40cf..dbfaa422820 100644 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ReservedWordsVersionTolerant/reservedwordsversiontolerant/operations/_operations.py +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ReservedWordsVersionTolerant/reservedwordsversiontolerant/operations/_operations.py @@ -23,8 +23,8 @@ from azure.core.utils import case_insensitive_dict from .._configuration import ReservedWordsClientConfiguration -from .._serialization import Deserializer, Serializer -from .._vendor import ReservedWordsClientMixinABC, raise_if_not_implemented +from .._utils.serialization import Deserializer, Serializer +from .._utils.utils import ClientMixinABC, raise_if_not_implemented JSON = MutableMapping[str, Any] T = TypeVar("T") @@ -207,7 +207,9 @@ def operation_one(self, *, parameter1: str, **kwargs: Any) -> JSON: return cast(JSON, deserialized) # type: ignore -class ReservedWordsClientOperationsMixin(ReservedWordsClientMixinABC): # pylint: disable=abstract-class-instantiated +class ReservedWordsClientOperationsMixin( # pylint: disable=abstract-class-instantiated + ClientMixinABC[PipelineClient, ReservedWordsClientConfiguration] +): def __init__(self): raise_if_not_implemented( diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/SecurityAadSwaggerVersionTolerant/securityaadswaggerversiontolerant/_client.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/SecurityAadSwaggerVersionTolerant/securityaadswaggerversiontolerant/_client.py index 3d0954f244a..61ee113a306 100644 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/SecurityAadSwaggerVersionTolerant/securityaadswaggerversiontolerant/_client.py +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/SecurityAadSwaggerVersionTolerant/securityaadswaggerversiontolerant/_client.py @@ -16,7 +16,7 @@ from ._configuration import AutorestSecurityAadConfiguration from ._operations import AutorestSecurityAadOperationsMixin -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer if TYPE_CHECKING: from azure.core.credentials import TokenCredential diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/SecurityAadSwaggerVersionTolerant/securityaadswaggerversiontolerant/_operations/_operations.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/SecurityAadSwaggerVersionTolerant/securityaadswaggerversiontolerant/_operations/_operations.py index b991f622db3..a104df4fd62 100644 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/SecurityAadSwaggerVersionTolerant/securityaadswaggerversiontolerant/_operations/_operations.py +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/SecurityAadSwaggerVersionTolerant/securityaadswaggerversiontolerant/_operations/_operations.py @@ -8,6 +8,7 @@ from collections.abc import MutableMapping from typing import Any, Callable, Dict, Optional, TypeVar +from azure.core import PipelineClient from azure.core.exceptions import ( ClientAuthenticationError, HttpResponseError, @@ -20,8 +21,9 @@ from azure.core.rest import HttpRequest, HttpResponse from azure.core.tracing.decorator import distributed_trace -from .._serialization import Serializer -from .._vendor import AutorestSecurityAadMixinABC +from .._configuration import AutorestSecurityAadConfiguration +from .._utils.serialization import Serializer +from .._utils.utils import ClientMixinABC T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] @@ -37,7 +39,7 @@ def build_autorest_security_aad_head_request(**kwargs: Any) -> HttpRequest: return HttpRequest(method="HEAD", url=_url, **kwargs) -class AutorestSecurityAadOperationsMixin(AutorestSecurityAadMixinABC): +class AutorestSecurityAadOperationsMixin(ClientMixinABC[PipelineClient, AutorestSecurityAadConfiguration]): @distributed_trace def head(self, **kwargs: Any) -> None: # pylint: disable=inconsistent-return-statements diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/SecurityAadSwaggerVersionTolerant/securityaadswaggerversiontolerant/_utils/__init__.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/SecurityAadSwaggerVersionTolerant/securityaadswaggerversiontolerant/_utils/__init__.py new file mode 100644 index 00000000000..0af9b28f660 --- /dev/null +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/SecurityAadSwaggerVersionTolerant/securityaadswaggerversiontolerant/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/SecurityAadSwaggerVersionTolerant/securityaadswaggerversiontolerant/_utils/serialization.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/SecurityAadSwaggerVersionTolerant/securityaadswaggerversiontolerant/_utils/serialization.py new file mode 100644 index 00000000000..f5187701d7b --- /dev/null +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/SecurityAadSwaggerVersionTolerant/securityaadswaggerversiontolerant/_utils/serialization.py @@ -0,0 +1,2032 @@ +# pylint: disable=line-too-long,useless-suppression,too-many-lines +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +# pyright: reportUnnecessaryTypeIgnoreComment=false + +from base64 import b64decode, b64encode +import calendar +import datetime +import decimal +import email +from enum import Enum +import json +import logging +import re +import sys +import codecs +from typing import ( + Dict, + Any, + cast, + Optional, + Union, + AnyStr, + IO, + Mapping, + Callable, + MutableMapping, + List, +) + +try: + from urllib import quote # type: ignore +except ImportError: + from urllib.parse import quote +import xml.etree.ElementTree as ET + +import isodate # type: ignore +from typing_extensions import Self + +from azure.core.exceptions import DeserializationError, SerializationError +from azure.core.serialization import NULL as CoreNull + +_BOM = codecs.BOM_UTF8.decode(encoding="utf-8") + +JSON = MutableMapping[str, Any] + + +class RawDeserializer: + + # Accept "text" because we're open minded people... + JSON_REGEXP = re.compile(r"^(application|text)/([a-z+.]+\+)?json$") + + # Name used in context + CONTEXT_NAME = "deserialized_data" + + @classmethod + def deserialize_from_text(cls, data: Optional[Union[AnyStr, IO]], content_type: Optional[str] = None) -> Any: + """Decode data according to content-type. + + Accept a stream of data as well, but will be load at once in memory for now. + + If no content-type, will return the string version (not bytes, not stream) + + :param data: Input, could be bytes or stream (will be decoded with UTF8) or text + :type data: str or bytes or IO + :param str content_type: The content type. + :return: The deserialized data. + :rtype: object + """ + if hasattr(data, "read"): + # Assume a stream + data = cast(IO, data).read() + + if isinstance(data, bytes): + data_as_str = data.decode(encoding="utf-8-sig") + else: + # Explain to mypy the correct type. + data_as_str = cast(str, data) + + # Remove Byte Order Mark if present in string + data_as_str = data_as_str.lstrip(_BOM) + + if content_type is None: + return data + + if cls.JSON_REGEXP.match(content_type): + try: + return json.loads(data_as_str) + except ValueError as err: + raise DeserializationError("JSON is invalid: {}".format(err), err) from err + elif "xml" in (content_type or []): + try: + + try: + if isinstance(data, unicode): # type: ignore + # If I'm Python 2.7 and unicode XML will scream if I try a "fromstring" on unicode string + data_as_str = data_as_str.encode(encoding="utf-8") # type: ignore + except NameError: + pass + + return ET.fromstring(data_as_str) # nosec + except ET.ParseError as err: + # It might be because the server has an issue, and returned JSON with + # content-type XML.... + # So let's try a JSON load, and if it's still broken + # let's flow the initial exception + def _json_attemp(data): + try: + return True, json.loads(data) + except ValueError: + return False, None # Don't care about this one + + success, json_result = _json_attemp(data) + if success: + return json_result + # If i'm here, it's not JSON, it's not XML, let's scream + # and raise the last context in this block (the XML exception) + # The function hack is because Py2.7 messes up with exception + # context otherwise. + _LOGGER.critical("Wasn't XML not JSON, failing") + raise DeserializationError("XML is invalid") from err + elif content_type.startswith("text/"): + return data_as_str + raise DeserializationError("Cannot deserialize content-type: {}".format(content_type)) + + @classmethod + def deserialize_from_http_generics(cls, body_bytes: Optional[Union[AnyStr, IO]], headers: Mapping) -> Any: + """Deserialize from HTTP response. + + Use bytes and headers to NOT use any requests/aiohttp or whatever + specific implementation. + Headers will tested for "content-type" + + :param bytes body_bytes: The body of the response. + :param dict headers: The headers of the response. + :returns: The deserialized data. + :rtype: object + """ + # Try to use content-type from headers if available + content_type = None + if "content-type" in headers: + content_type = headers["content-type"].split(";")[0].strip().lower() + # Ouch, this server did not declare what it sent... + # Let's guess it's JSON... + # Also, since Autorest was considering that an empty body was a valid JSON, + # need that test as well.... + else: + content_type = "application/json" + + if body_bytes: + return cls.deserialize_from_text(body_bytes, content_type) + return None + + +_LOGGER = logging.getLogger(__name__) + +try: + _long_type = long # type: ignore +except NameError: + _long_type = int + +TZ_UTC = datetime.timezone.utc + +_FLATTEN = re.compile(r"(? None: + self.additional_properties: Optional[Dict[str, Any]] = {} + for k in kwargs: # pylint: disable=consider-using-dict-items + if k not in self._attribute_map: + _LOGGER.warning("%s is not a known attribute of class %s and will be ignored", k, self.__class__) + elif k in self._validation and self._validation[k].get("readonly", False): + _LOGGER.warning("Readonly attribute %s will be ignored in class %s", k, self.__class__) + else: + setattr(self, k, kwargs[k]) + + def __eq__(self, other: Any) -> bool: + """Compare objects by comparing all attributes. + + :param object other: The object to compare + :returns: True if objects are equal + :rtype: bool + """ + if isinstance(other, self.__class__): + return self.__dict__ == other.__dict__ + return False + + def __ne__(self, other: Any) -> bool: + """Compare objects by comparing all attributes. + + :param object other: The object to compare + :returns: True if objects are not equal + :rtype: bool + """ + return not self.__eq__(other) + + def __str__(self) -> str: + return str(self.__dict__) + + @classmethod + def enable_additional_properties_sending(cls) -> None: + cls._attribute_map["additional_properties"] = {"key": "", "type": "{object}"} + + @classmethod + def is_xml_model(cls) -> bool: + try: + cls._xml_map # type: ignore + except AttributeError: + return False + return True + + @classmethod + def _create_xml_node(cls): + """Create XML node. + + :returns: The XML node + :rtype: xml.etree.ElementTree.Element + """ + try: + xml_map = cls._xml_map # type: ignore + except AttributeError: + xml_map = {} + + return _create_xml_node(xml_map.get("name", cls.__name__), xml_map.get("prefix", None), xml_map.get("ns", None)) + + def serialize(self, keep_readonly: bool = False, **kwargs: Any) -> JSON: + """Return the JSON that would be sent to server from this model. + + This is an alias to `as_dict(full_restapi_key_transformer, keep_readonly=False)`. + + If you want XML serialization, you can pass the kwargs is_xml=True. + + :param bool keep_readonly: If you want to serialize the readonly attributes + :returns: A dict JSON compatible object + :rtype: dict + """ + serializer = Serializer(self._infer_class_models()) + return serializer._serialize( # type: ignore # pylint: disable=protected-access + self, keep_readonly=keep_readonly, **kwargs + ) + + def as_dict( + self, + keep_readonly: bool = True, + key_transformer: Callable[[str, Dict[str, Any], Any], Any] = attribute_transformer, + **kwargs: Any + ) -> JSON: + """Return a dict that can be serialized using json.dump. + + Advanced usage might optionally use a callback as parameter: + + .. code::python + + def my_key_transformer(key, attr_desc, value): + return key + + Key is the attribute name used in Python. Attr_desc + is a dict of metadata. Currently contains 'type' with the + msrest type and 'key' with the RestAPI encoded key. + Value is the current value in this object. + + The string returned will be used to serialize the key. + If the return type is a list, this is considered hierarchical + result dict. + + See the three examples in this file: + + - attribute_transformer + - full_restapi_key_transformer + - last_restapi_key_transformer + + If you want XML serialization, you can pass the kwargs is_xml=True. + + :param bool keep_readonly: If you want to serialize the readonly attributes + :param function key_transformer: A key transformer function. + :returns: A dict JSON compatible object + :rtype: dict + """ + serializer = Serializer(self._infer_class_models()) + return serializer._serialize( # type: ignore # pylint: disable=protected-access + self, key_transformer=key_transformer, keep_readonly=keep_readonly, **kwargs + ) + + @classmethod + def _infer_class_models(cls): + try: + str_models = cls.__module__.rsplit(".", 1)[0] + models = sys.modules[str_models] + client_models = {k: v for k, v in models.__dict__.items() if isinstance(v, type)} + if cls.__name__ not in client_models: + raise ValueError("Not Autorest generated code") + except Exception: # pylint: disable=broad-exception-caught + # Assume it's not Autorest generated (tests?). Add ourselves as dependencies. + client_models = {cls.__name__: cls} + return client_models + + @classmethod + def deserialize(cls, data: Any, content_type: Optional[str] = None) -> Self: + """Parse a str using the RestAPI syntax and return a model. + + :param str data: A str using RestAPI structure. JSON by default. + :param str content_type: JSON by default, set application/xml if XML. + :returns: An instance of this model + :raises DeserializationError: if something went wrong + :rtype: Self + """ + deserializer = Deserializer(cls._infer_class_models()) + return deserializer(cls.__name__, data, content_type=content_type) # type: ignore + + @classmethod + def from_dict( + cls, + data: Any, + key_extractors: Optional[Callable[[str, Dict[str, Any], Any], Any]] = None, + content_type: Optional[str] = None, + ) -> Self: + """Parse a dict using given key extractor return a model. + + By default consider key + extractors (rest_key_case_insensitive_extractor, attribute_key_case_insensitive_extractor + and last_rest_key_case_insensitive_extractor) + + :param dict data: A dict using RestAPI structure + :param function key_extractors: A key extractor function. + :param str content_type: JSON by default, set application/xml if XML. + :returns: An instance of this model + :raises DeserializationError: if something went wrong + :rtype: Self + """ + deserializer = Deserializer(cls._infer_class_models()) + deserializer.key_extractors = ( # type: ignore + [ # type: ignore + attribute_key_case_insensitive_extractor, + rest_key_case_insensitive_extractor, + last_rest_key_case_insensitive_extractor, + ] + if key_extractors is None + else key_extractors + ) + return deserializer(cls.__name__, data, content_type=content_type) # type: ignore + + @classmethod + def _flatten_subtype(cls, key, objects): + if "_subtype_map" not in cls.__dict__: + return {} + result = dict(cls._subtype_map[key]) + for valuetype in cls._subtype_map[key].values(): + result.update(objects[valuetype]._flatten_subtype(key, objects)) # pylint: disable=protected-access + return result + + @classmethod + def _classify(cls, response, objects): + """Check the class _subtype_map for any child classes. + We want to ignore any inherited _subtype_maps. + + :param dict response: The initial data + :param dict objects: The class objects + :returns: The class to be used + :rtype: class + """ + for subtype_key in cls.__dict__.get("_subtype_map", {}).keys(): + subtype_value = None + + if not isinstance(response, ET.Element): + rest_api_response_key = cls._get_rest_key_parts(subtype_key)[-1] + subtype_value = response.get(rest_api_response_key, None) or response.get(subtype_key, None) + else: + subtype_value = xml_key_extractor(subtype_key, cls._attribute_map[subtype_key], response) + if subtype_value: + # Try to match base class. Can be class name only + # (bug to fix in Autorest to support x-ms-discriminator-name) + if cls.__name__ == subtype_value: + return cls + flatten_mapping_type = cls._flatten_subtype(subtype_key, objects) + try: + return objects[flatten_mapping_type[subtype_value]] # type: ignore + except KeyError: + _LOGGER.warning( + "Subtype value %s has no mapping, use base class %s.", + subtype_value, + cls.__name__, + ) + break + else: + _LOGGER.warning("Discriminator %s is absent or null, use base class %s.", subtype_key, cls.__name__) + break + return cls + + @classmethod + def _get_rest_key_parts(cls, attr_key): + """Get the RestAPI key of this attr, split it and decode part + :param str attr_key: Attribute key must be in attribute_map. + :returns: A list of RestAPI part + :rtype: list + """ + rest_split_key = _FLATTEN.split(cls._attribute_map[attr_key]["key"]) + return [_decode_attribute_map_key(key_part) for key_part in rest_split_key] + + +def _decode_attribute_map_key(key): + """This decode a key in an _attribute_map to the actual key we want to look at + inside the received data. + + :param str key: A key string from the generated code + :returns: The decoded key + :rtype: str + """ + return key.replace("\\.", ".") + + +class Serializer: # pylint: disable=too-many-public-methods + """Request object model serializer.""" + + basic_types = {str: "str", int: "int", bool: "bool", float: "float"} + + _xml_basic_types_serializers = {"bool": lambda x: str(x).lower()} + days = {0: "Mon", 1: "Tue", 2: "Wed", 3: "Thu", 4: "Fri", 5: "Sat", 6: "Sun"} + months = { + 1: "Jan", + 2: "Feb", + 3: "Mar", + 4: "Apr", + 5: "May", + 6: "Jun", + 7: "Jul", + 8: "Aug", + 9: "Sep", + 10: "Oct", + 11: "Nov", + 12: "Dec", + } + validation = { + "min_length": lambda x, y: len(x) < y, + "max_length": lambda x, y: len(x) > y, + "minimum": lambda x, y: x < y, + "maximum": lambda x, y: x > y, + "minimum_ex": lambda x, y: x <= y, + "maximum_ex": lambda x, y: x >= y, + "min_items": lambda x, y: len(x) < y, + "max_items": lambda x, y: len(x) > y, + "pattern": lambda x, y: not re.match(y, x, re.UNICODE), + "unique": lambda x, y: len(x) != len(set(x)), + "multiple": lambda x, y: x % y != 0, + } + + def __init__(self, classes: Optional[Mapping[str, type]] = None) -> None: + self.serialize_type = { + "iso-8601": Serializer.serialize_iso, + "rfc-1123": Serializer.serialize_rfc, + "unix-time": Serializer.serialize_unix, + "duration": Serializer.serialize_duration, + "date": Serializer.serialize_date, + "time": Serializer.serialize_time, + "decimal": Serializer.serialize_decimal, + "long": Serializer.serialize_long, + "bytearray": Serializer.serialize_bytearray, + "base64": Serializer.serialize_base64, + "object": self.serialize_object, + "[]": self.serialize_iter, + "{}": self.serialize_dict, + } + self.dependencies: Dict[str, type] = dict(classes) if classes else {} + self.key_transformer = full_restapi_key_transformer + self.client_side_validation = True + + def _serialize( # pylint: disable=too-many-nested-blocks, too-many-branches, too-many-statements, too-many-locals + self, target_obj, data_type=None, **kwargs + ): + """Serialize data into a string according to type. + + :param object target_obj: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str, dict + :raises SerializationError: if serialization fails. + :returns: The serialized data. + """ + key_transformer = kwargs.get("key_transformer", self.key_transformer) + keep_readonly = kwargs.get("keep_readonly", False) + if target_obj is None: + return None + + attr_name = None + class_name = target_obj.__class__.__name__ + + if data_type: + return self.serialize_data(target_obj, data_type, **kwargs) + + if not hasattr(target_obj, "_attribute_map"): + data_type = type(target_obj).__name__ + if data_type in self.basic_types.values(): + return self.serialize_data(target_obj, data_type, **kwargs) + + # Force "is_xml" kwargs if we detect a XML model + try: + is_xml_model_serialization = kwargs["is_xml"] + except KeyError: + is_xml_model_serialization = kwargs.setdefault("is_xml", target_obj.is_xml_model()) + + serialized = {} + if is_xml_model_serialization: + serialized = target_obj._create_xml_node() # pylint: disable=protected-access + try: + attributes = target_obj._attribute_map # pylint: disable=protected-access + for attr, attr_desc in attributes.items(): + attr_name = attr + if not keep_readonly and target_obj._validation.get( # pylint: disable=protected-access + attr_name, {} + ).get("readonly", False): + continue + + if attr_name == "additional_properties" and attr_desc["key"] == "": + if target_obj.additional_properties is not None: + serialized.update(target_obj.additional_properties) + continue + try: + + orig_attr = getattr(target_obj, attr) + if is_xml_model_serialization: + pass # Don't provide "transformer" for XML for now. Keep "orig_attr" + else: # JSON + keys, orig_attr = key_transformer(attr, attr_desc.copy(), orig_attr) + keys = keys if isinstance(keys, list) else [keys] + + kwargs["serialization_ctxt"] = attr_desc + new_attr = self.serialize_data(orig_attr, attr_desc["type"], **kwargs) + + if is_xml_model_serialization: + xml_desc = attr_desc.get("xml", {}) + xml_name = xml_desc.get("name", attr_desc["key"]) + xml_prefix = xml_desc.get("prefix", None) + xml_ns = xml_desc.get("ns", None) + if xml_desc.get("attr", False): + if xml_ns: + ET.register_namespace(xml_prefix, xml_ns) + xml_name = "{{{}}}{}".format(xml_ns, xml_name) + serialized.set(xml_name, new_attr) # type: ignore + continue + if xml_desc.get("text", False): + serialized.text = new_attr # type: ignore + continue + if isinstance(new_attr, list): + serialized.extend(new_attr) # type: ignore + elif isinstance(new_attr, ET.Element): + # If the down XML has no XML/Name, + # we MUST replace the tag with the local tag. But keeping the namespaces. + if "name" not in getattr(orig_attr, "_xml_map", {}): + splitted_tag = new_attr.tag.split("}") + if len(splitted_tag) == 2: # Namespace + new_attr.tag = "}".join([splitted_tag[0], xml_name]) + else: + new_attr.tag = xml_name + serialized.append(new_attr) # type: ignore + else: # That's a basic type + # Integrate namespace if necessary + local_node = _create_xml_node(xml_name, xml_prefix, xml_ns) + local_node.text = str(new_attr) + serialized.append(local_node) # type: ignore + else: # JSON + for k in reversed(keys): # type: ignore + new_attr = {k: new_attr} + + _new_attr = new_attr + _serialized = serialized + for k in keys: # type: ignore + if k not in _serialized: + _serialized.update(_new_attr) # type: ignore + _new_attr = _new_attr[k] # type: ignore + _serialized = _serialized[k] + except ValueError as err: + if isinstance(err, SerializationError): + raise + + except (AttributeError, KeyError, TypeError) as err: + msg = "Attribute {} in object {} cannot be serialized.\n{}".format(attr_name, class_name, str(target_obj)) + raise SerializationError(msg) from err + return serialized + + def body(self, data, data_type, **kwargs): + """Serialize data intended for a request body. + + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: dict + :raises SerializationError: if serialization fails. + :raises ValueError: if data is None + :returns: The serialized request body + """ + + # Just in case this is a dict + internal_data_type_str = data_type.strip("[]{}") + internal_data_type = self.dependencies.get(internal_data_type_str, None) + try: + is_xml_model_serialization = kwargs["is_xml"] + except KeyError: + if internal_data_type and issubclass(internal_data_type, Model): + is_xml_model_serialization = kwargs.setdefault("is_xml", internal_data_type.is_xml_model()) + else: + is_xml_model_serialization = False + if internal_data_type and not isinstance(internal_data_type, Enum): + try: + deserializer = Deserializer(self.dependencies) + # Since it's on serialization, it's almost sure that format is not JSON REST + # We're not able to deal with additional properties for now. + deserializer.additional_properties_detection = False + if is_xml_model_serialization: + deserializer.key_extractors = [ # type: ignore + attribute_key_case_insensitive_extractor, + ] + else: + deserializer.key_extractors = [ + rest_key_case_insensitive_extractor, + attribute_key_case_insensitive_extractor, + last_rest_key_case_insensitive_extractor, + ] + data = deserializer._deserialize(data_type, data) # pylint: disable=protected-access + except DeserializationError as err: + raise SerializationError("Unable to build a model: " + str(err)) from err + + return self._serialize(data, data_type, **kwargs) + + def url(self, name, data, data_type, **kwargs): + """Serialize data intended for a URL path. + + :param str name: The name of the URL path parameter. + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str + :returns: The serialized URL path + :raises TypeError: if serialization fails. + :raises ValueError: if data is None + """ + try: + output = self.serialize_data(data, data_type, **kwargs) + if data_type == "bool": + output = json.dumps(output) + + if kwargs.get("skip_quote") is True: + output = str(output) + output = output.replace("{", quote("{")).replace("}", quote("}")) + else: + output = quote(str(output), safe="") + except SerializationError as exc: + raise TypeError("{} must be type {}.".format(name, data_type)) from exc + return output + + def query(self, name, data, data_type, **kwargs): + """Serialize data intended for a URL query. + + :param str name: The name of the query parameter. + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str, list + :raises TypeError: if serialization fails. + :raises ValueError: if data is None + :returns: The serialized query parameter + """ + try: + # Treat the list aside, since we don't want to encode the div separator + if data_type.startswith("["): + internal_data_type = data_type[1:-1] + do_quote = not kwargs.get("skip_quote", False) + return self.serialize_iter(data, internal_data_type, do_quote=do_quote, **kwargs) + + # Not a list, regular serialization + output = self.serialize_data(data, data_type, **kwargs) + if data_type == "bool": + output = json.dumps(output) + if kwargs.get("skip_quote") is True: + output = str(output) + else: + output = quote(str(output), safe="") + except SerializationError as exc: + raise TypeError("{} must be type {}.".format(name, data_type)) from exc + return str(output) + + def header(self, name, data, data_type, **kwargs): + """Serialize data intended for a request header. + + :param str name: The name of the header. + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str + :raises TypeError: if serialization fails. + :raises ValueError: if data is None + :returns: The serialized header + """ + try: + if data_type in ["[str]"]: + data = ["" if d is None else d for d in data] + + output = self.serialize_data(data, data_type, **kwargs) + if data_type == "bool": + output = json.dumps(output) + except SerializationError as exc: + raise TypeError("{} must be type {}.".format(name, data_type)) from exc + return str(output) + + def serialize_data(self, data, data_type, **kwargs): + """Serialize generic data according to supplied data type. + + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :raises AttributeError: if required data is None. + :raises ValueError: if data is None + :raises SerializationError: if serialization fails. + :returns: The serialized data. + :rtype: str, int, float, bool, dict, list + """ + if data is None: + raise ValueError("No value for given attribute") + + try: + if data is CoreNull: + return None + if data_type in self.basic_types.values(): + return self.serialize_basic(data, data_type, **kwargs) + + if data_type in self.serialize_type: + return self.serialize_type[data_type](data, **kwargs) + + # If dependencies is empty, try with current data class + # It has to be a subclass of Enum anyway + enum_type = self.dependencies.get(data_type, data.__class__) + if issubclass(enum_type, Enum): + return Serializer.serialize_enum(data, enum_obj=enum_type) + + iter_type = data_type[0] + data_type[-1] + if iter_type in self.serialize_type: + return self.serialize_type[iter_type](data, data_type[1:-1], **kwargs) + + except (ValueError, TypeError) as err: + msg = "Unable to serialize value: {!r} as type: {!r}." + raise SerializationError(msg.format(data, data_type)) from err + return self._serialize(data, **kwargs) + + @classmethod + def _get_custom_serializers(cls, data_type, **kwargs): # pylint: disable=inconsistent-return-statements + custom_serializer = kwargs.get("basic_types_serializers", {}).get(data_type) + if custom_serializer: + return custom_serializer + if kwargs.get("is_xml", False): + return cls._xml_basic_types_serializers.get(data_type) + + @classmethod + def serialize_basic(cls, data, data_type, **kwargs): + """Serialize basic builting data type. + Serializes objects to str, int, float or bool. + + Possible kwargs: + - basic_types_serializers dict[str, callable] : If set, use the callable as serializer + - is_xml bool : If set, use xml_basic_types_serializers + + :param obj data: Object to be serialized. + :param str data_type: Type of object in the iterable. + :rtype: str, int, float, bool + :return: serialized object + """ + custom_serializer = cls._get_custom_serializers(data_type, **kwargs) + if custom_serializer: + return custom_serializer(data) + if data_type == "str": + return cls.serialize_unicode(data) + return eval(data_type)(data) # nosec # pylint: disable=eval-used + + @classmethod + def serialize_unicode(cls, data): + """Special handling for serializing unicode strings in Py2. + Encode to UTF-8 if unicode, otherwise handle as a str. + + :param str data: Object to be serialized. + :rtype: str + :return: serialized object + """ + try: # If I received an enum, return its value + return data.value + except AttributeError: + pass + + try: + if isinstance(data, unicode): # type: ignore + # Don't change it, JSON and XML ElementTree are totally able + # to serialize correctly u'' strings + return data + except NameError: + return str(data) + return str(data) + + def serialize_iter(self, data, iter_type, div=None, **kwargs): + """Serialize iterable. + + Supported kwargs: + - serialization_ctxt dict : The current entry of _attribute_map, or same format. + serialization_ctxt['type'] should be same as data_type. + - is_xml bool : If set, serialize as XML + + :param list data: Object to be serialized. + :param str iter_type: Type of object in the iterable. + :param str div: If set, this str will be used to combine the elements + in the iterable into a combined string. Default is 'None'. + Defaults to False. + :rtype: list, str + :return: serialized iterable + """ + if isinstance(data, str): + raise SerializationError("Refuse str type as a valid iter type.") + + serialization_ctxt = kwargs.get("serialization_ctxt", {}) + is_xml = kwargs.get("is_xml", False) + + serialized = [] + for d in data: + try: + serialized.append(self.serialize_data(d, iter_type, **kwargs)) + except ValueError as err: + if isinstance(err, SerializationError): + raise + serialized.append(None) + + if kwargs.get("do_quote", False): + serialized = ["" if s is None else quote(str(s), safe="") for s in serialized] + + if div: + serialized = ["" if s is None else str(s) for s in serialized] + serialized = div.join(serialized) + + if "xml" in serialization_ctxt or is_xml: + # XML serialization is more complicated + xml_desc = serialization_ctxt.get("xml", {}) + xml_name = xml_desc.get("name") + if not xml_name: + xml_name = serialization_ctxt["key"] + + # Create a wrap node if necessary (use the fact that Element and list have "append") + is_wrapped = xml_desc.get("wrapped", False) + node_name = xml_desc.get("itemsName", xml_name) + if is_wrapped: + final_result = _create_xml_node(xml_name, xml_desc.get("prefix", None), xml_desc.get("ns", None)) + else: + final_result = [] + # All list elements to "local_node" + for el in serialized: + if isinstance(el, ET.Element): + el_node = el + else: + el_node = _create_xml_node(node_name, xml_desc.get("prefix", None), xml_desc.get("ns", None)) + if el is not None: # Otherwise it writes "None" :-p + el_node.text = str(el) + final_result.append(el_node) + return final_result + return serialized + + def serialize_dict(self, attr, dict_type, **kwargs): + """Serialize a dictionary of objects. + + :param dict attr: Object to be serialized. + :param str dict_type: Type of object in the dictionary. + :rtype: dict + :return: serialized dictionary + """ + serialization_ctxt = kwargs.get("serialization_ctxt", {}) + serialized = {} + for key, value in attr.items(): + try: + serialized[self.serialize_unicode(key)] = self.serialize_data(value, dict_type, **kwargs) + except ValueError as err: + if isinstance(err, SerializationError): + raise + serialized[self.serialize_unicode(key)] = None + + if "xml" in serialization_ctxt: + # XML serialization is more complicated + xml_desc = serialization_ctxt["xml"] + xml_name = xml_desc["name"] + + final_result = _create_xml_node(xml_name, xml_desc.get("prefix", None), xml_desc.get("ns", None)) + for key, value in serialized.items(): + ET.SubElement(final_result, key).text = value + return final_result + + return serialized + + def serialize_object(self, attr, **kwargs): # pylint: disable=too-many-return-statements + """Serialize a generic object. + This will be handled as a dictionary. If object passed in is not + a basic type (str, int, float, dict, list) it will simply be + cast to str. + + :param dict attr: Object to be serialized. + :rtype: dict or str + :return: serialized object + """ + if attr is None: + return None + if isinstance(attr, ET.Element): + return attr + obj_type = type(attr) + if obj_type in self.basic_types: + return self.serialize_basic(attr, self.basic_types[obj_type], **kwargs) + if obj_type is _long_type: + return self.serialize_long(attr) + if obj_type is str: + return self.serialize_unicode(attr) + if obj_type is datetime.datetime: + return self.serialize_iso(attr) + if obj_type is datetime.date: + return self.serialize_date(attr) + if obj_type is datetime.time: + return self.serialize_time(attr) + if obj_type is datetime.timedelta: + return self.serialize_duration(attr) + if obj_type is decimal.Decimal: + return self.serialize_decimal(attr) + + # If it's a model or I know this dependency, serialize as a Model + if obj_type in self.dependencies.values() or isinstance(attr, Model): + return self._serialize(attr) + + if obj_type == dict: + serialized = {} + for key, value in attr.items(): + try: + serialized[self.serialize_unicode(key)] = self.serialize_object(value, **kwargs) + except ValueError: + serialized[self.serialize_unicode(key)] = None + return serialized + + if obj_type == list: + serialized = [] + for obj in attr: + try: + serialized.append(self.serialize_object(obj, **kwargs)) + except ValueError: + pass + return serialized + return str(attr) + + @staticmethod + def serialize_enum(attr, enum_obj=None): + try: + result = attr.value + except AttributeError: + result = attr + try: + enum_obj(result) # type: ignore + return result + except ValueError as exc: + for enum_value in enum_obj: # type: ignore + if enum_value.value.lower() == str(attr).lower(): + return enum_value.value + error = "{!r} is not valid value for enum {!r}" + raise SerializationError(error.format(attr, enum_obj)) from exc + + @staticmethod + def serialize_bytearray(attr, **kwargs): # pylint: disable=unused-argument + """Serialize bytearray into base-64 string. + + :param str attr: Object to be serialized. + :rtype: str + :return: serialized base64 + """ + return b64encode(attr).decode() + + @staticmethod + def serialize_base64(attr, **kwargs): # pylint: disable=unused-argument + """Serialize str into base-64 string. + + :param str attr: Object to be serialized. + :rtype: str + :return: serialized base64 + """ + encoded = b64encode(attr).decode("ascii") + return encoded.strip("=").replace("+", "-").replace("/", "_") + + @staticmethod + def serialize_decimal(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Decimal object to float. + + :param decimal attr: Object to be serialized. + :rtype: float + :return: serialized decimal + """ + return float(attr) + + @staticmethod + def serialize_long(attr, **kwargs): # pylint: disable=unused-argument + """Serialize long (Py2) or int (Py3). + + :param int attr: Object to be serialized. + :rtype: int/long + :return: serialized long + """ + return _long_type(attr) + + @staticmethod + def serialize_date(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Date object into ISO-8601 formatted string. + + :param Date attr: Object to be serialized. + :rtype: str + :return: serialized date + """ + if isinstance(attr, str): + attr = isodate.parse_date(attr) + t = "{:04}-{:02}-{:02}".format(attr.year, attr.month, attr.day) + return t + + @staticmethod + def serialize_time(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Time object into ISO-8601 formatted string. + + :param datetime.time attr: Object to be serialized. + :rtype: str + :return: serialized time + """ + if isinstance(attr, str): + attr = isodate.parse_time(attr) + t = "{:02}:{:02}:{:02}".format(attr.hour, attr.minute, attr.second) + if attr.microsecond: + t += ".{:02}".format(attr.microsecond) + return t + + @staticmethod + def serialize_duration(attr, **kwargs): # pylint: disable=unused-argument + """Serialize TimeDelta object into ISO-8601 formatted string. + + :param TimeDelta attr: Object to be serialized. + :rtype: str + :return: serialized duration + """ + if isinstance(attr, str): + attr = isodate.parse_duration(attr) + return isodate.duration_isoformat(attr) + + @staticmethod + def serialize_rfc(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Datetime object into RFC-1123 formatted string. + + :param Datetime attr: Object to be serialized. + :rtype: str + :raises TypeError: if format invalid. + :return: serialized rfc + """ + try: + if not attr.tzinfo: + _LOGGER.warning("Datetime with no tzinfo will be considered UTC.") + utc = attr.utctimetuple() + except AttributeError as exc: + raise TypeError("RFC1123 object must be valid Datetime object.") from exc + + return "{}, {:02} {} {:04} {:02}:{:02}:{:02} GMT".format( + Serializer.days[utc.tm_wday], + utc.tm_mday, + Serializer.months[utc.tm_mon], + utc.tm_year, + utc.tm_hour, + utc.tm_min, + utc.tm_sec, + ) + + @staticmethod + def serialize_iso(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Datetime object into ISO-8601 formatted string. + + :param Datetime attr: Object to be serialized. + :rtype: str + :raises SerializationError: if format invalid. + :return: serialized iso + """ + if isinstance(attr, str): + attr = isodate.parse_datetime(attr) + try: + if not attr.tzinfo: + _LOGGER.warning("Datetime with no tzinfo will be considered UTC.") + utc = attr.utctimetuple() + if utc.tm_year > 9999 or utc.tm_year < 1: + raise OverflowError("Hit max or min date") + + microseconds = str(attr.microsecond).rjust(6, "0").rstrip("0").ljust(3, "0") + if microseconds: + microseconds = "." + microseconds + date = "{:04}-{:02}-{:02}T{:02}:{:02}:{:02}".format( + utc.tm_year, utc.tm_mon, utc.tm_mday, utc.tm_hour, utc.tm_min, utc.tm_sec + ) + return date + microseconds + "Z" + except (ValueError, OverflowError) as err: + msg = "Unable to serialize datetime object." + raise SerializationError(msg) from err + except AttributeError as err: + msg = "ISO-8601 object must be valid Datetime object." + raise TypeError(msg) from err + + @staticmethod + def serialize_unix(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Datetime object into IntTime format. + This is represented as seconds. + + :param Datetime attr: Object to be serialized. + :rtype: int + :raises SerializationError: if format invalid + :return: serialied unix + """ + if isinstance(attr, int): + return attr + try: + if not attr.tzinfo: + _LOGGER.warning("Datetime with no tzinfo will be considered UTC.") + return int(calendar.timegm(attr.utctimetuple())) + except AttributeError as exc: + raise TypeError("Unix time object must be valid Datetime object.") from exc + + +def rest_key_extractor(attr, attr_desc, data): # pylint: disable=unused-argument + key = attr_desc["key"] + working_data = data + + while "." in key: + # Need the cast, as for some reasons "split" is typed as list[str | Any] + dict_keys = cast(List[str], _FLATTEN.split(key)) + if len(dict_keys) == 1: + key = _decode_attribute_map_key(dict_keys[0]) + break + working_key = _decode_attribute_map_key(dict_keys[0]) + working_data = working_data.get(working_key, data) + if working_data is None: + # If at any point while following flatten JSON path see None, it means + # that all properties under are None as well + return None + key = ".".join(dict_keys[1:]) + + return working_data.get(key) + + +def rest_key_case_insensitive_extractor( # pylint: disable=unused-argument, inconsistent-return-statements + attr, attr_desc, data +): + key = attr_desc["key"] + working_data = data + + while "." in key: + dict_keys = _FLATTEN.split(key) + if len(dict_keys) == 1: + key = _decode_attribute_map_key(dict_keys[0]) + break + working_key = _decode_attribute_map_key(dict_keys[0]) + working_data = attribute_key_case_insensitive_extractor(working_key, None, working_data) + if working_data is None: + # If at any point while following flatten JSON path see None, it means + # that all properties under are None as well + return None + key = ".".join(dict_keys[1:]) + + if working_data: + return attribute_key_case_insensitive_extractor(key, None, working_data) + + +def last_rest_key_extractor(attr, attr_desc, data): # pylint: disable=unused-argument + """Extract the attribute in "data" based on the last part of the JSON path key. + + :param str attr: The attribute to extract + :param dict attr_desc: The attribute description + :param dict data: The data to extract from + :rtype: object + :returns: The extracted attribute + """ + key = attr_desc["key"] + dict_keys = _FLATTEN.split(key) + return attribute_key_extractor(dict_keys[-1], None, data) + + +def last_rest_key_case_insensitive_extractor(attr, attr_desc, data): # pylint: disable=unused-argument + """Extract the attribute in "data" based on the last part of the JSON path key. + + This is the case insensitive version of "last_rest_key_extractor" + :param str attr: The attribute to extract + :param dict attr_desc: The attribute description + :param dict data: The data to extract from + :rtype: object + :returns: The extracted attribute + """ + key = attr_desc["key"] + dict_keys = _FLATTEN.split(key) + return attribute_key_case_insensitive_extractor(dict_keys[-1], None, data) + + +def attribute_key_extractor(attr, _, data): + return data.get(attr) + + +def attribute_key_case_insensitive_extractor(attr, _, data): + found_key = None + lower_attr = attr.lower() + for key in data: + if lower_attr == key.lower(): + found_key = key + break + + return data.get(found_key) + + +def _extract_name_from_internal_type(internal_type): + """Given an internal type XML description, extract correct XML name with namespace. + + :param dict internal_type: An model type + :rtype: tuple + :returns: A tuple XML name + namespace dict + """ + internal_type_xml_map = getattr(internal_type, "_xml_map", {}) + xml_name = internal_type_xml_map.get("name", internal_type.__name__) + xml_ns = internal_type_xml_map.get("ns", None) + if xml_ns: + xml_name = "{{{}}}{}".format(xml_ns, xml_name) + return xml_name + + +def xml_key_extractor(attr, attr_desc, data): # pylint: disable=unused-argument,too-many-return-statements + if isinstance(data, dict): + return None + + # Test if this model is XML ready first + if not isinstance(data, ET.Element): + return None + + xml_desc = attr_desc.get("xml", {}) + xml_name = xml_desc.get("name", attr_desc["key"]) + + # Look for a children + is_iter_type = attr_desc["type"].startswith("[") + is_wrapped = xml_desc.get("wrapped", False) + internal_type = attr_desc.get("internalType", None) + internal_type_xml_map = getattr(internal_type, "_xml_map", {}) + + # Integrate namespace if necessary + xml_ns = xml_desc.get("ns", internal_type_xml_map.get("ns", None)) + if xml_ns: + xml_name = "{{{}}}{}".format(xml_ns, xml_name) + + # If it's an attribute, that's simple + if xml_desc.get("attr", False): + return data.get(xml_name) + + # If it's x-ms-text, that's simple too + if xml_desc.get("text", False): + return data.text + + # Scenario where I take the local name: + # - Wrapped node + # - Internal type is an enum (considered basic types) + # - Internal type has no XML/Name node + if is_wrapped or (internal_type and (issubclass(internal_type, Enum) or "name" not in internal_type_xml_map)): + children = data.findall(xml_name) + # If internal type has a local name and it's not a list, I use that name + elif not is_iter_type and internal_type and "name" in internal_type_xml_map: + xml_name = _extract_name_from_internal_type(internal_type) + children = data.findall(xml_name) + # That's an array + else: + if internal_type: # Complex type, ignore itemsName and use the complex type name + items_name = _extract_name_from_internal_type(internal_type) + else: + items_name = xml_desc.get("itemsName", xml_name) + children = data.findall(items_name) + + if len(children) == 0: + if is_iter_type: + if is_wrapped: + return None # is_wrapped no node, we want None + return [] # not wrapped, assume empty list + return None # Assume it's not there, maybe an optional node. + + # If is_iter_type and not wrapped, return all found children + if is_iter_type: + if not is_wrapped: + return children + # Iter and wrapped, should have found one node only (the wrap one) + if len(children) != 1: + raise DeserializationError( + "Tried to deserialize an array not wrapped, and found several nodes '{}'. Maybe you should declare this array as wrapped?".format( + xml_name + ) + ) + return list(children[0]) # Might be empty list and that's ok. + + # Here it's not a itertype, we should have found one element only or empty + if len(children) > 1: + raise DeserializationError("Find several XML '{}' where it was not expected".format(xml_name)) + return children[0] + + +class Deserializer: + """Response object model deserializer. + + :param dict classes: Class type dictionary for deserializing complex types. + :ivar list key_extractors: Ordered list of extractors to be used by this deserializer. + """ + + basic_types = {str: "str", int: "int", bool: "bool", float: "float"} + + valid_date = re.compile(r"\d{4}[-]\d{2}[-]\d{2}T\d{2}:\d{2}:\d{2}\.?\d*Z?[-+]?[\d{2}]?:?[\d{2}]?") + + def __init__(self, classes: Optional[Mapping[str, type]] = None) -> None: + self.deserialize_type = { + "iso-8601": Deserializer.deserialize_iso, + "rfc-1123": Deserializer.deserialize_rfc, + "unix-time": Deserializer.deserialize_unix, + "duration": Deserializer.deserialize_duration, + "date": Deserializer.deserialize_date, + "time": Deserializer.deserialize_time, + "decimal": Deserializer.deserialize_decimal, + "long": Deserializer.deserialize_long, + "bytearray": Deserializer.deserialize_bytearray, + "base64": Deserializer.deserialize_base64, + "object": self.deserialize_object, + "[]": self.deserialize_iter, + "{}": self.deserialize_dict, + } + self.deserialize_expected_types = { + "duration": (isodate.Duration, datetime.timedelta), + "iso-8601": (datetime.datetime), + } + self.dependencies: Dict[str, type] = dict(classes) if classes else {} + self.key_extractors = [rest_key_extractor, xml_key_extractor] + # Additional properties only works if the "rest_key_extractor" is used to + # extract the keys. Making it to work whatever the key extractor is too much + # complicated, with no real scenario for now. + # So adding a flag to disable additional properties detection. This flag should be + # used if your expect the deserialization to NOT come from a JSON REST syntax. + # Otherwise, result are unexpected + self.additional_properties_detection = True + + def __call__(self, target_obj, response_data, content_type=None): + """Call the deserializer to process a REST response. + + :param str target_obj: Target data type to deserialize to. + :param requests.Response response_data: REST response object. + :param str content_type: Swagger "produces" if available. + :raises DeserializationError: if deserialization fails. + :return: Deserialized object. + :rtype: object + """ + data = self._unpack_content(response_data, content_type) + return self._deserialize(target_obj, data) + + def _deserialize(self, target_obj, data): # pylint: disable=inconsistent-return-statements + """Call the deserializer on a model. + + Data needs to be already deserialized as JSON or XML ElementTree + + :param str target_obj: Target data type to deserialize to. + :param object data: Object to deserialize. + :raises DeserializationError: if deserialization fails. + :return: Deserialized object. + :rtype: object + """ + # This is already a model, go recursive just in case + if hasattr(data, "_attribute_map"): + constants = [name for name, config in getattr(data, "_validation", {}).items() if config.get("constant")] + try: + for attr, mapconfig in data._attribute_map.items(): # pylint: disable=protected-access + if attr in constants: + continue + value = getattr(data, attr) + if value is None: + continue + local_type = mapconfig["type"] + internal_data_type = local_type.strip("[]{}") + if internal_data_type not in self.dependencies or isinstance(internal_data_type, Enum): + continue + setattr(data, attr, self._deserialize(local_type, value)) + return data + except AttributeError: + return + + response, class_name = self._classify_target(target_obj, data) + + if isinstance(response, str): + return self.deserialize_data(data, response) + if isinstance(response, type) and issubclass(response, Enum): + return self.deserialize_enum(data, response) + + if data is None or data is CoreNull: + return data + try: + attributes = response._attribute_map # type: ignore # pylint: disable=protected-access + d_attrs = {} + for attr, attr_desc in attributes.items(): + # Check empty string. If it's not empty, someone has a real "additionalProperties"... + if attr == "additional_properties" and attr_desc["key"] == "": + continue + raw_value = None + # Enhance attr_desc with some dynamic data + attr_desc = attr_desc.copy() # Do a copy, do not change the real one + internal_data_type = attr_desc["type"].strip("[]{}") + if internal_data_type in self.dependencies: + attr_desc["internalType"] = self.dependencies[internal_data_type] + + for key_extractor in self.key_extractors: + found_value = key_extractor(attr, attr_desc, data) + if found_value is not None: + if raw_value is not None and raw_value != found_value: + msg = ( + "Ignoring extracted value '%s' from %s for key '%s'" + " (duplicate extraction, follow extractors order)" + ) + _LOGGER.warning(msg, found_value, key_extractor, attr) + continue + raw_value = found_value + + value = self.deserialize_data(raw_value, attr_desc["type"]) + d_attrs[attr] = value + except (AttributeError, TypeError, KeyError) as err: + msg = "Unable to deserialize to object: " + class_name # type: ignore + raise DeserializationError(msg) from err + additional_properties = self._build_additional_properties(attributes, data) + return self._instantiate_model(response, d_attrs, additional_properties) + + def _build_additional_properties(self, attribute_map, data): + if not self.additional_properties_detection: + return None + if "additional_properties" in attribute_map and attribute_map.get("additional_properties", {}).get("key") != "": + # Check empty string. If it's not empty, someone has a real "additionalProperties" + return None + if isinstance(data, ET.Element): + data = {el.tag: el.text for el in data} + + known_keys = { + _decode_attribute_map_key(_FLATTEN.split(desc["key"])[0]) + for desc in attribute_map.values() + if desc["key"] != "" + } + present_keys = set(data.keys()) + missing_keys = present_keys - known_keys + return {key: data[key] for key in missing_keys} + + def _classify_target(self, target, data): + """Check to see whether the deserialization target object can + be classified into a subclass. + Once classification has been determined, initialize object. + + :param str target: The target object type to deserialize to. + :param str/dict data: The response data to deserialize. + :return: The classified target object and its class name. + :rtype: tuple + """ + if target is None: + return None, None + + if isinstance(target, str): + try: + target = self.dependencies[target] + except KeyError: + return target, target + + try: + target = target._classify(data, self.dependencies) # type: ignore # pylint: disable=protected-access + except AttributeError: + pass # Target is not a Model, no classify + return target, target.__class__.__name__ # type: ignore + + def failsafe_deserialize(self, target_obj, data, content_type=None): + """Ignores any errors encountered in deserialization, + and falls back to not deserializing the object. Recommended + for use in error deserialization, as we want to return the + HttpResponseError to users, and not have them deal with + a deserialization error. + + :param str target_obj: The target object type to deserialize to. + :param str/dict data: The response data to deserialize. + :param str content_type: Swagger "produces" if available. + :return: Deserialized object. + :rtype: object + """ + try: + return self(target_obj, data, content_type=content_type) + except: # pylint: disable=bare-except + _LOGGER.debug( + "Ran into a deserialization error. Ignoring since this is failsafe deserialization", exc_info=True + ) + return None + + @staticmethod + def _unpack_content(raw_data, content_type=None): + """Extract the correct structure for deserialization. + + If raw_data is a PipelineResponse, try to extract the result of RawDeserializer. + if we can't, raise. Your Pipeline should have a RawDeserializer. + + If not a pipeline response and raw_data is bytes or string, use content-type + to decode it. If no content-type, try JSON. + + If raw_data is something else, bypass all logic and return it directly. + + :param obj raw_data: Data to be processed. + :param str content_type: How to parse if raw_data is a string/bytes. + :raises JSONDecodeError: If JSON is requested and parsing is impossible. + :raises UnicodeDecodeError: If bytes is not UTF8 + :rtype: object + :return: Unpacked content. + """ + # Assume this is enough to detect a Pipeline Response without importing it + context = getattr(raw_data, "context", {}) + if context: + if RawDeserializer.CONTEXT_NAME in context: + return context[RawDeserializer.CONTEXT_NAME] + raise ValueError("This pipeline didn't have the RawDeserializer policy; can't deserialize") + + # Assume this is enough to recognize universal_http.ClientResponse without importing it + if hasattr(raw_data, "body"): + return RawDeserializer.deserialize_from_http_generics(raw_data.text(), raw_data.headers) + + # Assume this enough to recognize requests.Response without importing it. + if hasattr(raw_data, "_content_consumed"): + return RawDeserializer.deserialize_from_http_generics(raw_data.text, raw_data.headers) + + if isinstance(raw_data, (str, bytes)) or hasattr(raw_data, "read"): + return RawDeserializer.deserialize_from_text(raw_data, content_type) # type: ignore + return raw_data + + def _instantiate_model(self, response, attrs, additional_properties=None): + """Instantiate a response model passing in deserialized args. + + :param Response response: The response model class. + :param dict attrs: The deserialized response attributes. + :param dict additional_properties: Additional properties to be set. + :rtype: Response + :return: The instantiated response model. + """ + if callable(response): + subtype = getattr(response, "_subtype_map", {}) + try: + readonly = [ + k + for k, v in response._validation.items() # pylint: disable=protected-access # type: ignore + if v.get("readonly") + ] + const = [ + k + for k, v in response._validation.items() # pylint: disable=protected-access # type: ignore + if v.get("constant") + ] + kwargs = {k: v for k, v in attrs.items() if k not in subtype and k not in readonly + const} + response_obj = response(**kwargs) + for attr in readonly: + setattr(response_obj, attr, attrs.get(attr)) + if additional_properties: + response_obj.additional_properties = additional_properties # type: ignore + return response_obj + except TypeError as err: + msg = "Unable to deserialize {} into model {}. ".format(kwargs, response) # type: ignore + raise DeserializationError(msg + str(err)) from err + else: + try: + for attr, value in attrs.items(): + setattr(response, attr, value) + return response + except Exception as exp: + msg = "Unable to populate response model. " + msg += "Type: {}, Error: {}".format(type(response), exp) + raise DeserializationError(msg) from exp + + def deserialize_data(self, data, data_type): # pylint: disable=too-many-return-statements + """Process data for deserialization according to data type. + + :param str data: The response string to be deserialized. + :param str data_type: The type to deserialize to. + :raises DeserializationError: if deserialization fails. + :return: Deserialized object. + :rtype: object + """ + if data is None: + return data + + try: + if not data_type: + return data + if data_type in self.basic_types.values(): + return self.deserialize_basic(data, data_type) + if data_type in self.deserialize_type: + if isinstance(data, self.deserialize_expected_types.get(data_type, tuple())): + return data + + is_a_text_parsing_type = lambda x: x not in [ # pylint: disable=unnecessary-lambda-assignment + "object", + "[]", + r"{}", + ] + if isinstance(data, ET.Element) and is_a_text_parsing_type(data_type) and not data.text: + return None + data_val = self.deserialize_type[data_type](data) + return data_val + + iter_type = data_type[0] + data_type[-1] + if iter_type in self.deserialize_type: + return self.deserialize_type[iter_type](data, data_type[1:-1]) + + obj_type = self.dependencies[data_type] + if issubclass(obj_type, Enum): + if isinstance(data, ET.Element): + data = data.text + return self.deserialize_enum(data, obj_type) + + except (ValueError, TypeError, AttributeError) as err: + msg = "Unable to deserialize response data." + msg += " Data: {}, {}".format(data, data_type) + raise DeserializationError(msg) from err + return self._deserialize(obj_type, data) + + def deserialize_iter(self, attr, iter_type): + """Deserialize an iterable. + + :param list attr: Iterable to be deserialized. + :param str iter_type: The type of object in the iterable. + :return: Deserialized iterable. + :rtype: list + """ + if attr is None: + return None + if isinstance(attr, ET.Element): # If I receive an element here, get the children + attr = list(attr) + if not isinstance(attr, (list, set)): + raise DeserializationError("Cannot deserialize as [{}] an object of type {}".format(iter_type, type(attr))) + return [self.deserialize_data(a, iter_type) for a in attr] + + def deserialize_dict(self, attr, dict_type): + """Deserialize a dictionary. + + :param dict/list attr: Dictionary to be deserialized. Also accepts + a list of key, value pairs. + :param str dict_type: The object type of the items in the dictionary. + :return: Deserialized dictionary. + :rtype: dict + """ + if isinstance(attr, list): + return {x["key"]: self.deserialize_data(x["value"], dict_type) for x in attr} + + if isinstance(attr, ET.Element): + # Transform value into {"Key": "value"} + attr = {el.tag: el.text for el in attr} + return {k: self.deserialize_data(v, dict_type) for k, v in attr.items()} + + def deserialize_object(self, attr, **kwargs): # pylint: disable=too-many-return-statements + """Deserialize a generic object. + This will be handled as a dictionary. + + :param dict attr: Dictionary to be deserialized. + :return: Deserialized object. + :rtype: dict + :raises TypeError: if non-builtin datatype encountered. + """ + if attr is None: + return None + if isinstance(attr, ET.Element): + # Do no recurse on XML, just return the tree as-is + return attr + if isinstance(attr, str): + return self.deserialize_basic(attr, "str") + obj_type = type(attr) + if obj_type in self.basic_types: + return self.deserialize_basic(attr, self.basic_types[obj_type]) + if obj_type is _long_type: + return self.deserialize_long(attr) + + if obj_type == dict: + deserialized = {} + for key, value in attr.items(): + try: + deserialized[key] = self.deserialize_object(value, **kwargs) + except ValueError: + deserialized[key] = None + return deserialized + + if obj_type == list: + deserialized = [] + for obj in attr: + try: + deserialized.append(self.deserialize_object(obj, **kwargs)) + except ValueError: + pass + return deserialized + + error = "Cannot deserialize generic object with type: " + raise TypeError(error + str(obj_type)) + + def deserialize_basic(self, attr, data_type): # pylint: disable=too-many-return-statements + """Deserialize basic builtin data type from string. + Will attempt to convert to str, int, float and bool. + This function will also accept '1', '0', 'true' and 'false' as + valid bool values. + + :param str attr: response string to be deserialized. + :param str data_type: deserialization data type. + :return: Deserialized basic type. + :rtype: str, int, float or bool + :raises TypeError: if string format is not valid. + """ + # If we're here, data is supposed to be a basic type. + # If it's still an XML node, take the text + if isinstance(attr, ET.Element): + attr = attr.text + if not attr: + if data_type == "str": + # None or '', node is empty string. + return "" + # None or '', node with a strong type is None. + # Don't try to model "empty bool" or "empty int" + return None + + if data_type == "bool": + if attr in [True, False, 1, 0]: + return bool(attr) + if isinstance(attr, str): + if attr.lower() in ["true", "1"]: + return True + if attr.lower() in ["false", "0"]: + return False + raise TypeError("Invalid boolean value: {}".format(attr)) + + if data_type == "str": + return self.deserialize_unicode(attr) + return eval(data_type)(attr) # nosec # pylint: disable=eval-used + + @staticmethod + def deserialize_unicode(data): + """Preserve unicode objects in Python 2, otherwise return data + as a string. + + :param str data: response string to be deserialized. + :return: Deserialized string. + :rtype: str or unicode + """ + # We might be here because we have an enum modeled as string, + # and we try to deserialize a partial dict with enum inside + if isinstance(data, Enum): + return data + + # Consider this is real string + try: + if isinstance(data, unicode): # type: ignore + return data + except NameError: + return str(data) + return str(data) + + @staticmethod + def deserialize_enum(data, enum_obj): + """Deserialize string into enum object. + + If the string is not a valid enum value it will be returned as-is + and a warning will be logged. + + :param str data: Response string to be deserialized. If this value is + None or invalid it will be returned as-is. + :param Enum enum_obj: Enum object to deserialize to. + :return: Deserialized enum object. + :rtype: Enum + """ + if isinstance(data, enum_obj) or data is None: + return data + if isinstance(data, Enum): + data = data.value + if isinstance(data, int): + # Workaround. We might consider remove it in the future. + try: + return list(enum_obj.__members__.values())[data] + except IndexError as exc: + error = "{!r} is not a valid index for enum {!r}" + raise DeserializationError(error.format(data, enum_obj)) from exc + try: + return enum_obj(str(data)) + except ValueError: + for enum_value in enum_obj: + if enum_value.value.lower() == str(data).lower(): + return enum_value + # We don't fail anymore for unknown value, we deserialize as a string + _LOGGER.warning("Deserializer is not able to find %s as valid enum in %s", data, enum_obj) + return Deserializer.deserialize_unicode(data) + + @staticmethod + def deserialize_bytearray(attr): + """Deserialize string into bytearray. + + :param str attr: response string to be deserialized. + :return: Deserialized bytearray + :rtype: bytearray + :raises TypeError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + return bytearray(b64decode(attr)) # type: ignore + + @staticmethod + def deserialize_base64(attr): + """Deserialize base64 encoded string into string. + + :param str attr: response string to be deserialized. + :return: Deserialized base64 string + :rtype: bytearray + :raises TypeError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + padding = "=" * (3 - (len(attr) + 3) % 4) # type: ignore + attr = attr + padding # type: ignore + encoded = attr.replace("-", "+").replace("_", "/") + return b64decode(encoded) + + @staticmethod + def deserialize_decimal(attr): + """Deserialize string into Decimal object. + + :param str attr: response string to be deserialized. + :return: Deserialized decimal + :raises DeserializationError: if string format invalid. + :rtype: decimal + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + return decimal.Decimal(str(attr)) # type: ignore + except decimal.DecimalException as err: + msg = "Invalid decimal {}".format(attr) + raise DeserializationError(msg) from err + + @staticmethod + def deserialize_long(attr): + """Deserialize string into long (Py2) or int (Py3). + + :param str attr: response string to be deserialized. + :return: Deserialized int + :rtype: long or int + :raises ValueError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + return _long_type(attr) # type: ignore + + @staticmethod + def deserialize_duration(attr): + """Deserialize ISO-8601 formatted string into TimeDelta object. + + :param str attr: response string to be deserialized. + :return: Deserialized duration + :rtype: TimeDelta + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + duration = isodate.parse_duration(attr) + except (ValueError, OverflowError, AttributeError) as err: + msg = "Cannot deserialize duration object." + raise DeserializationError(msg) from err + return duration + + @staticmethod + def deserialize_date(attr): + """Deserialize ISO-8601 formatted string into Date object. + + :param str attr: response string to be deserialized. + :return: Deserialized date + :rtype: Date + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + if re.search(r"[^\W\d_]", attr, re.I + re.U): # type: ignore + raise DeserializationError("Date must have only digits and -. Received: %s" % attr) + # This must NOT use defaultmonth/defaultday. Using None ensure this raises an exception. + return isodate.parse_date(attr, defaultmonth=0, defaultday=0) + + @staticmethod + def deserialize_time(attr): + """Deserialize ISO-8601 formatted string into time object. + + :param str attr: response string to be deserialized. + :return: Deserialized time + :rtype: datetime.time + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + if re.search(r"[^\W\d_]", attr, re.I + re.U): # type: ignore + raise DeserializationError("Date must have only digits and -. Received: %s" % attr) + return isodate.parse_time(attr) + + @staticmethod + def deserialize_rfc(attr): + """Deserialize RFC-1123 formatted string into Datetime object. + + :param str attr: response string to be deserialized. + :return: Deserialized RFC datetime + :rtype: Datetime + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + parsed_date = email.utils.parsedate_tz(attr) # type: ignore + date_obj = datetime.datetime( + *parsed_date[:6], tzinfo=datetime.timezone(datetime.timedelta(minutes=(parsed_date[9] or 0) / 60)) + ) + if not date_obj.tzinfo: + date_obj = date_obj.astimezone(tz=TZ_UTC) + except ValueError as err: + msg = "Cannot deserialize to rfc datetime object." + raise DeserializationError(msg) from err + return date_obj + + @staticmethod + def deserialize_iso(attr): + """Deserialize ISO-8601 formatted string into Datetime object. + + :param str attr: response string to be deserialized. + :return: Deserialized ISO datetime + :rtype: Datetime + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + attr = attr.upper() # type: ignore + match = Deserializer.valid_date.match(attr) + if not match: + raise ValueError("Invalid datetime string: " + attr) + + check_decimal = attr.split(".") + if len(check_decimal) > 1: + decimal_str = "" + for digit in check_decimal[1]: + if digit.isdigit(): + decimal_str += digit + else: + break + if len(decimal_str) > 6: + attr = attr.replace(decimal_str, decimal_str[0:6]) + + date_obj = isodate.parse_datetime(attr) + test_utc = date_obj.utctimetuple() + if test_utc.tm_year > 9999 or test_utc.tm_year < 1: + raise OverflowError("Hit max or min date") + except (ValueError, OverflowError, AttributeError) as err: + msg = "Cannot deserialize datetime object." + raise DeserializationError(msg) from err + return date_obj + + @staticmethod + def deserialize_unix(attr): + """Serialize Datetime object into IntTime format. + This is represented as seconds. + + :param int attr: Object to be serialized. + :return: Deserialized datetime + :rtype: Datetime + :raises DeserializationError: if format invalid + """ + if isinstance(attr, ET.Element): + attr = int(attr.text) # type: ignore + try: + attr = int(attr) + date_obj = datetime.datetime.fromtimestamp(attr, TZ_UTC) + except ValueError as err: + msg = "Cannot deserialize to unix datetime object." + raise DeserializationError(msg) from err + return date_obj diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/SecurityAadSwaggerVersionTolerant/securityaadswaggerversiontolerant/_utils/utils.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/SecurityAadSwaggerVersionTolerant/securityaadswaggerversiontolerant/_utils/utils.py new file mode 100644 index 00000000000..39b612f39a9 --- /dev/null +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/SecurityAadSwaggerVersionTolerant/securityaadswaggerversiontolerant/_utils/utils.py @@ -0,0 +1,25 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from abc import ABC +from typing import Generic, TYPE_CHECKING, TypeVar + +if TYPE_CHECKING: + from .serialization import Deserializer, Serializer + + +TClient = TypeVar("TClient") +TConfig = TypeVar("TConfig") + + +class ClientMixinABC(ABC, Generic[TClient, TConfig]): + """DO NOT use this class. It is for internal typing use only.""" + + _client: TClient + _config: TConfig + _serialize: "Serializer" + _deserialize: "Deserializer" diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/SecurityAadSwaggerVersionTolerant/securityaadswaggerversiontolerant/_vendor.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/SecurityAadSwaggerVersionTolerant/securityaadswaggerversiontolerant/_vendor.py deleted file mode 100644 index 4bac3abea25..00000000000 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/SecurityAadSwaggerVersionTolerant/securityaadswaggerversiontolerant/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) AutoRest Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import AutorestSecurityAadConfiguration - -if TYPE_CHECKING: - from azure.core import PipelineClient - - from ._serialization import Deserializer, Serializer - - -class AutorestSecurityAadMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "PipelineClient" - _config: AutorestSecurityAadConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/SecurityAadSwaggerVersionTolerant/securityaadswaggerversiontolerant/aio/_client.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/SecurityAadSwaggerVersionTolerant/securityaadswaggerversiontolerant/aio/_client.py index 9dab62c5002..cc1d5685e5d 100644 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/SecurityAadSwaggerVersionTolerant/securityaadswaggerversiontolerant/aio/_client.py +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/SecurityAadSwaggerVersionTolerant/securityaadswaggerversiontolerant/aio/_client.py @@ -14,7 +14,7 @@ from azure.core.pipeline import policies from azure.core.rest import AsyncHttpResponse, HttpRequest -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import AutorestSecurityAadConfiguration from ._operations import AutorestSecurityAadOperationsMixin diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/SecurityAadSwaggerVersionTolerant/securityaadswaggerversiontolerant/aio/_operations/_operations.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/SecurityAadSwaggerVersionTolerant/securityaadswaggerversiontolerant/aio/_operations/_operations.py index 48ba26ce1bb..86bf11db1de 100644 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/SecurityAadSwaggerVersionTolerant/securityaadswaggerversiontolerant/aio/_operations/_operations.py +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/SecurityAadSwaggerVersionTolerant/securityaadswaggerversiontolerant/aio/_operations/_operations.py @@ -9,6 +9,7 @@ from collections.abc import MutableMapping from typing import Any, Callable, Dict, Optional, TypeVar +from azure.core import AsyncPipelineClient from azure.core.exceptions import ( ClientAuthenticationError, HttpResponseError, @@ -22,13 +23,14 @@ from azure.core.tracing.decorator_async import distributed_trace_async from ..._operations._operations import build_autorest_security_aad_head_request -from .._vendor import AutorestSecurityAadMixinABC +from ..._utils.utils import ClientMixinABC +from .._configuration import AutorestSecurityAadConfiguration T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, AsyncHttpResponse], T, Dict[str, Any]], Any]] -class AutorestSecurityAadOperationsMixin(AutorestSecurityAadMixinABC): +class AutorestSecurityAadOperationsMixin(ClientMixinABC[AsyncPipelineClient, AutorestSecurityAadConfiguration]): @distributed_trace_async async def head(self, **kwargs: Any) -> None: diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/SecurityAadSwaggerVersionTolerant/securityaadswaggerversiontolerant/aio/_vendor.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/SecurityAadSwaggerVersionTolerant/securityaadswaggerversiontolerant/aio/_vendor.py deleted file mode 100644 index 3b07efefdc0..00000000000 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/SecurityAadSwaggerVersionTolerant/securityaadswaggerversiontolerant/aio/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) AutoRest Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import AutorestSecurityAadConfiguration - -if TYPE_CHECKING: - from azure.core import AsyncPipelineClient - - from .._serialization import Deserializer, Serializer - - -class AutorestSecurityAadMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "AsyncPipelineClient" - _config: AutorestSecurityAadConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/SecurityKeySwaggerVersionTolerant/securitykeyswaggerversiontolerant/_client.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/SecurityKeySwaggerVersionTolerant/securitykeyswaggerversiontolerant/_client.py index b6f719f3fcf..f9345349046 100644 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/SecurityKeySwaggerVersionTolerant/securitykeyswaggerversiontolerant/_client.py +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/SecurityKeySwaggerVersionTolerant/securitykeyswaggerversiontolerant/_client.py @@ -17,7 +17,7 @@ from ._configuration import AutorestSecurityKeyConfiguration from ._operations import AutorestSecurityKeyOperationsMixin -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer class AutorestSecurityKey(AutorestSecurityKeyOperationsMixin): # pylint: disable=client-accepts-api-version-keyword diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/SecurityKeySwaggerVersionTolerant/securitykeyswaggerversiontolerant/_operations/_operations.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/SecurityKeySwaggerVersionTolerant/securitykeyswaggerversiontolerant/_operations/_operations.py index caa33af7c51..32eabed4384 100644 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/SecurityKeySwaggerVersionTolerant/securitykeyswaggerversiontolerant/_operations/_operations.py +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/SecurityKeySwaggerVersionTolerant/securitykeyswaggerversiontolerant/_operations/_operations.py @@ -8,6 +8,7 @@ from collections.abc import MutableMapping from typing import Any, Callable, Dict, Optional, TypeVar +from azure.core import PipelineClient from azure.core.exceptions import ( ClientAuthenticationError, HttpResponseError, @@ -20,8 +21,9 @@ from azure.core.rest import HttpRequest, HttpResponse from azure.core.tracing.decorator import distributed_trace -from .._serialization import Serializer -from .._vendor import AutorestSecurityKeyMixinABC +from .._configuration import AutorestSecurityKeyConfiguration +from .._utils.serialization import Serializer +from .._utils.utils import ClientMixinABC T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] @@ -37,7 +39,7 @@ def build_autorest_security_key_head_request(**kwargs: Any) -> HttpRequest: return HttpRequest(method="HEAD", url=_url, **kwargs) -class AutorestSecurityKeyOperationsMixin(AutorestSecurityKeyMixinABC): +class AutorestSecurityKeyOperationsMixin(ClientMixinABC[PipelineClient, AutorestSecurityKeyConfiguration]): @distributed_trace def head(self, **kwargs: Any) -> None: # pylint: disable=inconsistent-return-statements diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/SecurityKeySwaggerVersionTolerant/securitykeyswaggerversiontolerant/_utils/__init__.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/SecurityKeySwaggerVersionTolerant/securitykeyswaggerversiontolerant/_utils/__init__.py new file mode 100644 index 00000000000..0af9b28f660 --- /dev/null +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/SecurityKeySwaggerVersionTolerant/securitykeyswaggerversiontolerant/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/SecurityKeySwaggerVersionTolerant/securitykeyswaggerversiontolerant/_utils/serialization.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/SecurityKeySwaggerVersionTolerant/securitykeyswaggerversiontolerant/_utils/serialization.py new file mode 100644 index 00000000000..f5187701d7b --- /dev/null +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/SecurityKeySwaggerVersionTolerant/securitykeyswaggerversiontolerant/_utils/serialization.py @@ -0,0 +1,2032 @@ +# pylint: disable=line-too-long,useless-suppression,too-many-lines +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +# pyright: reportUnnecessaryTypeIgnoreComment=false + +from base64 import b64decode, b64encode +import calendar +import datetime +import decimal +import email +from enum import Enum +import json +import logging +import re +import sys +import codecs +from typing import ( + Dict, + Any, + cast, + Optional, + Union, + AnyStr, + IO, + Mapping, + Callable, + MutableMapping, + List, +) + +try: + from urllib import quote # type: ignore +except ImportError: + from urllib.parse import quote +import xml.etree.ElementTree as ET + +import isodate # type: ignore +from typing_extensions import Self + +from azure.core.exceptions import DeserializationError, SerializationError +from azure.core.serialization import NULL as CoreNull + +_BOM = codecs.BOM_UTF8.decode(encoding="utf-8") + +JSON = MutableMapping[str, Any] + + +class RawDeserializer: + + # Accept "text" because we're open minded people... + JSON_REGEXP = re.compile(r"^(application|text)/([a-z+.]+\+)?json$") + + # Name used in context + CONTEXT_NAME = "deserialized_data" + + @classmethod + def deserialize_from_text(cls, data: Optional[Union[AnyStr, IO]], content_type: Optional[str] = None) -> Any: + """Decode data according to content-type. + + Accept a stream of data as well, but will be load at once in memory for now. + + If no content-type, will return the string version (not bytes, not stream) + + :param data: Input, could be bytes or stream (will be decoded with UTF8) or text + :type data: str or bytes or IO + :param str content_type: The content type. + :return: The deserialized data. + :rtype: object + """ + if hasattr(data, "read"): + # Assume a stream + data = cast(IO, data).read() + + if isinstance(data, bytes): + data_as_str = data.decode(encoding="utf-8-sig") + else: + # Explain to mypy the correct type. + data_as_str = cast(str, data) + + # Remove Byte Order Mark if present in string + data_as_str = data_as_str.lstrip(_BOM) + + if content_type is None: + return data + + if cls.JSON_REGEXP.match(content_type): + try: + return json.loads(data_as_str) + except ValueError as err: + raise DeserializationError("JSON is invalid: {}".format(err), err) from err + elif "xml" in (content_type or []): + try: + + try: + if isinstance(data, unicode): # type: ignore + # If I'm Python 2.7 and unicode XML will scream if I try a "fromstring" on unicode string + data_as_str = data_as_str.encode(encoding="utf-8") # type: ignore + except NameError: + pass + + return ET.fromstring(data_as_str) # nosec + except ET.ParseError as err: + # It might be because the server has an issue, and returned JSON with + # content-type XML.... + # So let's try a JSON load, and if it's still broken + # let's flow the initial exception + def _json_attemp(data): + try: + return True, json.loads(data) + except ValueError: + return False, None # Don't care about this one + + success, json_result = _json_attemp(data) + if success: + return json_result + # If i'm here, it's not JSON, it's not XML, let's scream + # and raise the last context in this block (the XML exception) + # The function hack is because Py2.7 messes up with exception + # context otherwise. + _LOGGER.critical("Wasn't XML not JSON, failing") + raise DeserializationError("XML is invalid") from err + elif content_type.startswith("text/"): + return data_as_str + raise DeserializationError("Cannot deserialize content-type: {}".format(content_type)) + + @classmethod + def deserialize_from_http_generics(cls, body_bytes: Optional[Union[AnyStr, IO]], headers: Mapping) -> Any: + """Deserialize from HTTP response. + + Use bytes and headers to NOT use any requests/aiohttp or whatever + specific implementation. + Headers will tested for "content-type" + + :param bytes body_bytes: The body of the response. + :param dict headers: The headers of the response. + :returns: The deserialized data. + :rtype: object + """ + # Try to use content-type from headers if available + content_type = None + if "content-type" in headers: + content_type = headers["content-type"].split(";")[0].strip().lower() + # Ouch, this server did not declare what it sent... + # Let's guess it's JSON... + # Also, since Autorest was considering that an empty body was a valid JSON, + # need that test as well.... + else: + content_type = "application/json" + + if body_bytes: + return cls.deserialize_from_text(body_bytes, content_type) + return None + + +_LOGGER = logging.getLogger(__name__) + +try: + _long_type = long # type: ignore +except NameError: + _long_type = int + +TZ_UTC = datetime.timezone.utc + +_FLATTEN = re.compile(r"(? None: + self.additional_properties: Optional[Dict[str, Any]] = {} + for k in kwargs: # pylint: disable=consider-using-dict-items + if k not in self._attribute_map: + _LOGGER.warning("%s is not a known attribute of class %s and will be ignored", k, self.__class__) + elif k in self._validation and self._validation[k].get("readonly", False): + _LOGGER.warning("Readonly attribute %s will be ignored in class %s", k, self.__class__) + else: + setattr(self, k, kwargs[k]) + + def __eq__(self, other: Any) -> bool: + """Compare objects by comparing all attributes. + + :param object other: The object to compare + :returns: True if objects are equal + :rtype: bool + """ + if isinstance(other, self.__class__): + return self.__dict__ == other.__dict__ + return False + + def __ne__(self, other: Any) -> bool: + """Compare objects by comparing all attributes. + + :param object other: The object to compare + :returns: True if objects are not equal + :rtype: bool + """ + return not self.__eq__(other) + + def __str__(self) -> str: + return str(self.__dict__) + + @classmethod + def enable_additional_properties_sending(cls) -> None: + cls._attribute_map["additional_properties"] = {"key": "", "type": "{object}"} + + @classmethod + def is_xml_model(cls) -> bool: + try: + cls._xml_map # type: ignore + except AttributeError: + return False + return True + + @classmethod + def _create_xml_node(cls): + """Create XML node. + + :returns: The XML node + :rtype: xml.etree.ElementTree.Element + """ + try: + xml_map = cls._xml_map # type: ignore + except AttributeError: + xml_map = {} + + return _create_xml_node(xml_map.get("name", cls.__name__), xml_map.get("prefix", None), xml_map.get("ns", None)) + + def serialize(self, keep_readonly: bool = False, **kwargs: Any) -> JSON: + """Return the JSON that would be sent to server from this model. + + This is an alias to `as_dict(full_restapi_key_transformer, keep_readonly=False)`. + + If you want XML serialization, you can pass the kwargs is_xml=True. + + :param bool keep_readonly: If you want to serialize the readonly attributes + :returns: A dict JSON compatible object + :rtype: dict + """ + serializer = Serializer(self._infer_class_models()) + return serializer._serialize( # type: ignore # pylint: disable=protected-access + self, keep_readonly=keep_readonly, **kwargs + ) + + def as_dict( + self, + keep_readonly: bool = True, + key_transformer: Callable[[str, Dict[str, Any], Any], Any] = attribute_transformer, + **kwargs: Any + ) -> JSON: + """Return a dict that can be serialized using json.dump. + + Advanced usage might optionally use a callback as parameter: + + .. code::python + + def my_key_transformer(key, attr_desc, value): + return key + + Key is the attribute name used in Python. Attr_desc + is a dict of metadata. Currently contains 'type' with the + msrest type and 'key' with the RestAPI encoded key. + Value is the current value in this object. + + The string returned will be used to serialize the key. + If the return type is a list, this is considered hierarchical + result dict. + + See the three examples in this file: + + - attribute_transformer + - full_restapi_key_transformer + - last_restapi_key_transformer + + If you want XML serialization, you can pass the kwargs is_xml=True. + + :param bool keep_readonly: If you want to serialize the readonly attributes + :param function key_transformer: A key transformer function. + :returns: A dict JSON compatible object + :rtype: dict + """ + serializer = Serializer(self._infer_class_models()) + return serializer._serialize( # type: ignore # pylint: disable=protected-access + self, key_transformer=key_transformer, keep_readonly=keep_readonly, **kwargs + ) + + @classmethod + def _infer_class_models(cls): + try: + str_models = cls.__module__.rsplit(".", 1)[0] + models = sys.modules[str_models] + client_models = {k: v for k, v in models.__dict__.items() if isinstance(v, type)} + if cls.__name__ not in client_models: + raise ValueError("Not Autorest generated code") + except Exception: # pylint: disable=broad-exception-caught + # Assume it's not Autorest generated (tests?). Add ourselves as dependencies. + client_models = {cls.__name__: cls} + return client_models + + @classmethod + def deserialize(cls, data: Any, content_type: Optional[str] = None) -> Self: + """Parse a str using the RestAPI syntax and return a model. + + :param str data: A str using RestAPI structure. JSON by default. + :param str content_type: JSON by default, set application/xml if XML. + :returns: An instance of this model + :raises DeserializationError: if something went wrong + :rtype: Self + """ + deserializer = Deserializer(cls._infer_class_models()) + return deserializer(cls.__name__, data, content_type=content_type) # type: ignore + + @classmethod + def from_dict( + cls, + data: Any, + key_extractors: Optional[Callable[[str, Dict[str, Any], Any], Any]] = None, + content_type: Optional[str] = None, + ) -> Self: + """Parse a dict using given key extractor return a model. + + By default consider key + extractors (rest_key_case_insensitive_extractor, attribute_key_case_insensitive_extractor + and last_rest_key_case_insensitive_extractor) + + :param dict data: A dict using RestAPI structure + :param function key_extractors: A key extractor function. + :param str content_type: JSON by default, set application/xml if XML. + :returns: An instance of this model + :raises DeserializationError: if something went wrong + :rtype: Self + """ + deserializer = Deserializer(cls._infer_class_models()) + deserializer.key_extractors = ( # type: ignore + [ # type: ignore + attribute_key_case_insensitive_extractor, + rest_key_case_insensitive_extractor, + last_rest_key_case_insensitive_extractor, + ] + if key_extractors is None + else key_extractors + ) + return deserializer(cls.__name__, data, content_type=content_type) # type: ignore + + @classmethod + def _flatten_subtype(cls, key, objects): + if "_subtype_map" not in cls.__dict__: + return {} + result = dict(cls._subtype_map[key]) + for valuetype in cls._subtype_map[key].values(): + result.update(objects[valuetype]._flatten_subtype(key, objects)) # pylint: disable=protected-access + return result + + @classmethod + def _classify(cls, response, objects): + """Check the class _subtype_map for any child classes. + We want to ignore any inherited _subtype_maps. + + :param dict response: The initial data + :param dict objects: The class objects + :returns: The class to be used + :rtype: class + """ + for subtype_key in cls.__dict__.get("_subtype_map", {}).keys(): + subtype_value = None + + if not isinstance(response, ET.Element): + rest_api_response_key = cls._get_rest_key_parts(subtype_key)[-1] + subtype_value = response.get(rest_api_response_key, None) or response.get(subtype_key, None) + else: + subtype_value = xml_key_extractor(subtype_key, cls._attribute_map[subtype_key], response) + if subtype_value: + # Try to match base class. Can be class name only + # (bug to fix in Autorest to support x-ms-discriminator-name) + if cls.__name__ == subtype_value: + return cls + flatten_mapping_type = cls._flatten_subtype(subtype_key, objects) + try: + return objects[flatten_mapping_type[subtype_value]] # type: ignore + except KeyError: + _LOGGER.warning( + "Subtype value %s has no mapping, use base class %s.", + subtype_value, + cls.__name__, + ) + break + else: + _LOGGER.warning("Discriminator %s is absent or null, use base class %s.", subtype_key, cls.__name__) + break + return cls + + @classmethod + def _get_rest_key_parts(cls, attr_key): + """Get the RestAPI key of this attr, split it and decode part + :param str attr_key: Attribute key must be in attribute_map. + :returns: A list of RestAPI part + :rtype: list + """ + rest_split_key = _FLATTEN.split(cls._attribute_map[attr_key]["key"]) + return [_decode_attribute_map_key(key_part) for key_part in rest_split_key] + + +def _decode_attribute_map_key(key): + """This decode a key in an _attribute_map to the actual key we want to look at + inside the received data. + + :param str key: A key string from the generated code + :returns: The decoded key + :rtype: str + """ + return key.replace("\\.", ".") + + +class Serializer: # pylint: disable=too-many-public-methods + """Request object model serializer.""" + + basic_types = {str: "str", int: "int", bool: "bool", float: "float"} + + _xml_basic_types_serializers = {"bool": lambda x: str(x).lower()} + days = {0: "Mon", 1: "Tue", 2: "Wed", 3: "Thu", 4: "Fri", 5: "Sat", 6: "Sun"} + months = { + 1: "Jan", + 2: "Feb", + 3: "Mar", + 4: "Apr", + 5: "May", + 6: "Jun", + 7: "Jul", + 8: "Aug", + 9: "Sep", + 10: "Oct", + 11: "Nov", + 12: "Dec", + } + validation = { + "min_length": lambda x, y: len(x) < y, + "max_length": lambda x, y: len(x) > y, + "minimum": lambda x, y: x < y, + "maximum": lambda x, y: x > y, + "minimum_ex": lambda x, y: x <= y, + "maximum_ex": lambda x, y: x >= y, + "min_items": lambda x, y: len(x) < y, + "max_items": lambda x, y: len(x) > y, + "pattern": lambda x, y: not re.match(y, x, re.UNICODE), + "unique": lambda x, y: len(x) != len(set(x)), + "multiple": lambda x, y: x % y != 0, + } + + def __init__(self, classes: Optional[Mapping[str, type]] = None) -> None: + self.serialize_type = { + "iso-8601": Serializer.serialize_iso, + "rfc-1123": Serializer.serialize_rfc, + "unix-time": Serializer.serialize_unix, + "duration": Serializer.serialize_duration, + "date": Serializer.serialize_date, + "time": Serializer.serialize_time, + "decimal": Serializer.serialize_decimal, + "long": Serializer.serialize_long, + "bytearray": Serializer.serialize_bytearray, + "base64": Serializer.serialize_base64, + "object": self.serialize_object, + "[]": self.serialize_iter, + "{}": self.serialize_dict, + } + self.dependencies: Dict[str, type] = dict(classes) if classes else {} + self.key_transformer = full_restapi_key_transformer + self.client_side_validation = True + + def _serialize( # pylint: disable=too-many-nested-blocks, too-many-branches, too-many-statements, too-many-locals + self, target_obj, data_type=None, **kwargs + ): + """Serialize data into a string according to type. + + :param object target_obj: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str, dict + :raises SerializationError: if serialization fails. + :returns: The serialized data. + """ + key_transformer = kwargs.get("key_transformer", self.key_transformer) + keep_readonly = kwargs.get("keep_readonly", False) + if target_obj is None: + return None + + attr_name = None + class_name = target_obj.__class__.__name__ + + if data_type: + return self.serialize_data(target_obj, data_type, **kwargs) + + if not hasattr(target_obj, "_attribute_map"): + data_type = type(target_obj).__name__ + if data_type in self.basic_types.values(): + return self.serialize_data(target_obj, data_type, **kwargs) + + # Force "is_xml" kwargs if we detect a XML model + try: + is_xml_model_serialization = kwargs["is_xml"] + except KeyError: + is_xml_model_serialization = kwargs.setdefault("is_xml", target_obj.is_xml_model()) + + serialized = {} + if is_xml_model_serialization: + serialized = target_obj._create_xml_node() # pylint: disable=protected-access + try: + attributes = target_obj._attribute_map # pylint: disable=protected-access + for attr, attr_desc in attributes.items(): + attr_name = attr + if not keep_readonly and target_obj._validation.get( # pylint: disable=protected-access + attr_name, {} + ).get("readonly", False): + continue + + if attr_name == "additional_properties" and attr_desc["key"] == "": + if target_obj.additional_properties is not None: + serialized.update(target_obj.additional_properties) + continue + try: + + orig_attr = getattr(target_obj, attr) + if is_xml_model_serialization: + pass # Don't provide "transformer" for XML for now. Keep "orig_attr" + else: # JSON + keys, orig_attr = key_transformer(attr, attr_desc.copy(), orig_attr) + keys = keys if isinstance(keys, list) else [keys] + + kwargs["serialization_ctxt"] = attr_desc + new_attr = self.serialize_data(orig_attr, attr_desc["type"], **kwargs) + + if is_xml_model_serialization: + xml_desc = attr_desc.get("xml", {}) + xml_name = xml_desc.get("name", attr_desc["key"]) + xml_prefix = xml_desc.get("prefix", None) + xml_ns = xml_desc.get("ns", None) + if xml_desc.get("attr", False): + if xml_ns: + ET.register_namespace(xml_prefix, xml_ns) + xml_name = "{{{}}}{}".format(xml_ns, xml_name) + serialized.set(xml_name, new_attr) # type: ignore + continue + if xml_desc.get("text", False): + serialized.text = new_attr # type: ignore + continue + if isinstance(new_attr, list): + serialized.extend(new_attr) # type: ignore + elif isinstance(new_attr, ET.Element): + # If the down XML has no XML/Name, + # we MUST replace the tag with the local tag. But keeping the namespaces. + if "name" not in getattr(orig_attr, "_xml_map", {}): + splitted_tag = new_attr.tag.split("}") + if len(splitted_tag) == 2: # Namespace + new_attr.tag = "}".join([splitted_tag[0], xml_name]) + else: + new_attr.tag = xml_name + serialized.append(new_attr) # type: ignore + else: # That's a basic type + # Integrate namespace if necessary + local_node = _create_xml_node(xml_name, xml_prefix, xml_ns) + local_node.text = str(new_attr) + serialized.append(local_node) # type: ignore + else: # JSON + for k in reversed(keys): # type: ignore + new_attr = {k: new_attr} + + _new_attr = new_attr + _serialized = serialized + for k in keys: # type: ignore + if k not in _serialized: + _serialized.update(_new_attr) # type: ignore + _new_attr = _new_attr[k] # type: ignore + _serialized = _serialized[k] + except ValueError as err: + if isinstance(err, SerializationError): + raise + + except (AttributeError, KeyError, TypeError) as err: + msg = "Attribute {} in object {} cannot be serialized.\n{}".format(attr_name, class_name, str(target_obj)) + raise SerializationError(msg) from err + return serialized + + def body(self, data, data_type, **kwargs): + """Serialize data intended for a request body. + + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: dict + :raises SerializationError: if serialization fails. + :raises ValueError: if data is None + :returns: The serialized request body + """ + + # Just in case this is a dict + internal_data_type_str = data_type.strip("[]{}") + internal_data_type = self.dependencies.get(internal_data_type_str, None) + try: + is_xml_model_serialization = kwargs["is_xml"] + except KeyError: + if internal_data_type and issubclass(internal_data_type, Model): + is_xml_model_serialization = kwargs.setdefault("is_xml", internal_data_type.is_xml_model()) + else: + is_xml_model_serialization = False + if internal_data_type and not isinstance(internal_data_type, Enum): + try: + deserializer = Deserializer(self.dependencies) + # Since it's on serialization, it's almost sure that format is not JSON REST + # We're not able to deal with additional properties for now. + deserializer.additional_properties_detection = False + if is_xml_model_serialization: + deserializer.key_extractors = [ # type: ignore + attribute_key_case_insensitive_extractor, + ] + else: + deserializer.key_extractors = [ + rest_key_case_insensitive_extractor, + attribute_key_case_insensitive_extractor, + last_rest_key_case_insensitive_extractor, + ] + data = deserializer._deserialize(data_type, data) # pylint: disable=protected-access + except DeserializationError as err: + raise SerializationError("Unable to build a model: " + str(err)) from err + + return self._serialize(data, data_type, **kwargs) + + def url(self, name, data, data_type, **kwargs): + """Serialize data intended for a URL path. + + :param str name: The name of the URL path parameter. + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str + :returns: The serialized URL path + :raises TypeError: if serialization fails. + :raises ValueError: if data is None + """ + try: + output = self.serialize_data(data, data_type, **kwargs) + if data_type == "bool": + output = json.dumps(output) + + if kwargs.get("skip_quote") is True: + output = str(output) + output = output.replace("{", quote("{")).replace("}", quote("}")) + else: + output = quote(str(output), safe="") + except SerializationError as exc: + raise TypeError("{} must be type {}.".format(name, data_type)) from exc + return output + + def query(self, name, data, data_type, **kwargs): + """Serialize data intended for a URL query. + + :param str name: The name of the query parameter. + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str, list + :raises TypeError: if serialization fails. + :raises ValueError: if data is None + :returns: The serialized query parameter + """ + try: + # Treat the list aside, since we don't want to encode the div separator + if data_type.startswith("["): + internal_data_type = data_type[1:-1] + do_quote = not kwargs.get("skip_quote", False) + return self.serialize_iter(data, internal_data_type, do_quote=do_quote, **kwargs) + + # Not a list, regular serialization + output = self.serialize_data(data, data_type, **kwargs) + if data_type == "bool": + output = json.dumps(output) + if kwargs.get("skip_quote") is True: + output = str(output) + else: + output = quote(str(output), safe="") + except SerializationError as exc: + raise TypeError("{} must be type {}.".format(name, data_type)) from exc + return str(output) + + def header(self, name, data, data_type, **kwargs): + """Serialize data intended for a request header. + + :param str name: The name of the header. + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str + :raises TypeError: if serialization fails. + :raises ValueError: if data is None + :returns: The serialized header + """ + try: + if data_type in ["[str]"]: + data = ["" if d is None else d for d in data] + + output = self.serialize_data(data, data_type, **kwargs) + if data_type == "bool": + output = json.dumps(output) + except SerializationError as exc: + raise TypeError("{} must be type {}.".format(name, data_type)) from exc + return str(output) + + def serialize_data(self, data, data_type, **kwargs): + """Serialize generic data according to supplied data type. + + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :raises AttributeError: if required data is None. + :raises ValueError: if data is None + :raises SerializationError: if serialization fails. + :returns: The serialized data. + :rtype: str, int, float, bool, dict, list + """ + if data is None: + raise ValueError("No value for given attribute") + + try: + if data is CoreNull: + return None + if data_type in self.basic_types.values(): + return self.serialize_basic(data, data_type, **kwargs) + + if data_type in self.serialize_type: + return self.serialize_type[data_type](data, **kwargs) + + # If dependencies is empty, try with current data class + # It has to be a subclass of Enum anyway + enum_type = self.dependencies.get(data_type, data.__class__) + if issubclass(enum_type, Enum): + return Serializer.serialize_enum(data, enum_obj=enum_type) + + iter_type = data_type[0] + data_type[-1] + if iter_type in self.serialize_type: + return self.serialize_type[iter_type](data, data_type[1:-1], **kwargs) + + except (ValueError, TypeError) as err: + msg = "Unable to serialize value: {!r} as type: {!r}." + raise SerializationError(msg.format(data, data_type)) from err + return self._serialize(data, **kwargs) + + @classmethod + def _get_custom_serializers(cls, data_type, **kwargs): # pylint: disable=inconsistent-return-statements + custom_serializer = kwargs.get("basic_types_serializers", {}).get(data_type) + if custom_serializer: + return custom_serializer + if kwargs.get("is_xml", False): + return cls._xml_basic_types_serializers.get(data_type) + + @classmethod + def serialize_basic(cls, data, data_type, **kwargs): + """Serialize basic builting data type. + Serializes objects to str, int, float or bool. + + Possible kwargs: + - basic_types_serializers dict[str, callable] : If set, use the callable as serializer + - is_xml bool : If set, use xml_basic_types_serializers + + :param obj data: Object to be serialized. + :param str data_type: Type of object in the iterable. + :rtype: str, int, float, bool + :return: serialized object + """ + custom_serializer = cls._get_custom_serializers(data_type, **kwargs) + if custom_serializer: + return custom_serializer(data) + if data_type == "str": + return cls.serialize_unicode(data) + return eval(data_type)(data) # nosec # pylint: disable=eval-used + + @classmethod + def serialize_unicode(cls, data): + """Special handling for serializing unicode strings in Py2. + Encode to UTF-8 if unicode, otherwise handle as a str. + + :param str data: Object to be serialized. + :rtype: str + :return: serialized object + """ + try: # If I received an enum, return its value + return data.value + except AttributeError: + pass + + try: + if isinstance(data, unicode): # type: ignore + # Don't change it, JSON and XML ElementTree are totally able + # to serialize correctly u'' strings + return data + except NameError: + return str(data) + return str(data) + + def serialize_iter(self, data, iter_type, div=None, **kwargs): + """Serialize iterable. + + Supported kwargs: + - serialization_ctxt dict : The current entry of _attribute_map, or same format. + serialization_ctxt['type'] should be same as data_type. + - is_xml bool : If set, serialize as XML + + :param list data: Object to be serialized. + :param str iter_type: Type of object in the iterable. + :param str div: If set, this str will be used to combine the elements + in the iterable into a combined string. Default is 'None'. + Defaults to False. + :rtype: list, str + :return: serialized iterable + """ + if isinstance(data, str): + raise SerializationError("Refuse str type as a valid iter type.") + + serialization_ctxt = kwargs.get("serialization_ctxt", {}) + is_xml = kwargs.get("is_xml", False) + + serialized = [] + for d in data: + try: + serialized.append(self.serialize_data(d, iter_type, **kwargs)) + except ValueError as err: + if isinstance(err, SerializationError): + raise + serialized.append(None) + + if kwargs.get("do_quote", False): + serialized = ["" if s is None else quote(str(s), safe="") for s in serialized] + + if div: + serialized = ["" if s is None else str(s) for s in serialized] + serialized = div.join(serialized) + + if "xml" in serialization_ctxt or is_xml: + # XML serialization is more complicated + xml_desc = serialization_ctxt.get("xml", {}) + xml_name = xml_desc.get("name") + if not xml_name: + xml_name = serialization_ctxt["key"] + + # Create a wrap node if necessary (use the fact that Element and list have "append") + is_wrapped = xml_desc.get("wrapped", False) + node_name = xml_desc.get("itemsName", xml_name) + if is_wrapped: + final_result = _create_xml_node(xml_name, xml_desc.get("prefix", None), xml_desc.get("ns", None)) + else: + final_result = [] + # All list elements to "local_node" + for el in serialized: + if isinstance(el, ET.Element): + el_node = el + else: + el_node = _create_xml_node(node_name, xml_desc.get("prefix", None), xml_desc.get("ns", None)) + if el is not None: # Otherwise it writes "None" :-p + el_node.text = str(el) + final_result.append(el_node) + return final_result + return serialized + + def serialize_dict(self, attr, dict_type, **kwargs): + """Serialize a dictionary of objects. + + :param dict attr: Object to be serialized. + :param str dict_type: Type of object in the dictionary. + :rtype: dict + :return: serialized dictionary + """ + serialization_ctxt = kwargs.get("serialization_ctxt", {}) + serialized = {} + for key, value in attr.items(): + try: + serialized[self.serialize_unicode(key)] = self.serialize_data(value, dict_type, **kwargs) + except ValueError as err: + if isinstance(err, SerializationError): + raise + serialized[self.serialize_unicode(key)] = None + + if "xml" in serialization_ctxt: + # XML serialization is more complicated + xml_desc = serialization_ctxt["xml"] + xml_name = xml_desc["name"] + + final_result = _create_xml_node(xml_name, xml_desc.get("prefix", None), xml_desc.get("ns", None)) + for key, value in serialized.items(): + ET.SubElement(final_result, key).text = value + return final_result + + return serialized + + def serialize_object(self, attr, **kwargs): # pylint: disable=too-many-return-statements + """Serialize a generic object. + This will be handled as a dictionary. If object passed in is not + a basic type (str, int, float, dict, list) it will simply be + cast to str. + + :param dict attr: Object to be serialized. + :rtype: dict or str + :return: serialized object + """ + if attr is None: + return None + if isinstance(attr, ET.Element): + return attr + obj_type = type(attr) + if obj_type in self.basic_types: + return self.serialize_basic(attr, self.basic_types[obj_type], **kwargs) + if obj_type is _long_type: + return self.serialize_long(attr) + if obj_type is str: + return self.serialize_unicode(attr) + if obj_type is datetime.datetime: + return self.serialize_iso(attr) + if obj_type is datetime.date: + return self.serialize_date(attr) + if obj_type is datetime.time: + return self.serialize_time(attr) + if obj_type is datetime.timedelta: + return self.serialize_duration(attr) + if obj_type is decimal.Decimal: + return self.serialize_decimal(attr) + + # If it's a model or I know this dependency, serialize as a Model + if obj_type in self.dependencies.values() or isinstance(attr, Model): + return self._serialize(attr) + + if obj_type == dict: + serialized = {} + for key, value in attr.items(): + try: + serialized[self.serialize_unicode(key)] = self.serialize_object(value, **kwargs) + except ValueError: + serialized[self.serialize_unicode(key)] = None + return serialized + + if obj_type == list: + serialized = [] + for obj in attr: + try: + serialized.append(self.serialize_object(obj, **kwargs)) + except ValueError: + pass + return serialized + return str(attr) + + @staticmethod + def serialize_enum(attr, enum_obj=None): + try: + result = attr.value + except AttributeError: + result = attr + try: + enum_obj(result) # type: ignore + return result + except ValueError as exc: + for enum_value in enum_obj: # type: ignore + if enum_value.value.lower() == str(attr).lower(): + return enum_value.value + error = "{!r} is not valid value for enum {!r}" + raise SerializationError(error.format(attr, enum_obj)) from exc + + @staticmethod + def serialize_bytearray(attr, **kwargs): # pylint: disable=unused-argument + """Serialize bytearray into base-64 string. + + :param str attr: Object to be serialized. + :rtype: str + :return: serialized base64 + """ + return b64encode(attr).decode() + + @staticmethod + def serialize_base64(attr, **kwargs): # pylint: disable=unused-argument + """Serialize str into base-64 string. + + :param str attr: Object to be serialized. + :rtype: str + :return: serialized base64 + """ + encoded = b64encode(attr).decode("ascii") + return encoded.strip("=").replace("+", "-").replace("/", "_") + + @staticmethod + def serialize_decimal(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Decimal object to float. + + :param decimal attr: Object to be serialized. + :rtype: float + :return: serialized decimal + """ + return float(attr) + + @staticmethod + def serialize_long(attr, **kwargs): # pylint: disable=unused-argument + """Serialize long (Py2) or int (Py3). + + :param int attr: Object to be serialized. + :rtype: int/long + :return: serialized long + """ + return _long_type(attr) + + @staticmethod + def serialize_date(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Date object into ISO-8601 formatted string. + + :param Date attr: Object to be serialized. + :rtype: str + :return: serialized date + """ + if isinstance(attr, str): + attr = isodate.parse_date(attr) + t = "{:04}-{:02}-{:02}".format(attr.year, attr.month, attr.day) + return t + + @staticmethod + def serialize_time(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Time object into ISO-8601 formatted string. + + :param datetime.time attr: Object to be serialized. + :rtype: str + :return: serialized time + """ + if isinstance(attr, str): + attr = isodate.parse_time(attr) + t = "{:02}:{:02}:{:02}".format(attr.hour, attr.minute, attr.second) + if attr.microsecond: + t += ".{:02}".format(attr.microsecond) + return t + + @staticmethod + def serialize_duration(attr, **kwargs): # pylint: disable=unused-argument + """Serialize TimeDelta object into ISO-8601 formatted string. + + :param TimeDelta attr: Object to be serialized. + :rtype: str + :return: serialized duration + """ + if isinstance(attr, str): + attr = isodate.parse_duration(attr) + return isodate.duration_isoformat(attr) + + @staticmethod + def serialize_rfc(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Datetime object into RFC-1123 formatted string. + + :param Datetime attr: Object to be serialized. + :rtype: str + :raises TypeError: if format invalid. + :return: serialized rfc + """ + try: + if not attr.tzinfo: + _LOGGER.warning("Datetime with no tzinfo will be considered UTC.") + utc = attr.utctimetuple() + except AttributeError as exc: + raise TypeError("RFC1123 object must be valid Datetime object.") from exc + + return "{}, {:02} {} {:04} {:02}:{:02}:{:02} GMT".format( + Serializer.days[utc.tm_wday], + utc.tm_mday, + Serializer.months[utc.tm_mon], + utc.tm_year, + utc.tm_hour, + utc.tm_min, + utc.tm_sec, + ) + + @staticmethod + def serialize_iso(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Datetime object into ISO-8601 formatted string. + + :param Datetime attr: Object to be serialized. + :rtype: str + :raises SerializationError: if format invalid. + :return: serialized iso + """ + if isinstance(attr, str): + attr = isodate.parse_datetime(attr) + try: + if not attr.tzinfo: + _LOGGER.warning("Datetime with no tzinfo will be considered UTC.") + utc = attr.utctimetuple() + if utc.tm_year > 9999 or utc.tm_year < 1: + raise OverflowError("Hit max or min date") + + microseconds = str(attr.microsecond).rjust(6, "0").rstrip("0").ljust(3, "0") + if microseconds: + microseconds = "." + microseconds + date = "{:04}-{:02}-{:02}T{:02}:{:02}:{:02}".format( + utc.tm_year, utc.tm_mon, utc.tm_mday, utc.tm_hour, utc.tm_min, utc.tm_sec + ) + return date + microseconds + "Z" + except (ValueError, OverflowError) as err: + msg = "Unable to serialize datetime object." + raise SerializationError(msg) from err + except AttributeError as err: + msg = "ISO-8601 object must be valid Datetime object." + raise TypeError(msg) from err + + @staticmethod + def serialize_unix(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Datetime object into IntTime format. + This is represented as seconds. + + :param Datetime attr: Object to be serialized. + :rtype: int + :raises SerializationError: if format invalid + :return: serialied unix + """ + if isinstance(attr, int): + return attr + try: + if not attr.tzinfo: + _LOGGER.warning("Datetime with no tzinfo will be considered UTC.") + return int(calendar.timegm(attr.utctimetuple())) + except AttributeError as exc: + raise TypeError("Unix time object must be valid Datetime object.") from exc + + +def rest_key_extractor(attr, attr_desc, data): # pylint: disable=unused-argument + key = attr_desc["key"] + working_data = data + + while "." in key: + # Need the cast, as for some reasons "split" is typed as list[str | Any] + dict_keys = cast(List[str], _FLATTEN.split(key)) + if len(dict_keys) == 1: + key = _decode_attribute_map_key(dict_keys[0]) + break + working_key = _decode_attribute_map_key(dict_keys[0]) + working_data = working_data.get(working_key, data) + if working_data is None: + # If at any point while following flatten JSON path see None, it means + # that all properties under are None as well + return None + key = ".".join(dict_keys[1:]) + + return working_data.get(key) + + +def rest_key_case_insensitive_extractor( # pylint: disable=unused-argument, inconsistent-return-statements + attr, attr_desc, data +): + key = attr_desc["key"] + working_data = data + + while "." in key: + dict_keys = _FLATTEN.split(key) + if len(dict_keys) == 1: + key = _decode_attribute_map_key(dict_keys[0]) + break + working_key = _decode_attribute_map_key(dict_keys[0]) + working_data = attribute_key_case_insensitive_extractor(working_key, None, working_data) + if working_data is None: + # If at any point while following flatten JSON path see None, it means + # that all properties under are None as well + return None + key = ".".join(dict_keys[1:]) + + if working_data: + return attribute_key_case_insensitive_extractor(key, None, working_data) + + +def last_rest_key_extractor(attr, attr_desc, data): # pylint: disable=unused-argument + """Extract the attribute in "data" based on the last part of the JSON path key. + + :param str attr: The attribute to extract + :param dict attr_desc: The attribute description + :param dict data: The data to extract from + :rtype: object + :returns: The extracted attribute + """ + key = attr_desc["key"] + dict_keys = _FLATTEN.split(key) + return attribute_key_extractor(dict_keys[-1], None, data) + + +def last_rest_key_case_insensitive_extractor(attr, attr_desc, data): # pylint: disable=unused-argument + """Extract the attribute in "data" based on the last part of the JSON path key. + + This is the case insensitive version of "last_rest_key_extractor" + :param str attr: The attribute to extract + :param dict attr_desc: The attribute description + :param dict data: The data to extract from + :rtype: object + :returns: The extracted attribute + """ + key = attr_desc["key"] + dict_keys = _FLATTEN.split(key) + return attribute_key_case_insensitive_extractor(dict_keys[-1], None, data) + + +def attribute_key_extractor(attr, _, data): + return data.get(attr) + + +def attribute_key_case_insensitive_extractor(attr, _, data): + found_key = None + lower_attr = attr.lower() + for key in data: + if lower_attr == key.lower(): + found_key = key + break + + return data.get(found_key) + + +def _extract_name_from_internal_type(internal_type): + """Given an internal type XML description, extract correct XML name with namespace. + + :param dict internal_type: An model type + :rtype: tuple + :returns: A tuple XML name + namespace dict + """ + internal_type_xml_map = getattr(internal_type, "_xml_map", {}) + xml_name = internal_type_xml_map.get("name", internal_type.__name__) + xml_ns = internal_type_xml_map.get("ns", None) + if xml_ns: + xml_name = "{{{}}}{}".format(xml_ns, xml_name) + return xml_name + + +def xml_key_extractor(attr, attr_desc, data): # pylint: disable=unused-argument,too-many-return-statements + if isinstance(data, dict): + return None + + # Test if this model is XML ready first + if not isinstance(data, ET.Element): + return None + + xml_desc = attr_desc.get("xml", {}) + xml_name = xml_desc.get("name", attr_desc["key"]) + + # Look for a children + is_iter_type = attr_desc["type"].startswith("[") + is_wrapped = xml_desc.get("wrapped", False) + internal_type = attr_desc.get("internalType", None) + internal_type_xml_map = getattr(internal_type, "_xml_map", {}) + + # Integrate namespace if necessary + xml_ns = xml_desc.get("ns", internal_type_xml_map.get("ns", None)) + if xml_ns: + xml_name = "{{{}}}{}".format(xml_ns, xml_name) + + # If it's an attribute, that's simple + if xml_desc.get("attr", False): + return data.get(xml_name) + + # If it's x-ms-text, that's simple too + if xml_desc.get("text", False): + return data.text + + # Scenario where I take the local name: + # - Wrapped node + # - Internal type is an enum (considered basic types) + # - Internal type has no XML/Name node + if is_wrapped or (internal_type and (issubclass(internal_type, Enum) or "name" not in internal_type_xml_map)): + children = data.findall(xml_name) + # If internal type has a local name and it's not a list, I use that name + elif not is_iter_type and internal_type and "name" in internal_type_xml_map: + xml_name = _extract_name_from_internal_type(internal_type) + children = data.findall(xml_name) + # That's an array + else: + if internal_type: # Complex type, ignore itemsName and use the complex type name + items_name = _extract_name_from_internal_type(internal_type) + else: + items_name = xml_desc.get("itemsName", xml_name) + children = data.findall(items_name) + + if len(children) == 0: + if is_iter_type: + if is_wrapped: + return None # is_wrapped no node, we want None + return [] # not wrapped, assume empty list + return None # Assume it's not there, maybe an optional node. + + # If is_iter_type and not wrapped, return all found children + if is_iter_type: + if not is_wrapped: + return children + # Iter and wrapped, should have found one node only (the wrap one) + if len(children) != 1: + raise DeserializationError( + "Tried to deserialize an array not wrapped, and found several nodes '{}'. Maybe you should declare this array as wrapped?".format( + xml_name + ) + ) + return list(children[0]) # Might be empty list and that's ok. + + # Here it's not a itertype, we should have found one element only or empty + if len(children) > 1: + raise DeserializationError("Find several XML '{}' where it was not expected".format(xml_name)) + return children[0] + + +class Deserializer: + """Response object model deserializer. + + :param dict classes: Class type dictionary for deserializing complex types. + :ivar list key_extractors: Ordered list of extractors to be used by this deserializer. + """ + + basic_types = {str: "str", int: "int", bool: "bool", float: "float"} + + valid_date = re.compile(r"\d{4}[-]\d{2}[-]\d{2}T\d{2}:\d{2}:\d{2}\.?\d*Z?[-+]?[\d{2}]?:?[\d{2}]?") + + def __init__(self, classes: Optional[Mapping[str, type]] = None) -> None: + self.deserialize_type = { + "iso-8601": Deserializer.deserialize_iso, + "rfc-1123": Deserializer.deserialize_rfc, + "unix-time": Deserializer.deserialize_unix, + "duration": Deserializer.deserialize_duration, + "date": Deserializer.deserialize_date, + "time": Deserializer.deserialize_time, + "decimal": Deserializer.deserialize_decimal, + "long": Deserializer.deserialize_long, + "bytearray": Deserializer.deserialize_bytearray, + "base64": Deserializer.deserialize_base64, + "object": self.deserialize_object, + "[]": self.deserialize_iter, + "{}": self.deserialize_dict, + } + self.deserialize_expected_types = { + "duration": (isodate.Duration, datetime.timedelta), + "iso-8601": (datetime.datetime), + } + self.dependencies: Dict[str, type] = dict(classes) if classes else {} + self.key_extractors = [rest_key_extractor, xml_key_extractor] + # Additional properties only works if the "rest_key_extractor" is used to + # extract the keys. Making it to work whatever the key extractor is too much + # complicated, with no real scenario for now. + # So adding a flag to disable additional properties detection. This flag should be + # used if your expect the deserialization to NOT come from a JSON REST syntax. + # Otherwise, result are unexpected + self.additional_properties_detection = True + + def __call__(self, target_obj, response_data, content_type=None): + """Call the deserializer to process a REST response. + + :param str target_obj: Target data type to deserialize to. + :param requests.Response response_data: REST response object. + :param str content_type: Swagger "produces" if available. + :raises DeserializationError: if deserialization fails. + :return: Deserialized object. + :rtype: object + """ + data = self._unpack_content(response_data, content_type) + return self._deserialize(target_obj, data) + + def _deserialize(self, target_obj, data): # pylint: disable=inconsistent-return-statements + """Call the deserializer on a model. + + Data needs to be already deserialized as JSON or XML ElementTree + + :param str target_obj: Target data type to deserialize to. + :param object data: Object to deserialize. + :raises DeserializationError: if deserialization fails. + :return: Deserialized object. + :rtype: object + """ + # This is already a model, go recursive just in case + if hasattr(data, "_attribute_map"): + constants = [name for name, config in getattr(data, "_validation", {}).items() if config.get("constant")] + try: + for attr, mapconfig in data._attribute_map.items(): # pylint: disable=protected-access + if attr in constants: + continue + value = getattr(data, attr) + if value is None: + continue + local_type = mapconfig["type"] + internal_data_type = local_type.strip("[]{}") + if internal_data_type not in self.dependencies or isinstance(internal_data_type, Enum): + continue + setattr(data, attr, self._deserialize(local_type, value)) + return data + except AttributeError: + return + + response, class_name = self._classify_target(target_obj, data) + + if isinstance(response, str): + return self.deserialize_data(data, response) + if isinstance(response, type) and issubclass(response, Enum): + return self.deserialize_enum(data, response) + + if data is None or data is CoreNull: + return data + try: + attributes = response._attribute_map # type: ignore # pylint: disable=protected-access + d_attrs = {} + for attr, attr_desc in attributes.items(): + # Check empty string. If it's not empty, someone has a real "additionalProperties"... + if attr == "additional_properties" and attr_desc["key"] == "": + continue + raw_value = None + # Enhance attr_desc with some dynamic data + attr_desc = attr_desc.copy() # Do a copy, do not change the real one + internal_data_type = attr_desc["type"].strip("[]{}") + if internal_data_type in self.dependencies: + attr_desc["internalType"] = self.dependencies[internal_data_type] + + for key_extractor in self.key_extractors: + found_value = key_extractor(attr, attr_desc, data) + if found_value is not None: + if raw_value is not None and raw_value != found_value: + msg = ( + "Ignoring extracted value '%s' from %s for key '%s'" + " (duplicate extraction, follow extractors order)" + ) + _LOGGER.warning(msg, found_value, key_extractor, attr) + continue + raw_value = found_value + + value = self.deserialize_data(raw_value, attr_desc["type"]) + d_attrs[attr] = value + except (AttributeError, TypeError, KeyError) as err: + msg = "Unable to deserialize to object: " + class_name # type: ignore + raise DeserializationError(msg) from err + additional_properties = self._build_additional_properties(attributes, data) + return self._instantiate_model(response, d_attrs, additional_properties) + + def _build_additional_properties(self, attribute_map, data): + if not self.additional_properties_detection: + return None + if "additional_properties" in attribute_map and attribute_map.get("additional_properties", {}).get("key") != "": + # Check empty string. If it's not empty, someone has a real "additionalProperties" + return None + if isinstance(data, ET.Element): + data = {el.tag: el.text for el in data} + + known_keys = { + _decode_attribute_map_key(_FLATTEN.split(desc["key"])[0]) + for desc in attribute_map.values() + if desc["key"] != "" + } + present_keys = set(data.keys()) + missing_keys = present_keys - known_keys + return {key: data[key] for key in missing_keys} + + def _classify_target(self, target, data): + """Check to see whether the deserialization target object can + be classified into a subclass. + Once classification has been determined, initialize object. + + :param str target: The target object type to deserialize to. + :param str/dict data: The response data to deserialize. + :return: The classified target object and its class name. + :rtype: tuple + """ + if target is None: + return None, None + + if isinstance(target, str): + try: + target = self.dependencies[target] + except KeyError: + return target, target + + try: + target = target._classify(data, self.dependencies) # type: ignore # pylint: disable=protected-access + except AttributeError: + pass # Target is not a Model, no classify + return target, target.__class__.__name__ # type: ignore + + def failsafe_deserialize(self, target_obj, data, content_type=None): + """Ignores any errors encountered in deserialization, + and falls back to not deserializing the object. Recommended + for use in error deserialization, as we want to return the + HttpResponseError to users, and not have them deal with + a deserialization error. + + :param str target_obj: The target object type to deserialize to. + :param str/dict data: The response data to deserialize. + :param str content_type: Swagger "produces" if available. + :return: Deserialized object. + :rtype: object + """ + try: + return self(target_obj, data, content_type=content_type) + except: # pylint: disable=bare-except + _LOGGER.debug( + "Ran into a deserialization error. Ignoring since this is failsafe deserialization", exc_info=True + ) + return None + + @staticmethod + def _unpack_content(raw_data, content_type=None): + """Extract the correct structure for deserialization. + + If raw_data is a PipelineResponse, try to extract the result of RawDeserializer. + if we can't, raise. Your Pipeline should have a RawDeserializer. + + If not a pipeline response and raw_data is bytes or string, use content-type + to decode it. If no content-type, try JSON. + + If raw_data is something else, bypass all logic and return it directly. + + :param obj raw_data: Data to be processed. + :param str content_type: How to parse if raw_data is a string/bytes. + :raises JSONDecodeError: If JSON is requested and parsing is impossible. + :raises UnicodeDecodeError: If bytes is not UTF8 + :rtype: object + :return: Unpacked content. + """ + # Assume this is enough to detect a Pipeline Response without importing it + context = getattr(raw_data, "context", {}) + if context: + if RawDeserializer.CONTEXT_NAME in context: + return context[RawDeserializer.CONTEXT_NAME] + raise ValueError("This pipeline didn't have the RawDeserializer policy; can't deserialize") + + # Assume this is enough to recognize universal_http.ClientResponse without importing it + if hasattr(raw_data, "body"): + return RawDeserializer.deserialize_from_http_generics(raw_data.text(), raw_data.headers) + + # Assume this enough to recognize requests.Response without importing it. + if hasattr(raw_data, "_content_consumed"): + return RawDeserializer.deserialize_from_http_generics(raw_data.text, raw_data.headers) + + if isinstance(raw_data, (str, bytes)) or hasattr(raw_data, "read"): + return RawDeserializer.deserialize_from_text(raw_data, content_type) # type: ignore + return raw_data + + def _instantiate_model(self, response, attrs, additional_properties=None): + """Instantiate a response model passing in deserialized args. + + :param Response response: The response model class. + :param dict attrs: The deserialized response attributes. + :param dict additional_properties: Additional properties to be set. + :rtype: Response + :return: The instantiated response model. + """ + if callable(response): + subtype = getattr(response, "_subtype_map", {}) + try: + readonly = [ + k + for k, v in response._validation.items() # pylint: disable=protected-access # type: ignore + if v.get("readonly") + ] + const = [ + k + for k, v in response._validation.items() # pylint: disable=protected-access # type: ignore + if v.get("constant") + ] + kwargs = {k: v for k, v in attrs.items() if k not in subtype and k not in readonly + const} + response_obj = response(**kwargs) + for attr in readonly: + setattr(response_obj, attr, attrs.get(attr)) + if additional_properties: + response_obj.additional_properties = additional_properties # type: ignore + return response_obj + except TypeError as err: + msg = "Unable to deserialize {} into model {}. ".format(kwargs, response) # type: ignore + raise DeserializationError(msg + str(err)) from err + else: + try: + for attr, value in attrs.items(): + setattr(response, attr, value) + return response + except Exception as exp: + msg = "Unable to populate response model. " + msg += "Type: {}, Error: {}".format(type(response), exp) + raise DeserializationError(msg) from exp + + def deserialize_data(self, data, data_type): # pylint: disable=too-many-return-statements + """Process data for deserialization according to data type. + + :param str data: The response string to be deserialized. + :param str data_type: The type to deserialize to. + :raises DeserializationError: if deserialization fails. + :return: Deserialized object. + :rtype: object + """ + if data is None: + return data + + try: + if not data_type: + return data + if data_type in self.basic_types.values(): + return self.deserialize_basic(data, data_type) + if data_type in self.deserialize_type: + if isinstance(data, self.deserialize_expected_types.get(data_type, tuple())): + return data + + is_a_text_parsing_type = lambda x: x not in [ # pylint: disable=unnecessary-lambda-assignment + "object", + "[]", + r"{}", + ] + if isinstance(data, ET.Element) and is_a_text_parsing_type(data_type) and not data.text: + return None + data_val = self.deserialize_type[data_type](data) + return data_val + + iter_type = data_type[0] + data_type[-1] + if iter_type in self.deserialize_type: + return self.deserialize_type[iter_type](data, data_type[1:-1]) + + obj_type = self.dependencies[data_type] + if issubclass(obj_type, Enum): + if isinstance(data, ET.Element): + data = data.text + return self.deserialize_enum(data, obj_type) + + except (ValueError, TypeError, AttributeError) as err: + msg = "Unable to deserialize response data." + msg += " Data: {}, {}".format(data, data_type) + raise DeserializationError(msg) from err + return self._deserialize(obj_type, data) + + def deserialize_iter(self, attr, iter_type): + """Deserialize an iterable. + + :param list attr: Iterable to be deserialized. + :param str iter_type: The type of object in the iterable. + :return: Deserialized iterable. + :rtype: list + """ + if attr is None: + return None + if isinstance(attr, ET.Element): # If I receive an element here, get the children + attr = list(attr) + if not isinstance(attr, (list, set)): + raise DeserializationError("Cannot deserialize as [{}] an object of type {}".format(iter_type, type(attr))) + return [self.deserialize_data(a, iter_type) for a in attr] + + def deserialize_dict(self, attr, dict_type): + """Deserialize a dictionary. + + :param dict/list attr: Dictionary to be deserialized. Also accepts + a list of key, value pairs. + :param str dict_type: The object type of the items in the dictionary. + :return: Deserialized dictionary. + :rtype: dict + """ + if isinstance(attr, list): + return {x["key"]: self.deserialize_data(x["value"], dict_type) for x in attr} + + if isinstance(attr, ET.Element): + # Transform value into {"Key": "value"} + attr = {el.tag: el.text for el in attr} + return {k: self.deserialize_data(v, dict_type) for k, v in attr.items()} + + def deserialize_object(self, attr, **kwargs): # pylint: disable=too-many-return-statements + """Deserialize a generic object. + This will be handled as a dictionary. + + :param dict attr: Dictionary to be deserialized. + :return: Deserialized object. + :rtype: dict + :raises TypeError: if non-builtin datatype encountered. + """ + if attr is None: + return None + if isinstance(attr, ET.Element): + # Do no recurse on XML, just return the tree as-is + return attr + if isinstance(attr, str): + return self.deserialize_basic(attr, "str") + obj_type = type(attr) + if obj_type in self.basic_types: + return self.deserialize_basic(attr, self.basic_types[obj_type]) + if obj_type is _long_type: + return self.deserialize_long(attr) + + if obj_type == dict: + deserialized = {} + for key, value in attr.items(): + try: + deserialized[key] = self.deserialize_object(value, **kwargs) + except ValueError: + deserialized[key] = None + return deserialized + + if obj_type == list: + deserialized = [] + for obj in attr: + try: + deserialized.append(self.deserialize_object(obj, **kwargs)) + except ValueError: + pass + return deserialized + + error = "Cannot deserialize generic object with type: " + raise TypeError(error + str(obj_type)) + + def deserialize_basic(self, attr, data_type): # pylint: disable=too-many-return-statements + """Deserialize basic builtin data type from string. + Will attempt to convert to str, int, float and bool. + This function will also accept '1', '0', 'true' and 'false' as + valid bool values. + + :param str attr: response string to be deserialized. + :param str data_type: deserialization data type. + :return: Deserialized basic type. + :rtype: str, int, float or bool + :raises TypeError: if string format is not valid. + """ + # If we're here, data is supposed to be a basic type. + # If it's still an XML node, take the text + if isinstance(attr, ET.Element): + attr = attr.text + if not attr: + if data_type == "str": + # None or '', node is empty string. + return "" + # None or '', node with a strong type is None. + # Don't try to model "empty bool" or "empty int" + return None + + if data_type == "bool": + if attr in [True, False, 1, 0]: + return bool(attr) + if isinstance(attr, str): + if attr.lower() in ["true", "1"]: + return True + if attr.lower() in ["false", "0"]: + return False + raise TypeError("Invalid boolean value: {}".format(attr)) + + if data_type == "str": + return self.deserialize_unicode(attr) + return eval(data_type)(attr) # nosec # pylint: disable=eval-used + + @staticmethod + def deserialize_unicode(data): + """Preserve unicode objects in Python 2, otherwise return data + as a string. + + :param str data: response string to be deserialized. + :return: Deserialized string. + :rtype: str or unicode + """ + # We might be here because we have an enum modeled as string, + # and we try to deserialize a partial dict with enum inside + if isinstance(data, Enum): + return data + + # Consider this is real string + try: + if isinstance(data, unicode): # type: ignore + return data + except NameError: + return str(data) + return str(data) + + @staticmethod + def deserialize_enum(data, enum_obj): + """Deserialize string into enum object. + + If the string is not a valid enum value it will be returned as-is + and a warning will be logged. + + :param str data: Response string to be deserialized. If this value is + None or invalid it will be returned as-is. + :param Enum enum_obj: Enum object to deserialize to. + :return: Deserialized enum object. + :rtype: Enum + """ + if isinstance(data, enum_obj) or data is None: + return data + if isinstance(data, Enum): + data = data.value + if isinstance(data, int): + # Workaround. We might consider remove it in the future. + try: + return list(enum_obj.__members__.values())[data] + except IndexError as exc: + error = "{!r} is not a valid index for enum {!r}" + raise DeserializationError(error.format(data, enum_obj)) from exc + try: + return enum_obj(str(data)) + except ValueError: + for enum_value in enum_obj: + if enum_value.value.lower() == str(data).lower(): + return enum_value + # We don't fail anymore for unknown value, we deserialize as a string + _LOGGER.warning("Deserializer is not able to find %s as valid enum in %s", data, enum_obj) + return Deserializer.deserialize_unicode(data) + + @staticmethod + def deserialize_bytearray(attr): + """Deserialize string into bytearray. + + :param str attr: response string to be deserialized. + :return: Deserialized bytearray + :rtype: bytearray + :raises TypeError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + return bytearray(b64decode(attr)) # type: ignore + + @staticmethod + def deserialize_base64(attr): + """Deserialize base64 encoded string into string. + + :param str attr: response string to be deserialized. + :return: Deserialized base64 string + :rtype: bytearray + :raises TypeError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + padding = "=" * (3 - (len(attr) + 3) % 4) # type: ignore + attr = attr + padding # type: ignore + encoded = attr.replace("-", "+").replace("_", "/") + return b64decode(encoded) + + @staticmethod + def deserialize_decimal(attr): + """Deserialize string into Decimal object. + + :param str attr: response string to be deserialized. + :return: Deserialized decimal + :raises DeserializationError: if string format invalid. + :rtype: decimal + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + return decimal.Decimal(str(attr)) # type: ignore + except decimal.DecimalException as err: + msg = "Invalid decimal {}".format(attr) + raise DeserializationError(msg) from err + + @staticmethod + def deserialize_long(attr): + """Deserialize string into long (Py2) or int (Py3). + + :param str attr: response string to be deserialized. + :return: Deserialized int + :rtype: long or int + :raises ValueError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + return _long_type(attr) # type: ignore + + @staticmethod + def deserialize_duration(attr): + """Deserialize ISO-8601 formatted string into TimeDelta object. + + :param str attr: response string to be deserialized. + :return: Deserialized duration + :rtype: TimeDelta + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + duration = isodate.parse_duration(attr) + except (ValueError, OverflowError, AttributeError) as err: + msg = "Cannot deserialize duration object." + raise DeserializationError(msg) from err + return duration + + @staticmethod + def deserialize_date(attr): + """Deserialize ISO-8601 formatted string into Date object. + + :param str attr: response string to be deserialized. + :return: Deserialized date + :rtype: Date + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + if re.search(r"[^\W\d_]", attr, re.I + re.U): # type: ignore + raise DeserializationError("Date must have only digits and -. Received: %s" % attr) + # This must NOT use defaultmonth/defaultday. Using None ensure this raises an exception. + return isodate.parse_date(attr, defaultmonth=0, defaultday=0) + + @staticmethod + def deserialize_time(attr): + """Deserialize ISO-8601 formatted string into time object. + + :param str attr: response string to be deserialized. + :return: Deserialized time + :rtype: datetime.time + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + if re.search(r"[^\W\d_]", attr, re.I + re.U): # type: ignore + raise DeserializationError("Date must have only digits and -. Received: %s" % attr) + return isodate.parse_time(attr) + + @staticmethod + def deserialize_rfc(attr): + """Deserialize RFC-1123 formatted string into Datetime object. + + :param str attr: response string to be deserialized. + :return: Deserialized RFC datetime + :rtype: Datetime + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + parsed_date = email.utils.parsedate_tz(attr) # type: ignore + date_obj = datetime.datetime( + *parsed_date[:6], tzinfo=datetime.timezone(datetime.timedelta(minutes=(parsed_date[9] or 0) / 60)) + ) + if not date_obj.tzinfo: + date_obj = date_obj.astimezone(tz=TZ_UTC) + except ValueError as err: + msg = "Cannot deserialize to rfc datetime object." + raise DeserializationError(msg) from err + return date_obj + + @staticmethod + def deserialize_iso(attr): + """Deserialize ISO-8601 formatted string into Datetime object. + + :param str attr: response string to be deserialized. + :return: Deserialized ISO datetime + :rtype: Datetime + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + attr = attr.upper() # type: ignore + match = Deserializer.valid_date.match(attr) + if not match: + raise ValueError("Invalid datetime string: " + attr) + + check_decimal = attr.split(".") + if len(check_decimal) > 1: + decimal_str = "" + for digit in check_decimal[1]: + if digit.isdigit(): + decimal_str += digit + else: + break + if len(decimal_str) > 6: + attr = attr.replace(decimal_str, decimal_str[0:6]) + + date_obj = isodate.parse_datetime(attr) + test_utc = date_obj.utctimetuple() + if test_utc.tm_year > 9999 or test_utc.tm_year < 1: + raise OverflowError("Hit max or min date") + except (ValueError, OverflowError, AttributeError) as err: + msg = "Cannot deserialize datetime object." + raise DeserializationError(msg) from err + return date_obj + + @staticmethod + def deserialize_unix(attr): + """Serialize Datetime object into IntTime format. + This is represented as seconds. + + :param int attr: Object to be serialized. + :return: Deserialized datetime + :rtype: Datetime + :raises DeserializationError: if format invalid + """ + if isinstance(attr, ET.Element): + attr = int(attr.text) # type: ignore + try: + attr = int(attr) + date_obj = datetime.datetime.fromtimestamp(attr, TZ_UTC) + except ValueError as err: + msg = "Cannot deserialize to unix datetime object." + raise DeserializationError(msg) from err + return date_obj diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/SecurityKeySwaggerVersionTolerant/securitykeyswaggerversiontolerant/_utils/utils.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/SecurityKeySwaggerVersionTolerant/securitykeyswaggerversiontolerant/_utils/utils.py new file mode 100644 index 00000000000..39b612f39a9 --- /dev/null +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/SecurityKeySwaggerVersionTolerant/securitykeyswaggerversiontolerant/_utils/utils.py @@ -0,0 +1,25 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from abc import ABC +from typing import Generic, TYPE_CHECKING, TypeVar + +if TYPE_CHECKING: + from .serialization import Deserializer, Serializer + + +TClient = TypeVar("TClient") +TConfig = TypeVar("TConfig") + + +class ClientMixinABC(ABC, Generic[TClient, TConfig]): + """DO NOT use this class. It is for internal typing use only.""" + + _client: TClient + _config: TConfig + _serialize: "Serializer" + _deserialize: "Deserializer" diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/SecurityKeySwaggerVersionTolerant/securitykeyswaggerversiontolerant/_vendor.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/SecurityKeySwaggerVersionTolerant/securitykeyswaggerversiontolerant/_vendor.py deleted file mode 100644 index d615edd04da..00000000000 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/SecurityKeySwaggerVersionTolerant/securitykeyswaggerversiontolerant/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) AutoRest Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import AutorestSecurityKeyConfiguration - -if TYPE_CHECKING: - from azure.core import PipelineClient - - from ._serialization import Deserializer, Serializer - - -class AutorestSecurityKeyMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "PipelineClient" - _config: AutorestSecurityKeyConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/SecurityKeySwaggerVersionTolerant/securitykeyswaggerversiontolerant/aio/_client.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/SecurityKeySwaggerVersionTolerant/securitykeyswaggerversiontolerant/aio/_client.py index bd268f10c34..043d82cb84d 100644 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/SecurityKeySwaggerVersionTolerant/securitykeyswaggerversiontolerant/aio/_client.py +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/SecurityKeySwaggerVersionTolerant/securitykeyswaggerversiontolerant/aio/_client.py @@ -15,7 +15,7 @@ from azure.core.pipeline import policies from azure.core.rest import AsyncHttpResponse, HttpRequest -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import AutorestSecurityKeyConfiguration from ._operations import AutorestSecurityKeyOperationsMixin diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/SecurityKeySwaggerVersionTolerant/securitykeyswaggerversiontolerant/aio/_operations/_operations.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/SecurityKeySwaggerVersionTolerant/securitykeyswaggerversiontolerant/aio/_operations/_operations.py index ff666a72169..97964089679 100644 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/SecurityKeySwaggerVersionTolerant/securitykeyswaggerversiontolerant/aio/_operations/_operations.py +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/SecurityKeySwaggerVersionTolerant/securitykeyswaggerversiontolerant/aio/_operations/_operations.py @@ -9,6 +9,7 @@ from collections.abc import MutableMapping from typing import Any, Callable, Dict, Optional, TypeVar +from azure.core import AsyncPipelineClient from azure.core.exceptions import ( ClientAuthenticationError, HttpResponseError, @@ -22,13 +23,14 @@ from azure.core.tracing.decorator_async import distributed_trace_async from ..._operations._operations import build_autorest_security_key_head_request -from .._vendor import AutorestSecurityKeyMixinABC +from ..._utils.utils import ClientMixinABC +from .._configuration import AutorestSecurityKeyConfiguration T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, AsyncHttpResponse], T, Dict[str, Any]], Any]] -class AutorestSecurityKeyOperationsMixin(AutorestSecurityKeyMixinABC): +class AutorestSecurityKeyOperationsMixin(ClientMixinABC[AsyncPipelineClient, AutorestSecurityKeyConfiguration]): @distributed_trace_async async def head(self, **kwargs: Any) -> None: diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/SecurityKeySwaggerVersionTolerant/securitykeyswaggerversiontolerant/aio/_vendor.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/SecurityKeySwaggerVersionTolerant/securitykeyswaggerversiontolerant/aio/_vendor.py deleted file mode 100644 index cf209892619..00000000000 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/SecurityKeySwaggerVersionTolerant/securitykeyswaggerversiontolerant/aio/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) AutoRest Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import AutorestSecurityKeyConfiguration - -if TYPE_CHECKING: - from azure.core import AsyncPipelineClient - - from .._serialization import Deserializer, Serializer - - -class AutorestSecurityKeyMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "AsyncPipelineClient" - _config: AutorestSecurityKeyConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/UrlMultiCollectionFormatVersionTolerant/urlmulticollectionformatversiontolerant/_client.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/UrlMultiCollectionFormatVersionTolerant/urlmulticollectionformatversiontolerant/_client.py index 23698cca27c..c3b3286bc29 100644 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/UrlMultiCollectionFormatVersionTolerant/urlmulticollectionformatversiontolerant/_client.py +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/UrlMultiCollectionFormatVersionTolerant/urlmulticollectionformatversiontolerant/_client.py @@ -15,7 +15,7 @@ from azure.core.rest import HttpRequest, HttpResponse from ._configuration import AutoRestUrlMutliCollectionFormatTestServiceConfiguration -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer from .operations import QueriesOperations diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/UrlMultiCollectionFormatVersionTolerant/urlmulticollectionformatversiontolerant/_utils/__init__.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/UrlMultiCollectionFormatVersionTolerant/urlmulticollectionformatversiontolerant/_utils/__init__.py new file mode 100644 index 00000000000..0af9b28f660 --- /dev/null +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/UrlMultiCollectionFormatVersionTolerant/urlmulticollectionformatversiontolerant/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/UrlMultiCollectionFormatVersionTolerant/urlmulticollectionformatversiontolerant/_utils/serialization.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/UrlMultiCollectionFormatVersionTolerant/urlmulticollectionformatversiontolerant/_utils/serialization.py new file mode 100644 index 00000000000..f5187701d7b --- /dev/null +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/UrlMultiCollectionFormatVersionTolerant/urlmulticollectionformatversiontolerant/_utils/serialization.py @@ -0,0 +1,2032 @@ +# pylint: disable=line-too-long,useless-suppression,too-many-lines +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +# pyright: reportUnnecessaryTypeIgnoreComment=false + +from base64 import b64decode, b64encode +import calendar +import datetime +import decimal +import email +from enum import Enum +import json +import logging +import re +import sys +import codecs +from typing import ( + Dict, + Any, + cast, + Optional, + Union, + AnyStr, + IO, + Mapping, + Callable, + MutableMapping, + List, +) + +try: + from urllib import quote # type: ignore +except ImportError: + from urllib.parse import quote +import xml.etree.ElementTree as ET + +import isodate # type: ignore +from typing_extensions import Self + +from azure.core.exceptions import DeserializationError, SerializationError +from azure.core.serialization import NULL as CoreNull + +_BOM = codecs.BOM_UTF8.decode(encoding="utf-8") + +JSON = MutableMapping[str, Any] + + +class RawDeserializer: + + # Accept "text" because we're open minded people... + JSON_REGEXP = re.compile(r"^(application|text)/([a-z+.]+\+)?json$") + + # Name used in context + CONTEXT_NAME = "deserialized_data" + + @classmethod + def deserialize_from_text(cls, data: Optional[Union[AnyStr, IO]], content_type: Optional[str] = None) -> Any: + """Decode data according to content-type. + + Accept a stream of data as well, but will be load at once in memory for now. + + If no content-type, will return the string version (not bytes, not stream) + + :param data: Input, could be bytes or stream (will be decoded with UTF8) or text + :type data: str or bytes or IO + :param str content_type: The content type. + :return: The deserialized data. + :rtype: object + """ + if hasattr(data, "read"): + # Assume a stream + data = cast(IO, data).read() + + if isinstance(data, bytes): + data_as_str = data.decode(encoding="utf-8-sig") + else: + # Explain to mypy the correct type. + data_as_str = cast(str, data) + + # Remove Byte Order Mark if present in string + data_as_str = data_as_str.lstrip(_BOM) + + if content_type is None: + return data + + if cls.JSON_REGEXP.match(content_type): + try: + return json.loads(data_as_str) + except ValueError as err: + raise DeserializationError("JSON is invalid: {}".format(err), err) from err + elif "xml" in (content_type or []): + try: + + try: + if isinstance(data, unicode): # type: ignore + # If I'm Python 2.7 and unicode XML will scream if I try a "fromstring" on unicode string + data_as_str = data_as_str.encode(encoding="utf-8") # type: ignore + except NameError: + pass + + return ET.fromstring(data_as_str) # nosec + except ET.ParseError as err: + # It might be because the server has an issue, and returned JSON with + # content-type XML.... + # So let's try a JSON load, and if it's still broken + # let's flow the initial exception + def _json_attemp(data): + try: + return True, json.loads(data) + except ValueError: + return False, None # Don't care about this one + + success, json_result = _json_attemp(data) + if success: + return json_result + # If i'm here, it's not JSON, it's not XML, let's scream + # and raise the last context in this block (the XML exception) + # The function hack is because Py2.7 messes up with exception + # context otherwise. + _LOGGER.critical("Wasn't XML not JSON, failing") + raise DeserializationError("XML is invalid") from err + elif content_type.startswith("text/"): + return data_as_str + raise DeserializationError("Cannot deserialize content-type: {}".format(content_type)) + + @classmethod + def deserialize_from_http_generics(cls, body_bytes: Optional[Union[AnyStr, IO]], headers: Mapping) -> Any: + """Deserialize from HTTP response. + + Use bytes and headers to NOT use any requests/aiohttp or whatever + specific implementation. + Headers will tested for "content-type" + + :param bytes body_bytes: The body of the response. + :param dict headers: The headers of the response. + :returns: The deserialized data. + :rtype: object + """ + # Try to use content-type from headers if available + content_type = None + if "content-type" in headers: + content_type = headers["content-type"].split(";")[0].strip().lower() + # Ouch, this server did not declare what it sent... + # Let's guess it's JSON... + # Also, since Autorest was considering that an empty body was a valid JSON, + # need that test as well.... + else: + content_type = "application/json" + + if body_bytes: + return cls.deserialize_from_text(body_bytes, content_type) + return None + + +_LOGGER = logging.getLogger(__name__) + +try: + _long_type = long # type: ignore +except NameError: + _long_type = int + +TZ_UTC = datetime.timezone.utc + +_FLATTEN = re.compile(r"(? None: + self.additional_properties: Optional[Dict[str, Any]] = {} + for k in kwargs: # pylint: disable=consider-using-dict-items + if k not in self._attribute_map: + _LOGGER.warning("%s is not a known attribute of class %s and will be ignored", k, self.__class__) + elif k in self._validation and self._validation[k].get("readonly", False): + _LOGGER.warning("Readonly attribute %s will be ignored in class %s", k, self.__class__) + else: + setattr(self, k, kwargs[k]) + + def __eq__(self, other: Any) -> bool: + """Compare objects by comparing all attributes. + + :param object other: The object to compare + :returns: True if objects are equal + :rtype: bool + """ + if isinstance(other, self.__class__): + return self.__dict__ == other.__dict__ + return False + + def __ne__(self, other: Any) -> bool: + """Compare objects by comparing all attributes. + + :param object other: The object to compare + :returns: True if objects are not equal + :rtype: bool + """ + return not self.__eq__(other) + + def __str__(self) -> str: + return str(self.__dict__) + + @classmethod + def enable_additional_properties_sending(cls) -> None: + cls._attribute_map["additional_properties"] = {"key": "", "type": "{object}"} + + @classmethod + def is_xml_model(cls) -> bool: + try: + cls._xml_map # type: ignore + except AttributeError: + return False + return True + + @classmethod + def _create_xml_node(cls): + """Create XML node. + + :returns: The XML node + :rtype: xml.etree.ElementTree.Element + """ + try: + xml_map = cls._xml_map # type: ignore + except AttributeError: + xml_map = {} + + return _create_xml_node(xml_map.get("name", cls.__name__), xml_map.get("prefix", None), xml_map.get("ns", None)) + + def serialize(self, keep_readonly: bool = False, **kwargs: Any) -> JSON: + """Return the JSON that would be sent to server from this model. + + This is an alias to `as_dict(full_restapi_key_transformer, keep_readonly=False)`. + + If you want XML serialization, you can pass the kwargs is_xml=True. + + :param bool keep_readonly: If you want to serialize the readonly attributes + :returns: A dict JSON compatible object + :rtype: dict + """ + serializer = Serializer(self._infer_class_models()) + return serializer._serialize( # type: ignore # pylint: disable=protected-access + self, keep_readonly=keep_readonly, **kwargs + ) + + def as_dict( + self, + keep_readonly: bool = True, + key_transformer: Callable[[str, Dict[str, Any], Any], Any] = attribute_transformer, + **kwargs: Any + ) -> JSON: + """Return a dict that can be serialized using json.dump. + + Advanced usage might optionally use a callback as parameter: + + .. code::python + + def my_key_transformer(key, attr_desc, value): + return key + + Key is the attribute name used in Python. Attr_desc + is a dict of metadata. Currently contains 'type' with the + msrest type and 'key' with the RestAPI encoded key. + Value is the current value in this object. + + The string returned will be used to serialize the key. + If the return type is a list, this is considered hierarchical + result dict. + + See the three examples in this file: + + - attribute_transformer + - full_restapi_key_transformer + - last_restapi_key_transformer + + If you want XML serialization, you can pass the kwargs is_xml=True. + + :param bool keep_readonly: If you want to serialize the readonly attributes + :param function key_transformer: A key transformer function. + :returns: A dict JSON compatible object + :rtype: dict + """ + serializer = Serializer(self._infer_class_models()) + return serializer._serialize( # type: ignore # pylint: disable=protected-access + self, key_transformer=key_transformer, keep_readonly=keep_readonly, **kwargs + ) + + @classmethod + def _infer_class_models(cls): + try: + str_models = cls.__module__.rsplit(".", 1)[0] + models = sys.modules[str_models] + client_models = {k: v for k, v in models.__dict__.items() if isinstance(v, type)} + if cls.__name__ not in client_models: + raise ValueError("Not Autorest generated code") + except Exception: # pylint: disable=broad-exception-caught + # Assume it's not Autorest generated (tests?). Add ourselves as dependencies. + client_models = {cls.__name__: cls} + return client_models + + @classmethod + def deserialize(cls, data: Any, content_type: Optional[str] = None) -> Self: + """Parse a str using the RestAPI syntax and return a model. + + :param str data: A str using RestAPI structure. JSON by default. + :param str content_type: JSON by default, set application/xml if XML. + :returns: An instance of this model + :raises DeserializationError: if something went wrong + :rtype: Self + """ + deserializer = Deserializer(cls._infer_class_models()) + return deserializer(cls.__name__, data, content_type=content_type) # type: ignore + + @classmethod + def from_dict( + cls, + data: Any, + key_extractors: Optional[Callable[[str, Dict[str, Any], Any], Any]] = None, + content_type: Optional[str] = None, + ) -> Self: + """Parse a dict using given key extractor return a model. + + By default consider key + extractors (rest_key_case_insensitive_extractor, attribute_key_case_insensitive_extractor + and last_rest_key_case_insensitive_extractor) + + :param dict data: A dict using RestAPI structure + :param function key_extractors: A key extractor function. + :param str content_type: JSON by default, set application/xml if XML. + :returns: An instance of this model + :raises DeserializationError: if something went wrong + :rtype: Self + """ + deserializer = Deserializer(cls._infer_class_models()) + deserializer.key_extractors = ( # type: ignore + [ # type: ignore + attribute_key_case_insensitive_extractor, + rest_key_case_insensitive_extractor, + last_rest_key_case_insensitive_extractor, + ] + if key_extractors is None + else key_extractors + ) + return deserializer(cls.__name__, data, content_type=content_type) # type: ignore + + @classmethod + def _flatten_subtype(cls, key, objects): + if "_subtype_map" not in cls.__dict__: + return {} + result = dict(cls._subtype_map[key]) + for valuetype in cls._subtype_map[key].values(): + result.update(objects[valuetype]._flatten_subtype(key, objects)) # pylint: disable=protected-access + return result + + @classmethod + def _classify(cls, response, objects): + """Check the class _subtype_map for any child classes. + We want to ignore any inherited _subtype_maps. + + :param dict response: The initial data + :param dict objects: The class objects + :returns: The class to be used + :rtype: class + """ + for subtype_key in cls.__dict__.get("_subtype_map", {}).keys(): + subtype_value = None + + if not isinstance(response, ET.Element): + rest_api_response_key = cls._get_rest_key_parts(subtype_key)[-1] + subtype_value = response.get(rest_api_response_key, None) or response.get(subtype_key, None) + else: + subtype_value = xml_key_extractor(subtype_key, cls._attribute_map[subtype_key], response) + if subtype_value: + # Try to match base class. Can be class name only + # (bug to fix in Autorest to support x-ms-discriminator-name) + if cls.__name__ == subtype_value: + return cls + flatten_mapping_type = cls._flatten_subtype(subtype_key, objects) + try: + return objects[flatten_mapping_type[subtype_value]] # type: ignore + except KeyError: + _LOGGER.warning( + "Subtype value %s has no mapping, use base class %s.", + subtype_value, + cls.__name__, + ) + break + else: + _LOGGER.warning("Discriminator %s is absent or null, use base class %s.", subtype_key, cls.__name__) + break + return cls + + @classmethod + def _get_rest_key_parts(cls, attr_key): + """Get the RestAPI key of this attr, split it and decode part + :param str attr_key: Attribute key must be in attribute_map. + :returns: A list of RestAPI part + :rtype: list + """ + rest_split_key = _FLATTEN.split(cls._attribute_map[attr_key]["key"]) + return [_decode_attribute_map_key(key_part) for key_part in rest_split_key] + + +def _decode_attribute_map_key(key): + """This decode a key in an _attribute_map to the actual key we want to look at + inside the received data. + + :param str key: A key string from the generated code + :returns: The decoded key + :rtype: str + """ + return key.replace("\\.", ".") + + +class Serializer: # pylint: disable=too-many-public-methods + """Request object model serializer.""" + + basic_types = {str: "str", int: "int", bool: "bool", float: "float"} + + _xml_basic_types_serializers = {"bool": lambda x: str(x).lower()} + days = {0: "Mon", 1: "Tue", 2: "Wed", 3: "Thu", 4: "Fri", 5: "Sat", 6: "Sun"} + months = { + 1: "Jan", + 2: "Feb", + 3: "Mar", + 4: "Apr", + 5: "May", + 6: "Jun", + 7: "Jul", + 8: "Aug", + 9: "Sep", + 10: "Oct", + 11: "Nov", + 12: "Dec", + } + validation = { + "min_length": lambda x, y: len(x) < y, + "max_length": lambda x, y: len(x) > y, + "minimum": lambda x, y: x < y, + "maximum": lambda x, y: x > y, + "minimum_ex": lambda x, y: x <= y, + "maximum_ex": lambda x, y: x >= y, + "min_items": lambda x, y: len(x) < y, + "max_items": lambda x, y: len(x) > y, + "pattern": lambda x, y: not re.match(y, x, re.UNICODE), + "unique": lambda x, y: len(x) != len(set(x)), + "multiple": lambda x, y: x % y != 0, + } + + def __init__(self, classes: Optional[Mapping[str, type]] = None) -> None: + self.serialize_type = { + "iso-8601": Serializer.serialize_iso, + "rfc-1123": Serializer.serialize_rfc, + "unix-time": Serializer.serialize_unix, + "duration": Serializer.serialize_duration, + "date": Serializer.serialize_date, + "time": Serializer.serialize_time, + "decimal": Serializer.serialize_decimal, + "long": Serializer.serialize_long, + "bytearray": Serializer.serialize_bytearray, + "base64": Serializer.serialize_base64, + "object": self.serialize_object, + "[]": self.serialize_iter, + "{}": self.serialize_dict, + } + self.dependencies: Dict[str, type] = dict(classes) if classes else {} + self.key_transformer = full_restapi_key_transformer + self.client_side_validation = True + + def _serialize( # pylint: disable=too-many-nested-blocks, too-many-branches, too-many-statements, too-many-locals + self, target_obj, data_type=None, **kwargs + ): + """Serialize data into a string according to type. + + :param object target_obj: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str, dict + :raises SerializationError: if serialization fails. + :returns: The serialized data. + """ + key_transformer = kwargs.get("key_transformer", self.key_transformer) + keep_readonly = kwargs.get("keep_readonly", False) + if target_obj is None: + return None + + attr_name = None + class_name = target_obj.__class__.__name__ + + if data_type: + return self.serialize_data(target_obj, data_type, **kwargs) + + if not hasattr(target_obj, "_attribute_map"): + data_type = type(target_obj).__name__ + if data_type in self.basic_types.values(): + return self.serialize_data(target_obj, data_type, **kwargs) + + # Force "is_xml" kwargs if we detect a XML model + try: + is_xml_model_serialization = kwargs["is_xml"] + except KeyError: + is_xml_model_serialization = kwargs.setdefault("is_xml", target_obj.is_xml_model()) + + serialized = {} + if is_xml_model_serialization: + serialized = target_obj._create_xml_node() # pylint: disable=protected-access + try: + attributes = target_obj._attribute_map # pylint: disable=protected-access + for attr, attr_desc in attributes.items(): + attr_name = attr + if not keep_readonly and target_obj._validation.get( # pylint: disable=protected-access + attr_name, {} + ).get("readonly", False): + continue + + if attr_name == "additional_properties" and attr_desc["key"] == "": + if target_obj.additional_properties is not None: + serialized.update(target_obj.additional_properties) + continue + try: + + orig_attr = getattr(target_obj, attr) + if is_xml_model_serialization: + pass # Don't provide "transformer" for XML for now. Keep "orig_attr" + else: # JSON + keys, orig_attr = key_transformer(attr, attr_desc.copy(), orig_attr) + keys = keys if isinstance(keys, list) else [keys] + + kwargs["serialization_ctxt"] = attr_desc + new_attr = self.serialize_data(orig_attr, attr_desc["type"], **kwargs) + + if is_xml_model_serialization: + xml_desc = attr_desc.get("xml", {}) + xml_name = xml_desc.get("name", attr_desc["key"]) + xml_prefix = xml_desc.get("prefix", None) + xml_ns = xml_desc.get("ns", None) + if xml_desc.get("attr", False): + if xml_ns: + ET.register_namespace(xml_prefix, xml_ns) + xml_name = "{{{}}}{}".format(xml_ns, xml_name) + serialized.set(xml_name, new_attr) # type: ignore + continue + if xml_desc.get("text", False): + serialized.text = new_attr # type: ignore + continue + if isinstance(new_attr, list): + serialized.extend(new_attr) # type: ignore + elif isinstance(new_attr, ET.Element): + # If the down XML has no XML/Name, + # we MUST replace the tag with the local tag. But keeping the namespaces. + if "name" not in getattr(orig_attr, "_xml_map", {}): + splitted_tag = new_attr.tag.split("}") + if len(splitted_tag) == 2: # Namespace + new_attr.tag = "}".join([splitted_tag[0], xml_name]) + else: + new_attr.tag = xml_name + serialized.append(new_attr) # type: ignore + else: # That's a basic type + # Integrate namespace if necessary + local_node = _create_xml_node(xml_name, xml_prefix, xml_ns) + local_node.text = str(new_attr) + serialized.append(local_node) # type: ignore + else: # JSON + for k in reversed(keys): # type: ignore + new_attr = {k: new_attr} + + _new_attr = new_attr + _serialized = serialized + for k in keys: # type: ignore + if k not in _serialized: + _serialized.update(_new_attr) # type: ignore + _new_attr = _new_attr[k] # type: ignore + _serialized = _serialized[k] + except ValueError as err: + if isinstance(err, SerializationError): + raise + + except (AttributeError, KeyError, TypeError) as err: + msg = "Attribute {} in object {} cannot be serialized.\n{}".format(attr_name, class_name, str(target_obj)) + raise SerializationError(msg) from err + return serialized + + def body(self, data, data_type, **kwargs): + """Serialize data intended for a request body. + + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: dict + :raises SerializationError: if serialization fails. + :raises ValueError: if data is None + :returns: The serialized request body + """ + + # Just in case this is a dict + internal_data_type_str = data_type.strip("[]{}") + internal_data_type = self.dependencies.get(internal_data_type_str, None) + try: + is_xml_model_serialization = kwargs["is_xml"] + except KeyError: + if internal_data_type and issubclass(internal_data_type, Model): + is_xml_model_serialization = kwargs.setdefault("is_xml", internal_data_type.is_xml_model()) + else: + is_xml_model_serialization = False + if internal_data_type and not isinstance(internal_data_type, Enum): + try: + deserializer = Deserializer(self.dependencies) + # Since it's on serialization, it's almost sure that format is not JSON REST + # We're not able to deal with additional properties for now. + deserializer.additional_properties_detection = False + if is_xml_model_serialization: + deserializer.key_extractors = [ # type: ignore + attribute_key_case_insensitive_extractor, + ] + else: + deserializer.key_extractors = [ + rest_key_case_insensitive_extractor, + attribute_key_case_insensitive_extractor, + last_rest_key_case_insensitive_extractor, + ] + data = deserializer._deserialize(data_type, data) # pylint: disable=protected-access + except DeserializationError as err: + raise SerializationError("Unable to build a model: " + str(err)) from err + + return self._serialize(data, data_type, **kwargs) + + def url(self, name, data, data_type, **kwargs): + """Serialize data intended for a URL path. + + :param str name: The name of the URL path parameter. + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str + :returns: The serialized URL path + :raises TypeError: if serialization fails. + :raises ValueError: if data is None + """ + try: + output = self.serialize_data(data, data_type, **kwargs) + if data_type == "bool": + output = json.dumps(output) + + if kwargs.get("skip_quote") is True: + output = str(output) + output = output.replace("{", quote("{")).replace("}", quote("}")) + else: + output = quote(str(output), safe="") + except SerializationError as exc: + raise TypeError("{} must be type {}.".format(name, data_type)) from exc + return output + + def query(self, name, data, data_type, **kwargs): + """Serialize data intended for a URL query. + + :param str name: The name of the query parameter. + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str, list + :raises TypeError: if serialization fails. + :raises ValueError: if data is None + :returns: The serialized query parameter + """ + try: + # Treat the list aside, since we don't want to encode the div separator + if data_type.startswith("["): + internal_data_type = data_type[1:-1] + do_quote = not kwargs.get("skip_quote", False) + return self.serialize_iter(data, internal_data_type, do_quote=do_quote, **kwargs) + + # Not a list, regular serialization + output = self.serialize_data(data, data_type, **kwargs) + if data_type == "bool": + output = json.dumps(output) + if kwargs.get("skip_quote") is True: + output = str(output) + else: + output = quote(str(output), safe="") + except SerializationError as exc: + raise TypeError("{} must be type {}.".format(name, data_type)) from exc + return str(output) + + def header(self, name, data, data_type, **kwargs): + """Serialize data intended for a request header. + + :param str name: The name of the header. + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str + :raises TypeError: if serialization fails. + :raises ValueError: if data is None + :returns: The serialized header + """ + try: + if data_type in ["[str]"]: + data = ["" if d is None else d for d in data] + + output = self.serialize_data(data, data_type, **kwargs) + if data_type == "bool": + output = json.dumps(output) + except SerializationError as exc: + raise TypeError("{} must be type {}.".format(name, data_type)) from exc + return str(output) + + def serialize_data(self, data, data_type, **kwargs): + """Serialize generic data according to supplied data type. + + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :raises AttributeError: if required data is None. + :raises ValueError: if data is None + :raises SerializationError: if serialization fails. + :returns: The serialized data. + :rtype: str, int, float, bool, dict, list + """ + if data is None: + raise ValueError("No value for given attribute") + + try: + if data is CoreNull: + return None + if data_type in self.basic_types.values(): + return self.serialize_basic(data, data_type, **kwargs) + + if data_type in self.serialize_type: + return self.serialize_type[data_type](data, **kwargs) + + # If dependencies is empty, try with current data class + # It has to be a subclass of Enum anyway + enum_type = self.dependencies.get(data_type, data.__class__) + if issubclass(enum_type, Enum): + return Serializer.serialize_enum(data, enum_obj=enum_type) + + iter_type = data_type[0] + data_type[-1] + if iter_type in self.serialize_type: + return self.serialize_type[iter_type](data, data_type[1:-1], **kwargs) + + except (ValueError, TypeError) as err: + msg = "Unable to serialize value: {!r} as type: {!r}." + raise SerializationError(msg.format(data, data_type)) from err + return self._serialize(data, **kwargs) + + @classmethod + def _get_custom_serializers(cls, data_type, **kwargs): # pylint: disable=inconsistent-return-statements + custom_serializer = kwargs.get("basic_types_serializers", {}).get(data_type) + if custom_serializer: + return custom_serializer + if kwargs.get("is_xml", False): + return cls._xml_basic_types_serializers.get(data_type) + + @classmethod + def serialize_basic(cls, data, data_type, **kwargs): + """Serialize basic builting data type. + Serializes objects to str, int, float or bool. + + Possible kwargs: + - basic_types_serializers dict[str, callable] : If set, use the callable as serializer + - is_xml bool : If set, use xml_basic_types_serializers + + :param obj data: Object to be serialized. + :param str data_type: Type of object in the iterable. + :rtype: str, int, float, bool + :return: serialized object + """ + custom_serializer = cls._get_custom_serializers(data_type, **kwargs) + if custom_serializer: + return custom_serializer(data) + if data_type == "str": + return cls.serialize_unicode(data) + return eval(data_type)(data) # nosec # pylint: disable=eval-used + + @classmethod + def serialize_unicode(cls, data): + """Special handling for serializing unicode strings in Py2. + Encode to UTF-8 if unicode, otherwise handle as a str. + + :param str data: Object to be serialized. + :rtype: str + :return: serialized object + """ + try: # If I received an enum, return its value + return data.value + except AttributeError: + pass + + try: + if isinstance(data, unicode): # type: ignore + # Don't change it, JSON and XML ElementTree are totally able + # to serialize correctly u'' strings + return data + except NameError: + return str(data) + return str(data) + + def serialize_iter(self, data, iter_type, div=None, **kwargs): + """Serialize iterable. + + Supported kwargs: + - serialization_ctxt dict : The current entry of _attribute_map, or same format. + serialization_ctxt['type'] should be same as data_type. + - is_xml bool : If set, serialize as XML + + :param list data: Object to be serialized. + :param str iter_type: Type of object in the iterable. + :param str div: If set, this str will be used to combine the elements + in the iterable into a combined string. Default is 'None'. + Defaults to False. + :rtype: list, str + :return: serialized iterable + """ + if isinstance(data, str): + raise SerializationError("Refuse str type as a valid iter type.") + + serialization_ctxt = kwargs.get("serialization_ctxt", {}) + is_xml = kwargs.get("is_xml", False) + + serialized = [] + for d in data: + try: + serialized.append(self.serialize_data(d, iter_type, **kwargs)) + except ValueError as err: + if isinstance(err, SerializationError): + raise + serialized.append(None) + + if kwargs.get("do_quote", False): + serialized = ["" if s is None else quote(str(s), safe="") for s in serialized] + + if div: + serialized = ["" if s is None else str(s) for s in serialized] + serialized = div.join(serialized) + + if "xml" in serialization_ctxt or is_xml: + # XML serialization is more complicated + xml_desc = serialization_ctxt.get("xml", {}) + xml_name = xml_desc.get("name") + if not xml_name: + xml_name = serialization_ctxt["key"] + + # Create a wrap node if necessary (use the fact that Element and list have "append") + is_wrapped = xml_desc.get("wrapped", False) + node_name = xml_desc.get("itemsName", xml_name) + if is_wrapped: + final_result = _create_xml_node(xml_name, xml_desc.get("prefix", None), xml_desc.get("ns", None)) + else: + final_result = [] + # All list elements to "local_node" + for el in serialized: + if isinstance(el, ET.Element): + el_node = el + else: + el_node = _create_xml_node(node_name, xml_desc.get("prefix", None), xml_desc.get("ns", None)) + if el is not None: # Otherwise it writes "None" :-p + el_node.text = str(el) + final_result.append(el_node) + return final_result + return serialized + + def serialize_dict(self, attr, dict_type, **kwargs): + """Serialize a dictionary of objects. + + :param dict attr: Object to be serialized. + :param str dict_type: Type of object in the dictionary. + :rtype: dict + :return: serialized dictionary + """ + serialization_ctxt = kwargs.get("serialization_ctxt", {}) + serialized = {} + for key, value in attr.items(): + try: + serialized[self.serialize_unicode(key)] = self.serialize_data(value, dict_type, **kwargs) + except ValueError as err: + if isinstance(err, SerializationError): + raise + serialized[self.serialize_unicode(key)] = None + + if "xml" in serialization_ctxt: + # XML serialization is more complicated + xml_desc = serialization_ctxt["xml"] + xml_name = xml_desc["name"] + + final_result = _create_xml_node(xml_name, xml_desc.get("prefix", None), xml_desc.get("ns", None)) + for key, value in serialized.items(): + ET.SubElement(final_result, key).text = value + return final_result + + return serialized + + def serialize_object(self, attr, **kwargs): # pylint: disable=too-many-return-statements + """Serialize a generic object. + This will be handled as a dictionary. If object passed in is not + a basic type (str, int, float, dict, list) it will simply be + cast to str. + + :param dict attr: Object to be serialized. + :rtype: dict or str + :return: serialized object + """ + if attr is None: + return None + if isinstance(attr, ET.Element): + return attr + obj_type = type(attr) + if obj_type in self.basic_types: + return self.serialize_basic(attr, self.basic_types[obj_type], **kwargs) + if obj_type is _long_type: + return self.serialize_long(attr) + if obj_type is str: + return self.serialize_unicode(attr) + if obj_type is datetime.datetime: + return self.serialize_iso(attr) + if obj_type is datetime.date: + return self.serialize_date(attr) + if obj_type is datetime.time: + return self.serialize_time(attr) + if obj_type is datetime.timedelta: + return self.serialize_duration(attr) + if obj_type is decimal.Decimal: + return self.serialize_decimal(attr) + + # If it's a model or I know this dependency, serialize as a Model + if obj_type in self.dependencies.values() or isinstance(attr, Model): + return self._serialize(attr) + + if obj_type == dict: + serialized = {} + for key, value in attr.items(): + try: + serialized[self.serialize_unicode(key)] = self.serialize_object(value, **kwargs) + except ValueError: + serialized[self.serialize_unicode(key)] = None + return serialized + + if obj_type == list: + serialized = [] + for obj in attr: + try: + serialized.append(self.serialize_object(obj, **kwargs)) + except ValueError: + pass + return serialized + return str(attr) + + @staticmethod + def serialize_enum(attr, enum_obj=None): + try: + result = attr.value + except AttributeError: + result = attr + try: + enum_obj(result) # type: ignore + return result + except ValueError as exc: + for enum_value in enum_obj: # type: ignore + if enum_value.value.lower() == str(attr).lower(): + return enum_value.value + error = "{!r} is not valid value for enum {!r}" + raise SerializationError(error.format(attr, enum_obj)) from exc + + @staticmethod + def serialize_bytearray(attr, **kwargs): # pylint: disable=unused-argument + """Serialize bytearray into base-64 string. + + :param str attr: Object to be serialized. + :rtype: str + :return: serialized base64 + """ + return b64encode(attr).decode() + + @staticmethod + def serialize_base64(attr, **kwargs): # pylint: disable=unused-argument + """Serialize str into base-64 string. + + :param str attr: Object to be serialized. + :rtype: str + :return: serialized base64 + """ + encoded = b64encode(attr).decode("ascii") + return encoded.strip("=").replace("+", "-").replace("/", "_") + + @staticmethod + def serialize_decimal(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Decimal object to float. + + :param decimal attr: Object to be serialized. + :rtype: float + :return: serialized decimal + """ + return float(attr) + + @staticmethod + def serialize_long(attr, **kwargs): # pylint: disable=unused-argument + """Serialize long (Py2) or int (Py3). + + :param int attr: Object to be serialized. + :rtype: int/long + :return: serialized long + """ + return _long_type(attr) + + @staticmethod + def serialize_date(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Date object into ISO-8601 formatted string. + + :param Date attr: Object to be serialized. + :rtype: str + :return: serialized date + """ + if isinstance(attr, str): + attr = isodate.parse_date(attr) + t = "{:04}-{:02}-{:02}".format(attr.year, attr.month, attr.day) + return t + + @staticmethod + def serialize_time(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Time object into ISO-8601 formatted string. + + :param datetime.time attr: Object to be serialized. + :rtype: str + :return: serialized time + """ + if isinstance(attr, str): + attr = isodate.parse_time(attr) + t = "{:02}:{:02}:{:02}".format(attr.hour, attr.minute, attr.second) + if attr.microsecond: + t += ".{:02}".format(attr.microsecond) + return t + + @staticmethod + def serialize_duration(attr, **kwargs): # pylint: disable=unused-argument + """Serialize TimeDelta object into ISO-8601 formatted string. + + :param TimeDelta attr: Object to be serialized. + :rtype: str + :return: serialized duration + """ + if isinstance(attr, str): + attr = isodate.parse_duration(attr) + return isodate.duration_isoformat(attr) + + @staticmethod + def serialize_rfc(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Datetime object into RFC-1123 formatted string. + + :param Datetime attr: Object to be serialized. + :rtype: str + :raises TypeError: if format invalid. + :return: serialized rfc + """ + try: + if not attr.tzinfo: + _LOGGER.warning("Datetime with no tzinfo will be considered UTC.") + utc = attr.utctimetuple() + except AttributeError as exc: + raise TypeError("RFC1123 object must be valid Datetime object.") from exc + + return "{}, {:02} {} {:04} {:02}:{:02}:{:02} GMT".format( + Serializer.days[utc.tm_wday], + utc.tm_mday, + Serializer.months[utc.tm_mon], + utc.tm_year, + utc.tm_hour, + utc.tm_min, + utc.tm_sec, + ) + + @staticmethod + def serialize_iso(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Datetime object into ISO-8601 formatted string. + + :param Datetime attr: Object to be serialized. + :rtype: str + :raises SerializationError: if format invalid. + :return: serialized iso + """ + if isinstance(attr, str): + attr = isodate.parse_datetime(attr) + try: + if not attr.tzinfo: + _LOGGER.warning("Datetime with no tzinfo will be considered UTC.") + utc = attr.utctimetuple() + if utc.tm_year > 9999 or utc.tm_year < 1: + raise OverflowError("Hit max or min date") + + microseconds = str(attr.microsecond).rjust(6, "0").rstrip("0").ljust(3, "0") + if microseconds: + microseconds = "." + microseconds + date = "{:04}-{:02}-{:02}T{:02}:{:02}:{:02}".format( + utc.tm_year, utc.tm_mon, utc.tm_mday, utc.tm_hour, utc.tm_min, utc.tm_sec + ) + return date + microseconds + "Z" + except (ValueError, OverflowError) as err: + msg = "Unable to serialize datetime object." + raise SerializationError(msg) from err + except AttributeError as err: + msg = "ISO-8601 object must be valid Datetime object." + raise TypeError(msg) from err + + @staticmethod + def serialize_unix(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Datetime object into IntTime format. + This is represented as seconds. + + :param Datetime attr: Object to be serialized. + :rtype: int + :raises SerializationError: if format invalid + :return: serialied unix + """ + if isinstance(attr, int): + return attr + try: + if not attr.tzinfo: + _LOGGER.warning("Datetime with no tzinfo will be considered UTC.") + return int(calendar.timegm(attr.utctimetuple())) + except AttributeError as exc: + raise TypeError("Unix time object must be valid Datetime object.") from exc + + +def rest_key_extractor(attr, attr_desc, data): # pylint: disable=unused-argument + key = attr_desc["key"] + working_data = data + + while "." in key: + # Need the cast, as for some reasons "split" is typed as list[str | Any] + dict_keys = cast(List[str], _FLATTEN.split(key)) + if len(dict_keys) == 1: + key = _decode_attribute_map_key(dict_keys[0]) + break + working_key = _decode_attribute_map_key(dict_keys[0]) + working_data = working_data.get(working_key, data) + if working_data is None: + # If at any point while following flatten JSON path see None, it means + # that all properties under are None as well + return None + key = ".".join(dict_keys[1:]) + + return working_data.get(key) + + +def rest_key_case_insensitive_extractor( # pylint: disable=unused-argument, inconsistent-return-statements + attr, attr_desc, data +): + key = attr_desc["key"] + working_data = data + + while "." in key: + dict_keys = _FLATTEN.split(key) + if len(dict_keys) == 1: + key = _decode_attribute_map_key(dict_keys[0]) + break + working_key = _decode_attribute_map_key(dict_keys[0]) + working_data = attribute_key_case_insensitive_extractor(working_key, None, working_data) + if working_data is None: + # If at any point while following flatten JSON path see None, it means + # that all properties under are None as well + return None + key = ".".join(dict_keys[1:]) + + if working_data: + return attribute_key_case_insensitive_extractor(key, None, working_data) + + +def last_rest_key_extractor(attr, attr_desc, data): # pylint: disable=unused-argument + """Extract the attribute in "data" based on the last part of the JSON path key. + + :param str attr: The attribute to extract + :param dict attr_desc: The attribute description + :param dict data: The data to extract from + :rtype: object + :returns: The extracted attribute + """ + key = attr_desc["key"] + dict_keys = _FLATTEN.split(key) + return attribute_key_extractor(dict_keys[-1], None, data) + + +def last_rest_key_case_insensitive_extractor(attr, attr_desc, data): # pylint: disable=unused-argument + """Extract the attribute in "data" based on the last part of the JSON path key. + + This is the case insensitive version of "last_rest_key_extractor" + :param str attr: The attribute to extract + :param dict attr_desc: The attribute description + :param dict data: The data to extract from + :rtype: object + :returns: The extracted attribute + """ + key = attr_desc["key"] + dict_keys = _FLATTEN.split(key) + return attribute_key_case_insensitive_extractor(dict_keys[-1], None, data) + + +def attribute_key_extractor(attr, _, data): + return data.get(attr) + + +def attribute_key_case_insensitive_extractor(attr, _, data): + found_key = None + lower_attr = attr.lower() + for key in data: + if lower_attr == key.lower(): + found_key = key + break + + return data.get(found_key) + + +def _extract_name_from_internal_type(internal_type): + """Given an internal type XML description, extract correct XML name with namespace. + + :param dict internal_type: An model type + :rtype: tuple + :returns: A tuple XML name + namespace dict + """ + internal_type_xml_map = getattr(internal_type, "_xml_map", {}) + xml_name = internal_type_xml_map.get("name", internal_type.__name__) + xml_ns = internal_type_xml_map.get("ns", None) + if xml_ns: + xml_name = "{{{}}}{}".format(xml_ns, xml_name) + return xml_name + + +def xml_key_extractor(attr, attr_desc, data): # pylint: disable=unused-argument,too-many-return-statements + if isinstance(data, dict): + return None + + # Test if this model is XML ready first + if not isinstance(data, ET.Element): + return None + + xml_desc = attr_desc.get("xml", {}) + xml_name = xml_desc.get("name", attr_desc["key"]) + + # Look for a children + is_iter_type = attr_desc["type"].startswith("[") + is_wrapped = xml_desc.get("wrapped", False) + internal_type = attr_desc.get("internalType", None) + internal_type_xml_map = getattr(internal_type, "_xml_map", {}) + + # Integrate namespace if necessary + xml_ns = xml_desc.get("ns", internal_type_xml_map.get("ns", None)) + if xml_ns: + xml_name = "{{{}}}{}".format(xml_ns, xml_name) + + # If it's an attribute, that's simple + if xml_desc.get("attr", False): + return data.get(xml_name) + + # If it's x-ms-text, that's simple too + if xml_desc.get("text", False): + return data.text + + # Scenario where I take the local name: + # - Wrapped node + # - Internal type is an enum (considered basic types) + # - Internal type has no XML/Name node + if is_wrapped or (internal_type and (issubclass(internal_type, Enum) or "name" not in internal_type_xml_map)): + children = data.findall(xml_name) + # If internal type has a local name and it's not a list, I use that name + elif not is_iter_type and internal_type and "name" in internal_type_xml_map: + xml_name = _extract_name_from_internal_type(internal_type) + children = data.findall(xml_name) + # That's an array + else: + if internal_type: # Complex type, ignore itemsName and use the complex type name + items_name = _extract_name_from_internal_type(internal_type) + else: + items_name = xml_desc.get("itemsName", xml_name) + children = data.findall(items_name) + + if len(children) == 0: + if is_iter_type: + if is_wrapped: + return None # is_wrapped no node, we want None + return [] # not wrapped, assume empty list + return None # Assume it's not there, maybe an optional node. + + # If is_iter_type and not wrapped, return all found children + if is_iter_type: + if not is_wrapped: + return children + # Iter and wrapped, should have found one node only (the wrap one) + if len(children) != 1: + raise DeserializationError( + "Tried to deserialize an array not wrapped, and found several nodes '{}'. Maybe you should declare this array as wrapped?".format( + xml_name + ) + ) + return list(children[0]) # Might be empty list and that's ok. + + # Here it's not a itertype, we should have found one element only or empty + if len(children) > 1: + raise DeserializationError("Find several XML '{}' where it was not expected".format(xml_name)) + return children[0] + + +class Deserializer: + """Response object model deserializer. + + :param dict classes: Class type dictionary for deserializing complex types. + :ivar list key_extractors: Ordered list of extractors to be used by this deserializer. + """ + + basic_types = {str: "str", int: "int", bool: "bool", float: "float"} + + valid_date = re.compile(r"\d{4}[-]\d{2}[-]\d{2}T\d{2}:\d{2}:\d{2}\.?\d*Z?[-+]?[\d{2}]?:?[\d{2}]?") + + def __init__(self, classes: Optional[Mapping[str, type]] = None) -> None: + self.deserialize_type = { + "iso-8601": Deserializer.deserialize_iso, + "rfc-1123": Deserializer.deserialize_rfc, + "unix-time": Deserializer.deserialize_unix, + "duration": Deserializer.deserialize_duration, + "date": Deserializer.deserialize_date, + "time": Deserializer.deserialize_time, + "decimal": Deserializer.deserialize_decimal, + "long": Deserializer.deserialize_long, + "bytearray": Deserializer.deserialize_bytearray, + "base64": Deserializer.deserialize_base64, + "object": self.deserialize_object, + "[]": self.deserialize_iter, + "{}": self.deserialize_dict, + } + self.deserialize_expected_types = { + "duration": (isodate.Duration, datetime.timedelta), + "iso-8601": (datetime.datetime), + } + self.dependencies: Dict[str, type] = dict(classes) if classes else {} + self.key_extractors = [rest_key_extractor, xml_key_extractor] + # Additional properties only works if the "rest_key_extractor" is used to + # extract the keys. Making it to work whatever the key extractor is too much + # complicated, with no real scenario for now. + # So adding a flag to disable additional properties detection. This flag should be + # used if your expect the deserialization to NOT come from a JSON REST syntax. + # Otherwise, result are unexpected + self.additional_properties_detection = True + + def __call__(self, target_obj, response_data, content_type=None): + """Call the deserializer to process a REST response. + + :param str target_obj: Target data type to deserialize to. + :param requests.Response response_data: REST response object. + :param str content_type: Swagger "produces" if available. + :raises DeserializationError: if deserialization fails. + :return: Deserialized object. + :rtype: object + """ + data = self._unpack_content(response_data, content_type) + return self._deserialize(target_obj, data) + + def _deserialize(self, target_obj, data): # pylint: disable=inconsistent-return-statements + """Call the deserializer on a model. + + Data needs to be already deserialized as JSON or XML ElementTree + + :param str target_obj: Target data type to deserialize to. + :param object data: Object to deserialize. + :raises DeserializationError: if deserialization fails. + :return: Deserialized object. + :rtype: object + """ + # This is already a model, go recursive just in case + if hasattr(data, "_attribute_map"): + constants = [name for name, config in getattr(data, "_validation", {}).items() if config.get("constant")] + try: + for attr, mapconfig in data._attribute_map.items(): # pylint: disable=protected-access + if attr in constants: + continue + value = getattr(data, attr) + if value is None: + continue + local_type = mapconfig["type"] + internal_data_type = local_type.strip("[]{}") + if internal_data_type not in self.dependencies or isinstance(internal_data_type, Enum): + continue + setattr(data, attr, self._deserialize(local_type, value)) + return data + except AttributeError: + return + + response, class_name = self._classify_target(target_obj, data) + + if isinstance(response, str): + return self.deserialize_data(data, response) + if isinstance(response, type) and issubclass(response, Enum): + return self.deserialize_enum(data, response) + + if data is None or data is CoreNull: + return data + try: + attributes = response._attribute_map # type: ignore # pylint: disable=protected-access + d_attrs = {} + for attr, attr_desc in attributes.items(): + # Check empty string. If it's not empty, someone has a real "additionalProperties"... + if attr == "additional_properties" and attr_desc["key"] == "": + continue + raw_value = None + # Enhance attr_desc with some dynamic data + attr_desc = attr_desc.copy() # Do a copy, do not change the real one + internal_data_type = attr_desc["type"].strip("[]{}") + if internal_data_type in self.dependencies: + attr_desc["internalType"] = self.dependencies[internal_data_type] + + for key_extractor in self.key_extractors: + found_value = key_extractor(attr, attr_desc, data) + if found_value is not None: + if raw_value is not None and raw_value != found_value: + msg = ( + "Ignoring extracted value '%s' from %s for key '%s'" + " (duplicate extraction, follow extractors order)" + ) + _LOGGER.warning(msg, found_value, key_extractor, attr) + continue + raw_value = found_value + + value = self.deserialize_data(raw_value, attr_desc["type"]) + d_attrs[attr] = value + except (AttributeError, TypeError, KeyError) as err: + msg = "Unable to deserialize to object: " + class_name # type: ignore + raise DeserializationError(msg) from err + additional_properties = self._build_additional_properties(attributes, data) + return self._instantiate_model(response, d_attrs, additional_properties) + + def _build_additional_properties(self, attribute_map, data): + if not self.additional_properties_detection: + return None + if "additional_properties" in attribute_map and attribute_map.get("additional_properties", {}).get("key") != "": + # Check empty string. If it's not empty, someone has a real "additionalProperties" + return None + if isinstance(data, ET.Element): + data = {el.tag: el.text for el in data} + + known_keys = { + _decode_attribute_map_key(_FLATTEN.split(desc["key"])[0]) + for desc in attribute_map.values() + if desc["key"] != "" + } + present_keys = set(data.keys()) + missing_keys = present_keys - known_keys + return {key: data[key] for key in missing_keys} + + def _classify_target(self, target, data): + """Check to see whether the deserialization target object can + be classified into a subclass. + Once classification has been determined, initialize object. + + :param str target: The target object type to deserialize to. + :param str/dict data: The response data to deserialize. + :return: The classified target object and its class name. + :rtype: tuple + """ + if target is None: + return None, None + + if isinstance(target, str): + try: + target = self.dependencies[target] + except KeyError: + return target, target + + try: + target = target._classify(data, self.dependencies) # type: ignore # pylint: disable=protected-access + except AttributeError: + pass # Target is not a Model, no classify + return target, target.__class__.__name__ # type: ignore + + def failsafe_deserialize(self, target_obj, data, content_type=None): + """Ignores any errors encountered in deserialization, + and falls back to not deserializing the object. Recommended + for use in error deserialization, as we want to return the + HttpResponseError to users, and not have them deal with + a deserialization error. + + :param str target_obj: The target object type to deserialize to. + :param str/dict data: The response data to deserialize. + :param str content_type: Swagger "produces" if available. + :return: Deserialized object. + :rtype: object + """ + try: + return self(target_obj, data, content_type=content_type) + except: # pylint: disable=bare-except + _LOGGER.debug( + "Ran into a deserialization error. Ignoring since this is failsafe deserialization", exc_info=True + ) + return None + + @staticmethod + def _unpack_content(raw_data, content_type=None): + """Extract the correct structure for deserialization. + + If raw_data is a PipelineResponse, try to extract the result of RawDeserializer. + if we can't, raise. Your Pipeline should have a RawDeserializer. + + If not a pipeline response and raw_data is bytes or string, use content-type + to decode it. If no content-type, try JSON. + + If raw_data is something else, bypass all logic and return it directly. + + :param obj raw_data: Data to be processed. + :param str content_type: How to parse if raw_data is a string/bytes. + :raises JSONDecodeError: If JSON is requested and parsing is impossible. + :raises UnicodeDecodeError: If bytes is not UTF8 + :rtype: object + :return: Unpacked content. + """ + # Assume this is enough to detect a Pipeline Response without importing it + context = getattr(raw_data, "context", {}) + if context: + if RawDeserializer.CONTEXT_NAME in context: + return context[RawDeserializer.CONTEXT_NAME] + raise ValueError("This pipeline didn't have the RawDeserializer policy; can't deserialize") + + # Assume this is enough to recognize universal_http.ClientResponse without importing it + if hasattr(raw_data, "body"): + return RawDeserializer.deserialize_from_http_generics(raw_data.text(), raw_data.headers) + + # Assume this enough to recognize requests.Response without importing it. + if hasattr(raw_data, "_content_consumed"): + return RawDeserializer.deserialize_from_http_generics(raw_data.text, raw_data.headers) + + if isinstance(raw_data, (str, bytes)) or hasattr(raw_data, "read"): + return RawDeserializer.deserialize_from_text(raw_data, content_type) # type: ignore + return raw_data + + def _instantiate_model(self, response, attrs, additional_properties=None): + """Instantiate a response model passing in deserialized args. + + :param Response response: The response model class. + :param dict attrs: The deserialized response attributes. + :param dict additional_properties: Additional properties to be set. + :rtype: Response + :return: The instantiated response model. + """ + if callable(response): + subtype = getattr(response, "_subtype_map", {}) + try: + readonly = [ + k + for k, v in response._validation.items() # pylint: disable=protected-access # type: ignore + if v.get("readonly") + ] + const = [ + k + for k, v in response._validation.items() # pylint: disable=protected-access # type: ignore + if v.get("constant") + ] + kwargs = {k: v for k, v in attrs.items() if k not in subtype and k not in readonly + const} + response_obj = response(**kwargs) + for attr in readonly: + setattr(response_obj, attr, attrs.get(attr)) + if additional_properties: + response_obj.additional_properties = additional_properties # type: ignore + return response_obj + except TypeError as err: + msg = "Unable to deserialize {} into model {}. ".format(kwargs, response) # type: ignore + raise DeserializationError(msg + str(err)) from err + else: + try: + for attr, value in attrs.items(): + setattr(response, attr, value) + return response + except Exception as exp: + msg = "Unable to populate response model. " + msg += "Type: {}, Error: {}".format(type(response), exp) + raise DeserializationError(msg) from exp + + def deserialize_data(self, data, data_type): # pylint: disable=too-many-return-statements + """Process data for deserialization according to data type. + + :param str data: The response string to be deserialized. + :param str data_type: The type to deserialize to. + :raises DeserializationError: if deserialization fails. + :return: Deserialized object. + :rtype: object + """ + if data is None: + return data + + try: + if not data_type: + return data + if data_type in self.basic_types.values(): + return self.deserialize_basic(data, data_type) + if data_type in self.deserialize_type: + if isinstance(data, self.deserialize_expected_types.get(data_type, tuple())): + return data + + is_a_text_parsing_type = lambda x: x not in [ # pylint: disable=unnecessary-lambda-assignment + "object", + "[]", + r"{}", + ] + if isinstance(data, ET.Element) and is_a_text_parsing_type(data_type) and not data.text: + return None + data_val = self.deserialize_type[data_type](data) + return data_val + + iter_type = data_type[0] + data_type[-1] + if iter_type in self.deserialize_type: + return self.deserialize_type[iter_type](data, data_type[1:-1]) + + obj_type = self.dependencies[data_type] + if issubclass(obj_type, Enum): + if isinstance(data, ET.Element): + data = data.text + return self.deserialize_enum(data, obj_type) + + except (ValueError, TypeError, AttributeError) as err: + msg = "Unable to deserialize response data." + msg += " Data: {}, {}".format(data, data_type) + raise DeserializationError(msg) from err + return self._deserialize(obj_type, data) + + def deserialize_iter(self, attr, iter_type): + """Deserialize an iterable. + + :param list attr: Iterable to be deserialized. + :param str iter_type: The type of object in the iterable. + :return: Deserialized iterable. + :rtype: list + """ + if attr is None: + return None + if isinstance(attr, ET.Element): # If I receive an element here, get the children + attr = list(attr) + if not isinstance(attr, (list, set)): + raise DeserializationError("Cannot deserialize as [{}] an object of type {}".format(iter_type, type(attr))) + return [self.deserialize_data(a, iter_type) for a in attr] + + def deserialize_dict(self, attr, dict_type): + """Deserialize a dictionary. + + :param dict/list attr: Dictionary to be deserialized. Also accepts + a list of key, value pairs. + :param str dict_type: The object type of the items in the dictionary. + :return: Deserialized dictionary. + :rtype: dict + """ + if isinstance(attr, list): + return {x["key"]: self.deserialize_data(x["value"], dict_type) for x in attr} + + if isinstance(attr, ET.Element): + # Transform value into {"Key": "value"} + attr = {el.tag: el.text for el in attr} + return {k: self.deserialize_data(v, dict_type) for k, v in attr.items()} + + def deserialize_object(self, attr, **kwargs): # pylint: disable=too-many-return-statements + """Deserialize a generic object. + This will be handled as a dictionary. + + :param dict attr: Dictionary to be deserialized. + :return: Deserialized object. + :rtype: dict + :raises TypeError: if non-builtin datatype encountered. + """ + if attr is None: + return None + if isinstance(attr, ET.Element): + # Do no recurse on XML, just return the tree as-is + return attr + if isinstance(attr, str): + return self.deserialize_basic(attr, "str") + obj_type = type(attr) + if obj_type in self.basic_types: + return self.deserialize_basic(attr, self.basic_types[obj_type]) + if obj_type is _long_type: + return self.deserialize_long(attr) + + if obj_type == dict: + deserialized = {} + for key, value in attr.items(): + try: + deserialized[key] = self.deserialize_object(value, **kwargs) + except ValueError: + deserialized[key] = None + return deserialized + + if obj_type == list: + deserialized = [] + for obj in attr: + try: + deserialized.append(self.deserialize_object(obj, **kwargs)) + except ValueError: + pass + return deserialized + + error = "Cannot deserialize generic object with type: " + raise TypeError(error + str(obj_type)) + + def deserialize_basic(self, attr, data_type): # pylint: disable=too-many-return-statements + """Deserialize basic builtin data type from string. + Will attempt to convert to str, int, float and bool. + This function will also accept '1', '0', 'true' and 'false' as + valid bool values. + + :param str attr: response string to be deserialized. + :param str data_type: deserialization data type. + :return: Deserialized basic type. + :rtype: str, int, float or bool + :raises TypeError: if string format is not valid. + """ + # If we're here, data is supposed to be a basic type. + # If it's still an XML node, take the text + if isinstance(attr, ET.Element): + attr = attr.text + if not attr: + if data_type == "str": + # None or '', node is empty string. + return "" + # None or '', node with a strong type is None. + # Don't try to model "empty bool" or "empty int" + return None + + if data_type == "bool": + if attr in [True, False, 1, 0]: + return bool(attr) + if isinstance(attr, str): + if attr.lower() in ["true", "1"]: + return True + if attr.lower() in ["false", "0"]: + return False + raise TypeError("Invalid boolean value: {}".format(attr)) + + if data_type == "str": + return self.deserialize_unicode(attr) + return eval(data_type)(attr) # nosec # pylint: disable=eval-used + + @staticmethod + def deserialize_unicode(data): + """Preserve unicode objects in Python 2, otherwise return data + as a string. + + :param str data: response string to be deserialized. + :return: Deserialized string. + :rtype: str or unicode + """ + # We might be here because we have an enum modeled as string, + # and we try to deserialize a partial dict with enum inside + if isinstance(data, Enum): + return data + + # Consider this is real string + try: + if isinstance(data, unicode): # type: ignore + return data + except NameError: + return str(data) + return str(data) + + @staticmethod + def deserialize_enum(data, enum_obj): + """Deserialize string into enum object. + + If the string is not a valid enum value it will be returned as-is + and a warning will be logged. + + :param str data: Response string to be deserialized. If this value is + None or invalid it will be returned as-is. + :param Enum enum_obj: Enum object to deserialize to. + :return: Deserialized enum object. + :rtype: Enum + """ + if isinstance(data, enum_obj) or data is None: + return data + if isinstance(data, Enum): + data = data.value + if isinstance(data, int): + # Workaround. We might consider remove it in the future. + try: + return list(enum_obj.__members__.values())[data] + except IndexError as exc: + error = "{!r} is not a valid index for enum {!r}" + raise DeserializationError(error.format(data, enum_obj)) from exc + try: + return enum_obj(str(data)) + except ValueError: + for enum_value in enum_obj: + if enum_value.value.lower() == str(data).lower(): + return enum_value + # We don't fail anymore for unknown value, we deserialize as a string + _LOGGER.warning("Deserializer is not able to find %s as valid enum in %s", data, enum_obj) + return Deserializer.deserialize_unicode(data) + + @staticmethod + def deserialize_bytearray(attr): + """Deserialize string into bytearray. + + :param str attr: response string to be deserialized. + :return: Deserialized bytearray + :rtype: bytearray + :raises TypeError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + return bytearray(b64decode(attr)) # type: ignore + + @staticmethod + def deserialize_base64(attr): + """Deserialize base64 encoded string into string. + + :param str attr: response string to be deserialized. + :return: Deserialized base64 string + :rtype: bytearray + :raises TypeError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + padding = "=" * (3 - (len(attr) + 3) % 4) # type: ignore + attr = attr + padding # type: ignore + encoded = attr.replace("-", "+").replace("_", "/") + return b64decode(encoded) + + @staticmethod + def deserialize_decimal(attr): + """Deserialize string into Decimal object. + + :param str attr: response string to be deserialized. + :return: Deserialized decimal + :raises DeserializationError: if string format invalid. + :rtype: decimal + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + return decimal.Decimal(str(attr)) # type: ignore + except decimal.DecimalException as err: + msg = "Invalid decimal {}".format(attr) + raise DeserializationError(msg) from err + + @staticmethod + def deserialize_long(attr): + """Deserialize string into long (Py2) or int (Py3). + + :param str attr: response string to be deserialized. + :return: Deserialized int + :rtype: long or int + :raises ValueError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + return _long_type(attr) # type: ignore + + @staticmethod + def deserialize_duration(attr): + """Deserialize ISO-8601 formatted string into TimeDelta object. + + :param str attr: response string to be deserialized. + :return: Deserialized duration + :rtype: TimeDelta + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + duration = isodate.parse_duration(attr) + except (ValueError, OverflowError, AttributeError) as err: + msg = "Cannot deserialize duration object." + raise DeserializationError(msg) from err + return duration + + @staticmethod + def deserialize_date(attr): + """Deserialize ISO-8601 formatted string into Date object. + + :param str attr: response string to be deserialized. + :return: Deserialized date + :rtype: Date + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + if re.search(r"[^\W\d_]", attr, re.I + re.U): # type: ignore + raise DeserializationError("Date must have only digits and -. Received: %s" % attr) + # This must NOT use defaultmonth/defaultday. Using None ensure this raises an exception. + return isodate.parse_date(attr, defaultmonth=0, defaultday=0) + + @staticmethod + def deserialize_time(attr): + """Deserialize ISO-8601 formatted string into time object. + + :param str attr: response string to be deserialized. + :return: Deserialized time + :rtype: datetime.time + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + if re.search(r"[^\W\d_]", attr, re.I + re.U): # type: ignore + raise DeserializationError("Date must have only digits and -. Received: %s" % attr) + return isodate.parse_time(attr) + + @staticmethod + def deserialize_rfc(attr): + """Deserialize RFC-1123 formatted string into Datetime object. + + :param str attr: response string to be deserialized. + :return: Deserialized RFC datetime + :rtype: Datetime + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + parsed_date = email.utils.parsedate_tz(attr) # type: ignore + date_obj = datetime.datetime( + *parsed_date[:6], tzinfo=datetime.timezone(datetime.timedelta(minutes=(parsed_date[9] or 0) / 60)) + ) + if not date_obj.tzinfo: + date_obj = date_obj.astimezone(tz=TZ_UTC) + except ValueError as err: + msg = "Cannot deserialize to rfc datetime object." + raise DeserializationError(msg) from err + return date_obj + + @staticmethod + def deserialize_iso(attr): + """Deserialize ISO-8601 formatted string into Datetime object. + + :param str attr: response string to be deserialized. + :return: Deserialized ISO datetime + :rtype: Datetime + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + attr = attr.upper() # type: ignore + match = Deserializer.valid_date.match(attr) + if not match: + raise ValueError("Invalid datetime string: " + attr) + + check_decimal = attr.split(".") + if len(check_decimal) > 1: + decimal_str = "" + for digit in check_decimal[1]: + if digit.isdigit(): + decimal_str += digit + else: + break + if len(decimal_str) > 6: + attr = attr.replace(decimal_str, decimal_str[0:6]) + + date_obj = isodate.parse_datetime(attr) + test_utc = date_obj.utctimetuple() + if test_utc.tm_year > 9999 or test_utc.tm_year < 1: + raise OverflowError("Hit max or min date") + except (ValueError, OverflowError, AttributeError) as err: + msg = "Cannot deserialize datetime object." + raise DeserializationError(msg) from err + return date_obj + + @staticmethod + def deserialize_unix(attr): + """Serialize Datetime object into IntTime format. + This is represented as seconds. + + :param int attr: Object to be serialized. + :return: Deserialized datetime + :rtype: Datetime + :raises DeserializationError: if format invalid + """ + if isinstance(attr, ET.Element): + attr = int(attr.text) # type: ignore + try: + attr = int(attr) + date_obj = datetime.datetime.fromtimestamp(attr, TZ_UTC) + except ValueError as err: + msg = "Cannot deserialize to unix datetime object." + raise DeserializationError(msg) from err + return date_obj diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/UrlMultiCollectionFormatVersionTolerant/urlmulticollectionformatversiontolerant/aio/_client.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/UrlMultiCollectionFormatVersionTolerant/urlmulticollectionformatversiontolerant/aio/_client.py index d6adf616313..6ace52b7bc2 100644 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/UrlMultiCollectionFormatVersionTolerant/urlmulticollectionformatversiontolerant/aio/_client.py +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/UrlMultiCollectionFormatVersionTolerant/urlmulticollectionformatversiontolerant/aio/_client.py @@ -14,7 +14,7 @@ from azure.core.pipeline import policies from azure.core.rest import AsyncHttpResponse, HttpRequest -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import AutoRestUrlMutliCollectionFormatTestServiceConfiguration from .operations import QueriesOperations diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/UrlMultiCollectionFormatVersionTolerant/urlmulticollectionformatversiontolerant/aio/operations/_operations.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/UrlMultiCollectionFormatVersionTolerant/urlmulticollectionformatversiontolerant/aio/operations/_operations.py index fa64c80936a..bf0c8f0e541 100644 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/UrlMultiCollectionFormatVersionTolerant/urlmulticollectionformatversiontolerant/aio/operations/_operations.py +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/UrlMultiCollectionFormatVersionTolerant/urlmulticollectionformatversiontolerant/aio/operations/_operations.py @@ -21,7 +21,7 @@ from azure.core.rest import AsyncHttpResponse, HttpRequest from azure.core.tracing.decorator_async import distributed_trace_async -from ..._serialization import Deserializer, Serializer +from ..._utils.serialization import Deserializer, Serializer from ...operations._operations import ( build_queries_array_string_multi_empty_request, build_queries_array_string_multi_null_request, diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/UrlMultiCollectionFormatVersionTolerant/urlmulticollectionformatversiontolerant/operations/_operations.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/UrlMultiCollectionFormatVersionTolerant/urlmulticollectionformatversiontolerant/operations/_operations.py index 8f62d863036..eae5c6a9ff4 100644 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/UrlMultiCollectionFormatVersionTolerant/urlmulticollectionformatversiontolerant/operations/_operations.py +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/UrlMultiCollectionFormatVersionTolerant/urlmulticollectionformatversiontolerant/operations/_operations.py @@ -23,7 +23,7 @@ from azure.core.utils import case_insensitive_dict from .._configuration import AutoRestUrlMutliCollectionFormatTestServiceConfiguration -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/UrlVersionTolerant/urlversiontolerant/_client.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/UrlVersionTolerant/urlversiontolerant/_client.py index dd0b9152c5d..7e7e62277fd 100644 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/UrlVersionTolerant/urlversiontolerant/_client.py +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/UrlVersionTolerant/urlversiontolerant/_client.py @@ -15,7 +15,7 @@ from azure.core.rest import HttpRequest, HttpResponse from ._configuration import AutoRestUrlTestServiceConfiguration -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer from .operations import PathItemsOperations, PathsOperations, QueriesOperations diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/UrlVersionTolerant/urlversiontolerant/_utils/__init__.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/UrlVersionTolerant/urlversiontolerant/_utils/__init__.py new file mode 100644 index 00000000000..0af9b28f660 --- /dev/null +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/UrlVersionTolerant/urlversiontolerant/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/UrlVersionTolerant/urlversiontolerant/_utils/serialization.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/UrlVersionTolerant/urlversiontolerant/_utils/serialization.py new file mode 100644 index 00000000000..f5187701d7b --- /dev/null +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/UrlVersionTolerant/urlversiontolerant/_utils/serialization.py @@ -0,0 +1,2032 @@ +# pylint: disable=line-too-long,useless-suppression,too-many-lines +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +# pyright: reportUnnecessaryTypeIgnoreComment=false + +from base64 import b64decode, b64encode +import calendar +import datetime +import decimal +import email +from enum import Enum +import json +import logging +import re +import sys +import codecs +from typing import ( + Dict, + Any, + cast, + Optional, + Union, + AnyStr, + IO, + Mapping, + Callable, + MutableMapping, + List, +) + +try: + from urllib import quote # type: ignore +except ImportError: + from urllib.parse import quote +import xml.etree.ElementTree as ET + +import isodate # type: ignore +from typing_extensions import Self + +from azure.core.exceptions import DeserializationError, SerializationError +from azure.core.serialization import NULL as CoreNull + +_BOM = codecs.BOM_UTF8.decode(encoding="utf-8") + +JSON = MutableMapping[str, Any] + + +class RawDeserializer: + + # Accept "text" because we're open minded people... + JSON_REGEXP = re.compile(r"^(application|text)/([a-z+.]+\+)?json$") + + # Name used in context + CONTEXT_NAME = "deserialized_data" + + @classmethod + def deserialize_from_text(cls, data: Optional[Union[AnyStr, IO]], content_type: Optional[str] = None) -> Any: + """Decode data according to content-type. + + Accept a stream of data as well, but will be load at once in memory for now. + + If no content-type, will return the string version (not bytes, not stream) + + :param data: Input, could be bytes or stream (will be decoded with UTF8) or text + :type data: str or bytes or IO + :param str content_type: The content type. + :return: The deserialized data. + :rtype: object + """ + if hasattr(data, "read"): + # Assume a stream + data = cast(IO, data).read() + + if isinstance(data, bytes): + data_as_str = data.decode(encoding="utf-8-sig") + else: + # Explain to mypy the correct type. + data_as_str = cast(str, data) + + # Remove Byte Order Mark if present in string + data_as_str = data_as_str.lstrip(_BOM) + + if content_type is None: + return data + + if cls.JSON_REGEXP.match(content_type): + try: + return json.loads(data_as_str) + except ValueError as err: + raise DeserializationError("JSON is invalid: {}".format(err), err) from err + elif "xml" in (content_type or []): + try: + + try: + if isinstance(data, unicode): # type: ignore + # If I'm Python 2.7 and unicode XML will scream if I try a "fromstring" on unicode string + data_as_str = data_as_str.encode(encoding="utf-8") # type: ignore + except NameError: + pass + + return ET.fromstring(data_as_str) # nosec + except ET.ParseError as err: + # It might be because the server has an issue, and returned JSON with + # content-type XML.... + # So let's try a JSON load, and if it's still broken + # let's flow the initial exception + def _json_attemp(data): + try: + return True, json.loads(data) + except ValueError: + return False, None # Don't care about this one + + success, json_result = _json_attemp(data) + if success: + return json_result + # If i'm here, it's not JSON, it's not XML, let's scream + # and raise the last context in this block (the XML exception) + # The function hack is because Py2.7 messes up with exception + # context otherwise. + _LOGGER.critical("Wasn't XML not JSON, failing") + raise DeserializationError("XML is invalid") from err + elif content_type.startswith("text/"): + return data_as_str + raise DeserializationError("Cannot deserialize content-type: {}".format(content_type)) + + @classmethod + def deserialize_from_http_generics(cls, body_bytes: Optional[Union[AnyStr, IO]], headers: Mapping) -> Any: + """Deserialize from HTTP response. + + Use bytes and headers to NOT use any requests/aiohttp or whatever + specific implementation. + Headers will tested for "content-type" + + :param bytes body_bytes: The body of the response. + :param dict headers: The headers of the response. + :returns: The deserialized data. + :rtype: object + """ + # Try to use content-type from headers if available + content_type = None + if "content-type" in headers: + content_type = headers["content-type"].split(";")[0].strip().lower() + # Ouch, this server did not declare what it sent... + # Let's guess it's JSON... + # Also, since Autorest was considering that an empty body was a valid JSON, + # need that test as well.... + else: + content_type = "application/json" + + if body_bytes: + return cls.deserialize_from_text(body_bytes, content_type) + return None + + +_LOGGER = logging.getLogger(__name__) + +try: + _long_type = long # type: ignore +except NameError: + _long_type = int + +TZ_UTC = datetime.timezone.utc + +_FLATTEN = re.compile(r"(? None: + self.additional_properties: Optional[Dict[str, Any]] = {} + for k in kwargs: # pylint: disable=consider-using-dict-items + if k not in self._attribute_map: + _LOGGER.warning("%s is not a known attribute of class %s and will be ignored", k, self.__class__) + elif k in self._validation and self._validation[k].get("readonly", False): + _LOGGER.warning("Readonly attribute %s will be ignored in class %s", k, self.__class__) + else: + setattr(self, k, kwargs[k]) + + def __eq__(self, other: Any) -> bool: + """Compare objects by comparing all attributes. + + :param object other: The object to compare + :returns: True if objects are equal + :rtype: bool + """ + if isinstance(other, self.__class__): + return self.__dict__ == other.__dict__ + return False + + def __ne__(self, other: Any) -> bool: + """Compare objects by comparing all attributes. + + :param object other: The object to compare + :returns: True if objects are not equal + :rtype: bool + """ + return not self.__eq__(other) + + def __str__(self) -> str: + return str(self.__dict__) + + @classmethod + def enable_additional_properties_sending(cls) -> None: + cls._attribute_map["additional_properties"] = {"key": "", "type": "{object}"} + + @classmethod + def is_xml_model(cls) -> bool: + try: + cls._xml_map # type: ignore + except AttributeError: + return False + return True + + @classmethod + def _create_xml_node(cls): + """Create XML node. + + :returns: The XML node + :rtype: xml.etree.ElementTree.Element + """ + try: + xml_map = cls._xml_map # type: ignore + except AttributeError: + xml_map = {} + + return _create_xml_node(xml_map.get("name", cls.__name__), xml_map.get("prefix", None), xml_map.get("ns", None)) + + def serialize(self, keep_readonly: bool = False, **kwargs: Any) -> JSON: + """Return the JSON that would be sent to server from this model. + + This is an alias to `as_dict(full_restapi_key_transformer, keep_readonly=False)`. + + If you want XML serialization, you can pass the kwargs is_xml=True. + + :param bool keep_readonly: If you want to serialize the readonly attributes + :returns: A dict JSON compatible object + :rtype: dict + """ + serializer = Serializer(self._infer_class_models()) + return serializer._serialize( # type: ignore # pylint: disable=protected-access + self, keep_readonly=keep_readonly, **kwargs + ) + + def as_dict( + self, + keep_readonly: bool = True, + key_transformer: Callable[[str, Dict[str, Any], Any], Any] = attribute_transformer, + **kwargs: Any + ) -> JSON: + """Return a dict that can be serialized using json.dump. + + Advanced usage might optionally use a callback as parameter: + + .. code::python + + def my_key_transformer(key, attr_desc, value): + return key + + Key is the attribute name used in Python. Attr_desc + is a dict of metadata. Currently contains 'type' with the + msrest type and 'key' with the RestAPI encoded key. + Value is the current value in this object. + + The string returned will be used to serialize the key. + If the return type is a list, this is considered hierarchical + result dict. + + See the three examples in this file: + + - attribute_transformer + - full_restapi_key_transformer + - last_restapi_key_transformer + + If you want XML serialization, you can pass the kwargs is_xml=True. + + :param bool keep_readonly: If you want to serialize the readonly attributes + :param function key_transformer: A key transformer function. + :returns: A dict JSON compatible object + :rtype: dict + """ + serializer = Serializer(self._infer_class_models()) + return serializer._serialize( # type: ignore # pylint: disable=protected-access + self, key_transformer=key_transformer, keep_readonly=keep_readonly, **kwargs + ) + + @classmethod + def _infer_class_models(cls): + try: + str_models = cls.__module__.rsplit(".", 1)[0] + models = sys.modules[str_models] + client_models = {k: v for k, v in models.__dict__.items() if isinstance(v, type)} + if cls.__name__ not in client_models: + raise ValueError("Not Autorest generated code") + except Exception: # pylint: disable=broad-exception-caught + # Assume it's not Autorest generated (tests?). Add ourselves as dependencies. + client_models = {cls.__name__: cls} + return client_models + + @classmethod + def deserialize(cls, data: Any, content_type: Optional[str] = None) -> Self: + """Parse a str using the RestAPI syntax and return a model. + + :param str data: A str using RestAPI structure. JSON by default. + :param str content_type: JSON by default, set application/xml if XML. + :returns: An instance of this model + :raises DeserializationError: if something went wrong + :rtype: Self + """ + deserializer = Deserializer(cls._infer_class_models()) + return deserializer(cls.__name__, data, content_type=content_type) # type: ignore + + @classmethod + def from_dict( + cls, + data: Any, + key_extractors: Optional[Callable[[str, Dict[str, Any], Any], Any]] = None, + content_type: Optional[str] = None, + ) -> Self: + """Parse a dict using given key extractor return a model. + + By default consider key + extractors (rest_key_case_insensitive_extractor, attribute_key_case_insensitive_extractor + and last_rest_key_case_insensitive_extractor) + + :param dict data: A dict using RestAPI structure + :param function key_extractors: A key extractor function. + :param str content_type: JSON by default, set application/xml if XML. + :returns: An instance of this model + :raises DeserializationError: if something went wrong + :rtype: Self + """ + deserializer = Deserializer(cls._infer_class_models()) + deserializer.key_extractors = ( # type: ignore + [ # type: ignore + attribute_key_case_insensitive_extractor, + rest_key_case_insensitive_extractor, + last_rest_key_case_insensitive_extractor, + ] + if key_extractors is None + else key_extractors + ) + return deserializer(cls.__name__, data, content_type=content_type) # type: ignore + + @classmethod + def _flatten_subtype(cls, key, objects): + if "_subtype_map" not in cls.__dict__: + return {} + result = dict(cls._subtype_map[key]) + for valuetype in cls._subtype_map[key].values(): + result.update(objects[valuetype]._flatten_subtype(key, objects)) # pylint: disable=protected-access + return result + + @classmethod + def _classify(cls, response, objects): + """Check the class _subtype_map for any child classes. + We want to ignore any inherited _subtype_maps. + + :param dict response: The initial data + :param dict objects: The class objects + :returns: The class to be used + :rtype: class + """ + for subtype_key in cls.__dict__.get("_subtype_map", {}).keys(): + subtype_value = None + + if not isinstance(response, ET.Element): + rest_api_response_key = cls._get_rest_key_parts(subtype_key)[-1] + subtype_value = response.get(rest_api_response_key, None) or response.get(subtype_key, None) + else: + subtype_value = xml_key_extractor(subtype_key, cls._attribute_map[subtype_key], response) + if subtype_value: + # Try to match base class. Can be class name only + # (bug to fix in Autorest to support x-ms-discriminator-name) + if cls.__name__ == subtype_value: + return cls + flatten_mapping_type = cls._flatten_subtype(subtype_key, objects) + try: + return objects[flatten_mapping_type[subtype_value]] # type: ignore + except KeyError: + _LOGGER.warning( + "Subtype value %s has no mapping, use base class %s.", + subtype_value, + cls.__name__, + ) + break + else: + _LOGGER.warning("Discriminator %s is absent or null, use base class %s.", subtype_key, cls.__name__) + break + return cls + + @classmethod + def _get_rest_key_parts(cls, attr_key): + """Get the RestAPI key of this attr, split it and decode part + :param str attr_key: Attribute key must be in attribute_map. + :returns: A list of RestAPI part + :rtype: list + """ + rest_split_key = _FLATTEN.split(cls._attribute_map[attr_key]["key"]) + return [_decode_attribute_map_key(key_part) for key_part in rest_split_key] + + +def _decode_attribute_map_key(key): + """This decode a key in an _attribute_map to the actual key we want to look at + inside the received data. + + :param str key: A key string from the generated code + :returns: The decoded key + :rtype: str + """ + return key.replace("\\.", ".") + + +class Serializer: # pylint: disable=too-many-public-methods + """Request object model serializer.""" + + basic_types = {str: "str", int: "int", bool: "bool", float: "float"} + + _xml_basic_types_serializers = {"bool": lambda x: str(x).lower()} + days = {0: "Mon", 1: "Tue", 2: "Wed", 3: "Thu", 4: "Fri", 5: "Sat", 6: "Sun"} + months = { + 1: "Jan", + 2: "Feb", + 3: "Mar", + 4: "Apr", + 5: "May", + 6: "Jun", + 7: "Jul", + 8: "Aug", + 9: "Sep", + 10: "Oct", + 11: "Nov", + 12: "Dec", + } + validation = { + "min_length": lambda x, y: len(x) < y, + "max_length": lambda x, y: len(x) > y, + "minimum": lambda x, y: x < y, + "maximum": lambda x, y: x > y, + "minimum_ex": lambda x, y: x <= y, + "maximum_ex": lambda x, y: x >= y, + "min_items": lambda x, y: len(x) < y, + "max_items": lambda x, y: len(x) > y, + "pattern": lambda x, y: not re.match(y, x, re.UNICODE), + "unique": lambda x, y: len(x) != len(set(x)), + "multiple": lambda x, y: x % y != 0, + } + + def __init__(self, classes: Optional[Mapping[str, type]] = None) -> None: + self.serialize_type = { + "iso-8601": Serializer.serialize_iso, + "rfc-1123": Serializer.serialize_rfc, + "unix-time": Serializer.serialize_unix, + "duration": Serializer.serialize_duration, + "date": Serializer.serialize_date, + "time": Serializer.serialize_time, + "decimal": Serializer.serialize_decimal, + "long": Serializer.serialize_long, + "bytearray": Serializer.serialize_bytearray, + "base64": Serializer.serialize_base64, + "object": self.serialize_object, + "[]": self.serialize_iter, + "{}": self.serialize_dict, + } + self.dependencies: Dict[str, type] = dict(classes) if classes else {} + self.key_transformer = full_restapi_key_transformer + self.client_side_validation = True + + def _serialize( # pylint: disable=too-many-nested-blocks, too-many-branches, too-many-statements, too-many-locals + self, target_obj, data_type=None, **kwargs + ): + """Serialize data into a string according to type. + + :param object target_obj: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str, dict + :raises SerializationError: if serialization fails. + :returns: The serialized data. + """ + key_transformer = kwargs.get("key_transformer", self.key_transformer) + keep_readonly = kwargs.get("keep_readonly", False) + if target_obj is None: + return None + + attr_name = None + class_name = target_obj.__class__.__name__ + + if data_type: + return self.serialize_data(target_obj, data_type, **kwargs) + + if not hasattr(target_obj, "_attribute_map"): + data_type = type(target_obj).__name__ + if data_type in self.basic_types.values(): + return self.serialize_data(target_obj, data_type, **kwargs) + + # Force "is_xml" kwargs if we detect a XML model + try: + is_xml_model_serialization = kwargs["is_xml"] + except KeyError: + is_xml_model_serialization = kwargs.setdefault("is_xml", target_obj.is_xml_model()) + + serialized = {} + if is_xml_model_serialization: + serialized = target_obj._create_xml_node() # pylint: disable=protected-access + try: + attributes = target_obj._attribute_map # pylint: disable=protected-access + for attr, attr_desc in attributes.items(): + attr_name = attr + if not keep_readonly and target_obj._validation.get( # pylint: disable=protected-access + attr_name, {} + ).get("readonly", False): + continue + + if attr_name == "additional_properties" and attr_desc["key"] == "": + if target_obj.additional_properties is not None: + serialized.update(target_obj.additional_properties) + continue + try: + + orig_attr = getattr(target_obj, attr) + if is_xml_model_serialization: + pass # Don't provide "transformer" for XML for now. Keep "orig_attr" + else: # JSON + keys, orig_attr = key_transformer(attr, attr_desc.copy(), orig_attr) + keys = keys if isinstance(keys, list) else [keys] + + kwargs["serialization_ctxt"] = attr_desc + new_attr = self.serialize_data(orig_attr, attr_desc["type"], **kwargs) + + if is_xml_model_serialization: + xml_desc = attr_desc.get("xml", {}) + xml_name = xml_desc.get("name", attr_desc["key"]) + xml_prefix = xml_desc.get("prefix", None) + xml_ns = xml_desc.get("ns", None) + if xml_desc.get("attr", False): + if xml_ns: + ET.register_namespace(xml_prefix, xml_ns) + xml_name = "{{{}}}{}".format(xml_ns, xml_name) + serialized.set(xml_name, new_attr) # type: ignore + continue + if xml_desc.get("text", False): + serialized.text = new_attr # type: ignore + continue + if isinstance(new_attr, list): + serialized.extend(new_attr) # type: ignore + elif isinstance(new_attr, ET.Element): + # If the down XML has no XML/Name, + # we MUST replace the tag with the local tag. But keeping the namespaces. + if "name" not in getattr(orig_attr, "_xml_map", {}): + splitted_tag = new_attr.tag.split("}") + if len(splitted_tag) == 2: # Namespace + new_attr.tag = "}".join([splitted_tag[0], xml_name]) + else: + new_attr.tag = xml_name + serialized.append(new_attr) # type: ignore + else: # That's a basic type + # Integrate namespace if necessary + local_node = _create_xml_node(xml_name, xml_prefix, xml_ns) + local_node.text = str(new_attr) + serialized.append(local_node) # type: ignore + else: # JSON + for k in reversed(keys): # type: ignore + new_attr = {k: new_attr} + + _new_attr = new_attr + _serialized = serialized + for k in keys: # type: ignore + if k not in _serialized: + _serialized.update(_new_attr) # type: ignore + _new_attr = _new_attr[k] # type: ignore + _serialized = _serialized[k] + except ValueError as err: + if isinstance(err, SerializationError): + raise + + except (AttributeError, KeyError, TypeError) as err: + msg = "Attribute {} in object {} cannot be serialized.\n{}".format(attr_name, class_name, str(target_obj)) + raise SerializationError(msg) from err + return serialized + + def body(self, data, data_type, **kwargs): + """Serialize data intended for a request body. + + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: dict + :raises SerializationError: if serialization fails. + :raises ValueError: if data is None + :returns: The serialized request body + """ + + # Just in case this is a dict + internal_data_type_str = data_type.strip("[]{}") + internal_data_type = self.dependencies.get(internal_data_type_str, None) + try: + is_xml_model_serialization = kwargs["is_xml"] + except KeyError: + if internal_data_type and issubclass(internal_data_type, Model): + is_xml_model_serialization = kwargs.setdefault("is_xml", internal_data_type.is_xml_model()) + else: + is_xml_model_serialization = False + if internal_data_type and not isinstance(internal_data_type, Enum): + try: + deserializer = Deserializer(self.dependencies) + # Since it's on serialization, it's almost sure that format is not JSON REST + # We're not able to deal with additional properties for now. + deserializer.additional_properties_detection = False + if is_xml_model_serialization: + deserializer.key_extractors = [ # type: ignore + attribute_key_case_insensitive_extractor, + ] + else: + deserializer.key_extractors = [ + rest_key_case_insensitive_extractor, + attribute_key_case_insensitive_extractor, + last_rest_key_case_insensitive_extractor, + ] + data = deserializer._deserialize(data_type, data) # pylint: disable=protected-access + except DeserializationError as err: + raise SerializationError("Unable to build a model: " + str(err)) from err + + return self._serialize(data, data_type, **kwargs) + + def url(self, name, data, data_type, **kwargs): + """Serialize data intended for a URL path. + + :param str name: The name of the URL path parameter. + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str + :returns: The serialized URL path + :raises TypeError: if serialization fails. + :raises ValueError: if data is None + """ + try: + output = self.serialize_data(data, data_type, **kwargs) + if data_type == "bool": + output = json.dumps(output) + + if kwargs.get("skip_quote") is True: + output = str(output) + output = output.replace("{", quote("{")).replace("}", quote("}")) + else: + output = quote(str(output), safe="") + except SerializationError as exc: + raise TypeError("{} must be type {}.".format(name, data_type)) from exc + return output + + def query(self, name, data, data_type, **kwargs): + """Serialize data intended for a URL query. + + :param str name: The name of the query parameter. + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str, list + :raises TypeError: if serialization fails. + :raises ValueError: if data is None + :returns: The serialized query parameter + """ + try: + # Treat the list aside, since we don't want to encode the div separator + if data_type.startswith("["): + internal_data_type = data_type[1:-1] + do_quote = not kwargs.get("skip_quote", False) + return self.serialize_iter(data, internal_data_type, do_quote=do_quote, **kwargs) + + # Not a list, regular serialization + output = self.serialize_data(data, data_type, **kwargs) + if data_type == "bool": + output = json.dumps(output) + if kwargs.get("skip_quote") is True: + output = str(output) + else: + output = quote(str(output), safe="") + except SerializationError as exc: + raise TypeError("{} must be type {}.".format(name, data_type)) from exc + return str(output) + + def header(self, name, data, data_type, **kwargs): + """Serialize data intended for a request header. + + :param str name: The name of the header. + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str + :raises TypeError: if serialization fails. + :raises ValueError: if data is None + :returns: The serialized header + """ + try: + if data_type in ["[str]"]: + data = ["" if d is None else d for d in data] + + output = self.serialize_data(data, data_type, **kwargs) + if data_type == "bool": + output = json.dumps(output) + except SerializationError as exc: + raise TypeError("{} must be type {}.".format(name, data_type)) from exc + return str(output) + + def serialize_data(self, data, data_type, **kwargs): + """Serialize generic data according to supplied data type. + + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :raises AttributeError: if required data is None. + :raises ValueError: if data is None + :raises SerializationError: if serialization fails. + :returns: The serialized data. + :rtype: str, int, float, bool, dict, list + """ + if data is None: + raise ValueError("No value for given attribute") + + try: + if data is CoreNull: + return None + if data_type in self.basic_types.values(): + return self.serialize_basic(data, data_type, **kwargs) + + if data_type in self.serialize_type: + return self.serialize_type[data_type](data, **kwargs) + + # If dependencies is empty, try with current data class + # It has to be a subclass of Enum anyway + enum_type = self.dependencies.get(data_type, data.__class__) + if issubclass(enum_type, Enum): + return Serializer.serialize_enum(data, enum_obj=enum_type) + + iter_type = data_type[0] + data_type[-1] + if iter_type in self.serialize_type: + return self.serialize_type[iter_type](data, data_type[1:-1], **kwargs) + + except (ValueError, TypeError) as err: + msg = "Unable to serialize value: {!r} as type: {!r}." + raise SerializationError(msg.format(data, data_type)) from err + return self._serialize(data, **kwargs) + + @classmethod + def _get_custom_serializers(cls, data_type, **kwargs): # pylint: disable=inconsistent-return-statements + custom_serializer = kwargs.get("basic_types_serializers", {}).get(data_type) + if custom_serializer: + return custom_serializer + if kwargs.get("is_xml", False): + return cls._xml_basic_types_serializers.get(data_type) + + @classmethod + def serialize_basic(cls, data, data_type, **kwargs): + """Serialize basic builting data type. + Serializes objects to str, int, float or bool. + + Possible kwargs: + - basic_types_serializers dict[str, callable] : If set, use the callable as serializer + - is_xml bool : If set, use xml_basic_types_serializers + + :param obj data: Object to be serialized. + :param str data_type: Type of object in the iterable. + :rtype: str, int, float, bool + :return: serialized object + """ + custom_serializer = cls._get_custom_serializers(data_type, **kwargs) + if custom_serializer: + return custom_serializer(data) + if data_type == "str": + return cls.serialize_unicode(data) + return eval(data_type)(data) # nosec # pylint: disable=eval-used + + @classmethod + def serialize_unicode(cls, data): + """Special handling for serializing unicode strings in Py2. + Encode to UTF-8 if unicode, otherwise handle as a str. + + :param str data: Object to be serialized. + :rtype: str + :return: serialized object + """ + try: # If I received an enum, return its value + return data.value + except AttributeError: + pass + + try: + if isinstance(data, unicode): # type: ignore + # Don't change it, JSON and XML ElementTree are totally able + # to serialize correctly u'' strings + return data + except NameError: + return str(data) + return str(data) + + def serialize_iter(self, data, iter_type, div=None, **kwargs): + """Serialize iterable. + + Supported kwargs: + - serialization_ctxt dict : The current entry of _attribute_map, or same format. + serialization_ctxt['type'] should be same as data_type. + - is_xml bool : If set, serialize as XML + + :param list data: Object to be serialized. + :param str iter_type: Type of object in the iterable. + :param str div: If set, this str will be used to combine the elements + in the iterable into a combined string. Default is 'None'. + Defaults to False. + :rtype: list, str + :return: serialized iterable + """ + if isinstance(data, str): + raise SerializationError("Refuse str type as a valid iter type.") + + serialization_ctxt = kwargs.get("serialization_ctxt", {}) + is_xml = kwargs.get("is_xml", False) + + serialized = [] + for d in data: + try: + serialized.append(self.serialize_data(d, iter_type, **kwargs)) + except ValueError as err: + if isinstance(err, SerializationError): + raise + serialized.append(None) + + if kwargs.get("do_quote", False): + serialized = ["" if s is None else quote(str(s), safe="") for s in serialized] + + if div: + serialized = ["" if s is None else str(s) for s in serialized] + serialized = div.join(serialized) + + if "xml" in serialization_ctxt or is_xml: + # XML serialization is more complicated + xml_desc = serialization_ctxt.get("xml", {}) + xml_name = xml_desc.get("name") + if not xml_name: + xml_name = serialization_ctxt["key"] + + # Create a wrap node if necessary (use the fact that Element and list have "append") + is_wrapped = xml_desc.get("wrapped", False) + node_name = xml_desc.get("itemsName", xml_name) + if is_wrapped: + final_result = _create_xml_node(xml_name, xml_desc.get("prefix", None), xml_desc.get("ns", None)) + else: + final_result = [] + # All list elements to "local_node" + for el in serialized: + if isinstance(el, ET.Element): + el_node = el + else: + el_node = _create_xml_node(node_name, xml_desc.get("prefix", None), xml_desc.get("ns", None)) + if el is not None: # Otherwise it writes "None" :-p + el_node.text = str(el) + final_result.append(el_node) + return final_result + return serialized + + def serialize_dict(self, attr, dict_type, **kwargs): + """Serialize a dictionary of objects. + + :param dict attr: Object to be serialized. + :param str dict_type: Type of object in the dictionary. + :rtype: dict + :return: serialized dictionary + """ + serialization_ctxt = kwargs.get("serialization_ctxt", {}) + serialized = {} + for key, value in attr.items(): + try: + serialized[self.serialize_unicode(key)] = self.serialize_data(value, dict_type, **kwargs) + except ValueError as err: + if isinstance(err, SerializationError): + raise + serialized[self.serialize_unicode(key)] = None + + if "xml" in serialization_ctxt: + # XML serialization is more complicated + xml_desc = serialization_ctxt["xml"] + xml_name = xml_desc["name"] + + final_result = _create_xml_node(xml_name, xml_desc.get("prefix", None), xml_desc.get("ns", None)) + for key, value in serialized.items(): + ET.SubElement(final_result, key).text = value + return final_result + + return serialized + + def serialize_object(self, attr, **kwargs): # pylint: disable=too-many-return-statements + """Serialize a generic object. + This will be handled as a dictionary. If object passed in is not + a basic type (str, int, float, dict, list) it will simply be + cast to str. + + :param dict attr: Object to be serialized. + :rtype: dict or str + :return: serialized object + """ + if attr is None: + return None + if isinstance(attr, ET.Element): + return attr + obj_type = type(attr) + if obj_type in self.basic_types: + return self.serialize_basic(attr, self.basic_types[obj_type], **kwargs) + if obj_type is _long_type: + return self.serialize_long(attr) + if obj_type is str: + return self.serialize_unicode(attr) + if obj_type is datetime.datetime: + return self.serialize_iso(attr) + if obj_type is datetime.date: + return self.serialize_date(attr) + if obj_type is datetime.time: + return self.serialize_time(attr) + if obj_type is datetime.timedelta: + return self.serialize_duration(attr) + if obj_type is decimal.Decimal: + return self.serialize_decimal(attr) + + # If it's a model or I know this dependency, serialize as a Model + if obj_type in self.dependencies.values() or isinstance(attr, Model): + return self._serialize(attr) + + if obj_type == dict: + serialized = {} + for key, value in attr.items(): + try: + serialized[self.serialize_unicode(key)] = self.serialize_object(value, **kwargs) + except ValueError: + serialized[self.serialize_unicode(key)] = None + return serialized + + if obj_type == list: + serialized = [] + for obj in attr: + try: + serialized.append(self.serialize_object(obj, **kwargs)) + except ValueError: + pass + return serialized + return str(attr) + + @staticmethod + def serialize_enum(attr, enum_obj=None): + try: + result = attr.value + except AttributeError: + result = attr + try: + enum_obj(result) # type: ignore + return result + except ValueError as exc: + for enum_value in enum_obj: # type: ignore + if enum_value.value.lower() == str(attr).lower(): + return enum_value.value + error = "{!r} is not valid value for enum {!r}" + raise SerializationError(error.format(attr, enum_obj)) from exc + + @staticmethod + def serialize_bytearray(attr, **kwargs): # pylint: disable=unused-argument + """Serialize bytearray into base-64 string. + + :param str attr: Object to be serialized. + :rtype: str + :return: serialized base64 + """ + return b64encode(attr).decode() + + @staticmethod + def serialize_base64(attr, **kwargs): # pylint: disable=unused-argument + """Serialize str into base-64 string. + + :param str attr: Object to be serialized. + :rtype: str + :return: serialized base64 + """ + encoded = b64encode(attr).decode("ascii") + return encoded.strip("=").replace("+", "-").replace("/", "_") + + @staticmethod + def serialize_decimal(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Decimal object to float. + + :param decimal attr: Object to be serialized. + :rtype: float + :return: serialized decimal + """ + return float(attr) + + @staticmethod + def serialize_long(attr, **kwargs): # pylint: disable=unused-argument + """Serialize long (Py2) or int (Py3). + + :param int attr: Object to be serialized. + :rtype: int/long + :return: serialized long + """ + return _long_type(attr) + + @staticmethod + def serialize_date(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Date object into ISO-8601 formatted string. + + :param Date attr: Object to be serialized. + :rtype: str + :return: serialized date + """ + if isinstance(attr, str): + attr = isodate.parse_date(attr) + t = "{:04}-{:02}-{:02}".format(attr.year, attr.month, attr.day) + return t + + @staticmethod + def serialize_time(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Time object into ISO-8601 formatted string. + + :param datetime.time attr: Object to be serialized. + :rtype: str + :return: serialized time + """ + if isinstance(attr, str): + attr = isodate.parse_time(attr) + t = "{:02}:{:02}:{:02}".format(attr.hour, attr.minute, attr.second) + if attr.microsecond: + t += ".{:02}".format(attr.microsecond) + return t + + @staticmethod + def serialize_duration(attr, **kwargs): # pylint: disable=unused-argument + """Serialize TimeDelta object into ISO-8601 formatted string. + + :param TimeDelta attr: Object to be serialized. + :rtype: str + :return: serialized duration + """ + if isinstance(attr, str): + attr = isodate.parse_duration(attr) + return isodate.duration_isoformat(attr) + + @staticmethod + def serialize_rfc(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Datetime object into RFC-1123 formatted string. + + :param Datetime attr: Object to be serialized. + :rtype: str + :raises TypeError: if format invalid. + :return: serialized rfc + """ + try: + if not attr.tzinfo: + _LOGGER.warning("Datetime with no tzinfo will be considered UTC.") + utc = attr.utctimetuple() + except AttributeError as exc: + raise TypeError("RFC1123 object must be valid Datetime object.") from exc + + return "{}, {:02} {} {:04} {:02}:{:02}:{:02} GMT".format( + Serializer.days[utc.tm_wday], + utc.tm_mday, + Serializer.months[utc.tm_mon], + utc.tm_year, + utc.tm_hour, + utc.tm_min, + utc.tm_sec, + ) + + @staticmethod + def serialize_iso(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Datetime object into ISO-8601 formatted string. + + :param Datetime attr: Object to be serialized. + :rtype: str + :raises SerializationError: if format invalid. + :return: serialized iso + """ + if isinstance(attr, str): + attr = isodate.parse_datetime(attr) + try: + if not attr.tzinfo: + _LOGGER.warning("Datetime with no tzinfo will be considered UTC.") + utc = attr.utctimetuple() + if utc.tm_year > 9999 or utc.tm_year < 1: + raise OverflowError("Hit max or min date") + + microseconds = str(attr.microsecond).rjust(6, "0").rstrip("0").ljust(3, "0") + if microseconds: + microseconds = "." + microseconds + date = "{:04}-{:02}-{:02}T{:02}:{:02}:{:02}".format( + utc.tm_year, utc.tm_mon, utc.tm_mday, utc.tm_hour, utc.tm_min, utc.tm_sec + ) + return date + microseconds + "Z" + except (ValueError, OverflowError) as err: + msg = "Unable to serialize datetime object." + raise SerializationError(msg) from err + except AttributeError as err: + msg = "ISO-8601 object must be valid Datetime object." + raise TypeError(msg) from err + + @staticmethod + def serialize_unix(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Datetime object into IntTime format. + This is represented as seconds. + + :param Datetime attr: Object to be serialized. + :rtype: int + :raises SerializationError: if format invalid + :return: serialied unix + """ + if isinstance(attr, int): + return attr + try: + if not attr.tzinfo: + _LOGGER.warning("Datetime with no tzinfo will be considered UTC.") + return int(calendar.timegm(attr.utctimetuple())) + except AttributeError as exc: + raise TypeError("Unix time object must be valid Datetime object.") from exc + + +def rest_key_extractor(attr, attr_desc, data): # pylint: disable=unused-argument + key = attr_desc["key"] + working_data = data + + while "." in key: + # Need the cast, as for some reasons "split" is typed as list[str | Any] + dict_keys = cast(List[str], _FLATTEN.split(key)) + if len(dict_keys) == 1: + key = _decode_attribute_map_key(dict_keys[0]) + break + working_key = _decode_attribute_map_key(dict_keys[0]) + working_data = working_data.get(working_key, data) + if working_data is None: + # If at any point while following flatten JSON path see None, it means + # that all properties under are None as well + return None + key = ".".join(dict_keys[1:]) + + return working_data.get(key) + + +def rest_key_case_insensitive_extractor( # pylint: disable=unused-argument, inconsistent-return-statements + attr, attr_desc, data +): + key = attr_desc["key"] + working_data = data + + while "." in key: + dict_keys = _FLATTEN.split(key) + if len(dict_keys) == 1: + key = _decode_attribute_map_key(dict_keys[0]) + break + working_key = _decode_attribute_map_key(dict_keys[0]) + working_data = attribute_key_case_insensitive_extractor(working_key, None, working_data) + if working_data is None: + # If at any point while following flatten JSON path see None, it means + # that all properties under are None as well + return None + key = ".".join(dict_keys[1:]) + + if working_data: + return attribute_key_case_insensitive_extractor(key, None, working_data) + + +def last_rest_key_extractor(attr, attr_desc, data): # pylint: disable=unused-argument + """Extract the attribute in "data" based on the last part of the JSON path key. + + :param str attr: The attribute to extract + :param dict attr_desc: The attribute description + :param dict data: The data to extract from + :rtype: object + :returns: The extracted attribute + """ + key = attr_desc["key"] + dict_keys = _FLATTEN.split(key) + return attribute_key_extractor(dict_keys[-1], None, data) + + +def last_rest_key_case_insensitive_extractor(attr, attr_desc, data): # pylint: disable=unused-argument + """Extract the attribute in "data" based on the last part of the JSON path key. + + This is the case insensitive version of "last_rest_key_extractor" + :param str attr: The attribute to extract + :param dict attr_desc: The attribute description + :param dict data: The data to extract from + :rtype: object + :returns: The extracted attribute + """ + key = attr_desc["key"] + dict_keys = _FLATTEN.split(key) + return attribute_key_case_insensitive_extractor(dict_keys[-1], None, data) + + +def attribute_key_extractor(attr, _, data): + return data.get(attr) + + +def attribute_key_case_insensitive_extractor(attr, _, data): + found_key = None + lower_attr = attr.lower() + for key in data: + if lower_attr == key.lower(): + found_key = key + break + + return data.get(found_key) + + +def _extract_name_from_internal_type(internal_type): + """Given an internal type XML description, extract correct XML name with namespace. + + :param dict internal_type: An model type + :rtype: tuple + :returns: A tuple XML name + namespace dict + """ + internal_type_xml_map = getattr(internal_type, "_xml_map", {}) + xml_name = internal_type_xml_map.get("name", internal_type.__name__) + xml_ns = internal_type_xml_map.get("ns", None) + if xml_ns: + xml_name = "{{{}}}{}".format(xml_ns, xml_name) + return xml_name + + +def xml_key_extractor(attr, attr_desc, data): # pylint: disable=unused-argument,too-many-return-statements + if isinstance(data, dict): + return None + + # Test if this model is XML ready first + if not isinstance(data, ET.Element): + return None + + xml_desc = attr_desc.get("xml", {}) + xml_name = xml_desc.get("name", attr_desc["key"]) + + # Look for a children + is_iter_type = attr_desc["type"].startswith("[") + is_wrapped = xml_desc.get("wrapped", False) + internal_type = attr_desc.get("internalType", None) + internal_type_xml_map = getattr(internal_type, "_xml_map", {}) + + # Integrate namespace if necessary + xml_ns = xml_desc.get("ns", internal_type_xml_map.get("ns", None)) + if xml_ns: + xml_name = "{{{}}}{}".format(xml_ns, xml_name) + + # If it's an attribute, that's simple + if xml_desc.get("attr", False): + return data.get(xml_name) + + # If it's x-ms-text, that's simple too + if xml_desc.get("text", False): + return data.text + + # Scenario where I take the local name: + # - Wrapped node + # - Internal type is an enum (considered basic types) + # - Internal type has no XML/Name node + if is_wrapped or (internal_type and (issubclass(internal_type, Enum) or "name" not in internal_type_xml_map)): + children = data.findall(xml_name) + # If internal type has a local name and it's not a list, I use that name + elif not is_iter_type and internal_type and "name" in internal_type_xml_map: + xml_name = _extract_name_from_internal_type(internal_type) + children = data.findall(xml_name) + # That's an array + else: + if internal_type: # Complex type, ignore itemsName and use the complex type name + items_name = _extract_name_from_internal_type(internal_type) + else: + items_name = xml_desc.get("itemsName", xml_name) + children = data.findall(items_name) + + if len(children) == 0: + if is_iter_type: + if is_wrapped: + return None # is_wrapped no node, we want None + return [] # not wrapped, assume empty list + return None # Assume it's not there, maybe an optional node. + + # If is_iter_type and not wrapped, return all found children + if is_iter_type: + if not is_wrapped: + return children + # Iter and wrapped, should have found one node only (the wrap one) + if len(children) != 1: + raise DeserializationError( + "Tried to deserialize an array not wrapped, and found several nodes '{}'. Maybe you should declare this array as wrapped?".format( + xml_name + ) + ) + return list(children[0]) # Might be empty list and that's ok. + + # Here it's not a itertype, we should have found one element only or empty + if len(children) > 1: + raise DeserializationError("Find several XML '{}' where it was not expected".format(xml_name)) + return children[0] + + +class Deserializer: + """Response object model deserializer. + + :param dict classes: Class type dictionary for deserializing complex types. + :ivar list key_extractors: Ordered list of extractors to be used by this deserializer. + """ + + basic_types = {str: "str", int: "int", bool: "bool", float: "float"} + + valid_date = re.compile(r"\d{4}[-]\d{2}[-]\d{2}T\d{2}:\d{2}:\d{2}\.?\d*Z?[-+]?[\d{2}]?:?[\d{2}]?") + + def __init__(self, classes: Optional[Mapping[str, type]] = None) -> None: + self.deserialize_type = { + "iso-8601": Deserializer.deserialize_iso, + "rfc-1123": Deserializer.deserialize_rfc, + "unix-time": Deserializer.deserialize_unix, + "duration": Deserializer.deserialize_duration, + "date": Deserializer.deserialize_date, + "time": Deserializer.deserialize_time, + "decimal": Deserializer.deserialize_decimal, + "long": Deserializer.deserialize_long, + "bytearray": Deserializer.deserialize_bytearray, + "base64": Deserializer.deserialize_base64, + "object": self.deserialize_object, + "[]": self.deserialize_iter, + "{}": self.deserialize_dict, + } + self.deserialize_expected_types = { + "duration": (isodate.Duration, datetime.timedelta), + "iso-8601": (datetime.datetime), + } + self.dependencies: Dict[str, type] = dict(classes) if classes else {} + self.key_extractors = [rest_key_extractor, xml_key_extractor] + # Additional properties only works if the "rest_key_extractor" is used to + # extract the keys. Making it to work whatever the key extractor is too much + # complicated, with no real scenario for now. + # So adding a flag to disable additional properties detection. This flag should be + # used if your expect the deserialization to NOT come from a JSON REST syntax. + # Otherwise, result are unexpected + self.additional_properties_detection = True + + def __call__(self, target_obj, response_data, content_type=None): + """Call the deserializer to process a REST response. + + :param str target_obj: Target data type to deserialize to. + :param requests.Response response_data: REST response object. + :param str content_type: Swagger "produces" if available. + :raises DeserializationError: if deserialization fails. + :return: Deserialized object. + :rtype: object + """ + data = self._unpack_content(response_data, content_type) + return self._deserialize(target_obj, data) + + def _deserialize(self, target_obj, data): # pylint: disable=inconsistent-return-statements + """Call the deserializer on a model. + + Data needs to be already deserialized as JSON or XML ElementTree + + :param str target_obj: Target data type to deserialize to. + :param object data: Object to deserialize. + :raises DeserializationError: if deserialization fails. + :return: Deserialized object. + :rtype: object + """ + # This is already a model, go recursive just in case + if hasattr(data, "_attribute_map"): + constants = [name for name, config in getattr(data, "_validation", {}).items() if config.get("constant")] + try: + for attr, mapconfig in data._attribute_map.items(): # pylint: disable=protected-access + if attr in constants: + continue + value = getattr(data, attr) + if value is None: + continue + local_type = mapconfig["type"] + internal_data_type = local_type.strip("[]{}") + if internal_data_type not in self.dependencies or isinstance(internal_data_type, Enum): + continue + setattr(data, attr, self._deserialize(local_type, value)) + return data + except AttributeError: + return + + response, class_name = self._classify_target(target_obj, data) + + if isinstance(response, str): + return self.deserialize_data(data, response) + if isinstance(response, type) and issubclass(response, Enum): + return self.deserialize_enum(data, response) + + if data is None or data is CoreNull: + return data + try: + attributes = response._attribute_map # type: ignore # pylint: disable=protected-access + d_attrs = {} + for attr, attr_desc in attributes.items(): + # Check empty string. If it's not empty, someone has a real "additionalProperties"... + if attr == "additional_properties" and attr_desc["key"] == "": + continue + raw_value = None + # Enhance attr_desc with some dynamic data + attr_desc = attr_desc.copy() # Do a copy, do not change the real one + internal_data_type = attr_desc["type"].strip("[]{}") + if internal_data_type in self.dependencies: + attr_desc["internalType"] = self.dependencies[internal_data_type] + + for key_extractor in self.key_extractors: + found_value = key_extractor(attr, attr_desc, data) + if found_value is not None: + if raw_value is not None and raw_value != found_value: + msg = ( + "Ignoring extracted value '%s' from %s for key '%s'" + " (duplicate extraction, follow extractors order)" + ) + _LOGGER.warning(msg, found_value, key_extractor, attr) + continue + raw_value = found_value + + value = self.deserialize_data(raw_value, attr_desc["type"]) + d_attrs[attr] = value + except (AttributeError, TypeError, KeyError) as err: + msg = "Unable to deserialize to object: " + class_name # type: ignore + raise DeserializationError(msg) from err + additional_properties = self._build_additional_properties(attributes, data) + return self._instantiate_model(response, d_attrs, additional_properties) + + def _build_additional_properties(self, attribute_map, data): + if not self.additional_properties_detection: + return None + if "additional_properties" in attribute_map and attribute_map.get("additional_properties", {}).get("key") != "": + # Check empty string. If it's not empty, someone has a real "additionalProperties" + return None + if isinstance(data, ET.Element): + data = {el.tag: el.text for el in data} + + known_keys = { + _decode_attribute_map_key(_FLATTEN.split(desc["key"])[0]) + for desc in attribute_map.values() + if desc["key"] != "" + } + present_keys = set(data.keys()) + missing_keys = present_keys - known_keys + return {key: data[key] for key in missing_keys} + + def _classify_target(self, target, data): + """Check to see whether the deserialization target object can + be classified into a subclass. + Once classification has been determined, initialize object. + + :param str target: The target object type to deserialize to. + :param str/dict data: The response data to deserialize. + :return: The classified target object and its class name. + :rtype: tuple + """ + if target is None: + return None, None + + if isinstance(target, str): + try: + target = self.dependencies[target] + except KeyError: + return target, target + + try: + target = target._classify(data, self.dependencies) # type: ignore # pylint: disable=protected-access + except AttributeError: + pass # Target is not a Model, no classify + return target, target.__class__.__name__ # type: ignore + + def failsafe_deserialize(self, target_obj, data, content_type=None): + """Ignores any errors encountered in deserialization, + and falls back to not deserializing the object. Recommended + for use in error deserialization, as we want to return the + HttpResponseError to users, and not have them deal with + a deserialization error. + + :param str target_obj: The target object type to deserialize to. + :param str/dict data: The response data to deserialize. + :param str content_type: Swagger "produces" if available. + :return: Deserialized object. + :rtype: object + """ + try: + return self(target_obj, data, content_type=content_type) + except: # pylint: disable=bare-except + _LOGGER.debug( + "Ran into a deserialization error. Ignoring since this is failsafe deserialization", exc_info=True + ) + return None + + @staticmethod + def _unpack_content(raw_data, content_type=None): + """Extract the correct structure for deserialization. + + If raw_data is a PipelineResponse, try to extract the result of RawDeserializer. + if we can't, raise. Your Pipeline should have a RawDeserializer. + + If not a pipeline response and raw_data is bytes or string, use content-type + to decode it. If no content-type, try JSON. + + If raw_data is something else, bypass all logic and return it directly. + + :param obj raw_data: Data to be processed. + :param str content_type: How to parse if raw_data is a string/bytes. + :raises JSONDecodeError: If JSON is requested and parsing is impossible. + :raises UnicodeDecodeError: If bytes is not UTF8 + :rtype: object + :return: Unpacked content. + """ + # Assume this is enough to detect a Pipeline Response without importing it + context = getattr(raw_data, "context", {}) + if context: + if RawDeserializer.CONTEXT_NAME in context: + return context[RawDeserializer.CONTEXT_NAME] + raise ValueError("This pipeline didn't have the RawDeserializer policy; can't deserialize") + + # Assume this is enough to recognize universal_http.ClientResponse without importing it + if hasattr(raw_data, "body"): + return RawDeserializer.deserialize_from_http_generics(raw_data.text(), raw_data.headers) + + # Assume this enough to recognize requests.Response without importing it. + if hasattr(raw_data, "_content_consumed"): + return RawDeserializer.deserialize_from_http_generics(raw_data.text, raw_data.headers) + + if isinstance(raw_data, (str, bytes)) or hasattr(raw_data, "read"): + return RawDeserializer.deserialize_from_text(raw_data, content_type) # type: ignore + return raw_data + + def _instantiate_model(self, response, attrs, additional_properties=None): + """Instantiate a response model passing in deserialized args. + + :param Response response: The response model class. + :param dict attrs: The deserialized response attributes. + :param dict additional_properties: Additional properties to be set. + :rtype: Response + :return: The instantiated response model. + """ + if callable(response): + subtype = getattr(response, "_subtype_map", {}) + try: + readonly = [ + k + for k, v in response._validation.items() # pylint: disable=protected-access # type: ignore + if v.get("readonly") + ] + const = [ + k + for k, v in response._validation.items() # pylint: disable=protected-access # type: ignore + if v.get("constant") + ] + kwargs = {k: v for k, v in attrs.items() if k not in subtype and k not in readonly + const} + response_obj = response(**kwargs) + for attr in readonly: + setattr(response_obj, attr, attrs.get(attr)) + if additional_properties: + response_obj.additional_properties = additional_properties # type: ignore + return response_obj + except TypeError as err: + msg = "Unable to deserialize {} into model {}. ".format(kwargs, response) # type: ignore + raise DeserializationError(msg + str(err)) from err + else: + try: + for attr, value in attrs.items(): + setattr(response, attr, value) + return response + except Exception as exp: + msg = "Unable to populate response model. " + msg += "Type: {}, Error: {}".format(type(response), exp) + raise DeserializationError(msg) from exp + + def deserialize_data(self, data, data_type): # pylint: disable=too-many-return-statements + """Process data for deserialization according to data type. + + :param str data: The response string to be deserialized. + :param str data_type: The type to deserialize to. + :raises DeserializationError: if deserialization fails. + :return: Deserialized object. + :rtype: object + """ + if data is None: + return data + + try: + if not data_type: + return data + if data_type in self.basic_types.values(): + return self.deserialize_basic(data, data_type) + if data_type in self.deserialize_type: + if isinstance(data, self.deserialize_expected_types.get(data_type, tuple())): + return data + + is_a_text_parsing_type = lambda x: x not in [ # pylint: disable=unnecessary-lambda-assignment + "object", + "[]", + r"{}", + ] + if isinstance(data, ET.Element) and is_a_text_parsing_type(data_type) and not data.text: + return None + data_val = self.deserialize_type[data_type](data) + return data_val + + iter_type = data_type[0] + data_type[-1] + if iter_type in self.deserialize_type: + return self.deserialize_type[iter_type](data, data_type[1:-1]) + + obj_type = self.dependencies[data_type] + if issubclass(obj_type, Enum): + if isinstance(data, ET.Element): + data = data.text + return self.deserialize_enum(data, obj_type) + + except (ValueError, TypeError, AttributeError) as err: + msg = "Unable to deserialize response data." + msg += " Data: {}, {}".format(data, data_type) + raise DeserializationError(msg) from err + return self._deserialize(obj_type, data) + + def deserialize_iter(self, attr, iter_type): + """Deserialize an iterable. + + :param list attr: Iterable to be deserialized. + :param str iter_type: The type of object in the iterable. + :return: Deserialized iterable. + :rtype: list + """ + if attr is None: + return None + if isinstance(attr, ET.Element): # If I receive an element here, get the children + attr = list(attr) + if not isinstance(attr, (list, set)): + raise DeserializationError("Cannot deserialize as [{}] an object of type {}".format(iter_type, type(attr))) + return [self.deserialize_data(a, iter_type) for a in attr] + + def deserialize_dict(self, attr, dict_type): + """Deserialize a dictionary. + + :param dict/list attr: Dictionary to be deserialized. Also accepts + a list of key, value pairs. + :param str dict_type: The object type of the items in the dictionary. + :return: Deserialized dictionary. + :rtype: dict + """ + if isinstance(attr, list): + return {x["key"]: self.deserialize_data(x["value"], dict_type) for x in attr} + + if isinstance(attr, ET.Element): + # Transform value into {"Key": "value"} + attr = {el.tag: el.text for el in attr} + return {k: self.deserialize_data(v, dict_type) for k, v in attr.items()} + + def deserialize_object(self, attr, **kwargs): # pylint: disable=too-many-return-statements + """Deserialize a generic object. + This will be handled as a dictionary. + + :param dict attr: Dictionary to be deserialized. + :return: Deserialized object. + :rtype: dict + :raises TypeError: if non-builtin datatype encountered. + """ + if attr is None: + return None + if isinstance(attr, ET.Element): + # Do no recurse on XML, just return the tree as-is + return attr + if isinstance(attr, str): + return self.deserialize_basic(attr, "str") + obj_type = type(attr) + if obj_type in self.basic_types: + return self.deserialize_basic(attr, self.basic_types[obj_type]) + if obj_type is _long_type: + return self.deserialize_long(attr) + + if obj_type == dict: + deserialized = {} + for key, value in attr.items(): + try: + deserialized[key] = self.deserialize_object(value, **kwargs) + except ValueError: + deserialized[key] = None + return deserialized + + if obj_type == list: + deserialized = [] + for obj in attr: + try: + deserialized.append(self.deserialize_object(obj, **kwargs)) + except ValueError: + pass + return deserialized + + error = "Cannot deserialize generic object with type: " + raise TypeError(error + str(obj_type)) + + def deserialize_basic(self, attr, data_type): # pylint: disable=too-many-return-statements + """Deserialize basic builtin data type from string. + Will attempt to convert to str, int, float and bool. + This function will also accept '1', '0', 'true' and 'false' as + valid bool values. + + :param str attr: response string to be deserialized. + :param str data_type: deserialization data type. + :return: Deserialized basic type. + :rtype: str, int, float or bool + :raises TypeError: if string format is not valid. + """ + # If we're here, data is supposed to be a basic type. + # If it's still an XML node, take the text + if isinstance(attr, ET.Element): + attr = attr.text + if not attr: + if data_type == "str": + # None or '', node is empty string. + return "" + # None or '', node with a strong type is None. + # Don't try to model "empty bool" or "empty int" + return None + + if data_type == "bool": + if attr in [True, False, 1, 0]: + return bool(attr) + if isinstance(attr, str): + if attr.lower() in ["true", "1"]: + return True + if attr.lower() in ["false", "0"]: + return False + raise TypeError("Invalid boolean value: {}".format(attr)) + + if data_type == "str": + return self.deserialize_unicode(attr) + return eval(data_type)(attr) # nosec # pylint: disable=eval-used + + @staticmethod + def deserialize_unicode(data): + """Preserve unicode objects in Python 2, otherwise return data + as a string. + + :param str data: response string to be deserialized. + :return: Deserialized string. + :rtype: str or unicode + """ + # We might be here because we have an enum modeled as string, + # and we try to deserialize a partial dict with enum inside + if isinstance(data, Enum): + return data + + # Consider this is real string + try: + if isinstance(data, unicode): # type: ignore + return data + except NameError: + return str(data) + return str(data) + + @staticmethod + def deserialize_enum(data, enum_obj): + """Deserialize string into enum object. + + If the string is not a valid enum value it will be returned as-is + and a warning will be logged. + + :param str data: Response string to be deserialized. If this value is + None or invalid it will be returned as-is. + :param Enum enum_obj: Enum object to deserialize to. + :return: Deserialized enum object. + :rtype: Enum + """ + if isinstance(data, enum_obj) or data is None: + return data + if isinstance(data, Enum): + data = data.value + if isinstance(data, int): + # Workaround. We might consider remove it in the future. + try: + return list(enum_obj.__members__.values())[data] + except IndexError as exc: + error = "{!r} is not a valid index for enum {!r}" + raise DeserializationError(error.format(data, enum_obj)) from exc + try: + return enum_obj(str(data)) + except ValueError: + for enum_value in enum_obj: + if enum_value.value.lower() == str(data).lower(): + return enum_value + # We don't fail anymore for unknown value, we deserialize as a string + _LOGGER.warning("Deserializer is not able to find %s as valid enum in %s", data, enum_obj) + return Deserializer.deserialize_unicode(data) + + @staticmethod + def deserialize_bytearray(attr): + """Deserialize string into bytearray. + + :param str attr: response string to be deserialized. + :return: Deserialized bytearray + :rtype: bytearray + :raises TypeError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + return bytearray(b64decode(attr)) # type: ignore + + @staticmethod + def deserialize_base64(attr): + """Deserialize base64 encoded string into string. + + :param str attr: response string to be deserialized. + :return: Deserialized base64 string + :rtype: bytearray + :raises TypeError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + padding = "=" * (3 - (len(attr) + 3) % 4) # type: ignore + attr = attr + padding # type: ignore + encoded = attr.replace("-", "+").replace("_", "/") + return b64decode(encoded) + + @staticmethod + def deserialize_decimal(attr): + """Deserialize string into Decimal object. + + :param str attr: response string to be deserialized. + :return: Deserialized decimal + :raises DeserializationError: if string format invalid. + :rtype: decimal + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + return decimal.Decimal(str(attr)) # type: ignore + except decimal.DecimalException as err: + msg = "Invalid decimal {}".format(attr) + raise DeserializationError(msg) from err + + @staticmethod + def deserialize_long(attr): + """Deserialize string into long (Py2) or int (Py3). + + :param str attr: response string to be deserialized. + :return: Deserialized int + :rtype: long or int + :raises ValueError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + return _long_type(attr) # type: ignore + + @staticmethod + def deserialize_duration(attr): + """Deserialize ISO-8601 formatted string into TimeDelta object. + + :param str attr: response string to be deserialized. + :return: Deserialized duration + :rtype: TimeDelta + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + duration = isodate.parse_duration(attr) + except (ValueError, OverflowError, AttributeError) as err: + msg = "Cannot deserialize duration object." + raise DeserializationError(msg) from err + return duration + + @staticmethod + def deserialize_date(attr): + """Deserialize ISO-8601 formatted string into Date object. + + :param str attr: response string to be deserialized. + :return: Deserialized date + :rtype: Date + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + if re.search(r"[^\W\d_]", attr, re.I + re.U): # type: ignore + raise DeserializationError("Date must have only digits and -. Received: %s" % attr) + # This must NOT use defaultmonth/defaultday. Using None ensure this raises an exception. + return isodate.parse_date(attr, defaultmonth=0, defaultday=0) + + @staticmethod + def deserialize_time(attr): + """Deserialize ISO-8601 formatted string into time object. + + :param str attr: response string to be deserialized. + :return: Deserialized time + :rtype: datetime.time + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + if re.search(r"[^\W\d_]", attr, re.I + re.U): # type: ignore + raise DeserializationError("Date must have only digits and -. Received: %s" % attr) + return isodate.parse_time(attr) + + @staticmethod + def deserialize_rfc(attr): + """Deserialize RFC-1123 formatted string into Datetime object. + + :param str attr: response string to be deserialized. + :return: Deserialized RFC datetime + :rtype: Datetime + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + parsed_date = email.utils.parsedate_tz(attr) # type: ignore + date_obj = datetime.datetime( + *parsed_date[:6], tzinfo=datetime.timezone(datetime.timedelta(minutes=(parsed_date[9] or 0) / 60)) + ) + if not date_obj.tzinfo: + date_obj = date_obj.astimezone(tz=TZ_UTC) + except ValueError as err: + msg = "Cannot deserialize to rfc datetime object." + raise DeserializationError(msg) from err + return date_obj + + @staticmethod + def deserialize_iso(attr): + """Deserialize ISO-8601 formatted string into Datetime object. + + :param str attr: response string to be deserialized. + :return: Deserialized ISO datetime + :rtype: Datetime + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + attr = attr.upper() # type: ignore + match = Deserializer.valid_date.match(attr) + if not match: + raise ValueError("Invalid datetime string: " + attr) + + check_decimal = attr.split(".") + if len(check_decimal) > 1: + decimal_str = "" + for digit in check_decimal[1]: + if digit.isdigit(): + decimal_str += digit + else: + break + if len(decimal_str) > 6: + attr = attr.replace(decimal_str, decimal_str[0:6]) + + date_obj = isodate.parse_datetime(attr) + test_utc = date_obj.utctimetuple() + if test_utc.tm_year > 9999 or test_utc.tm_year < 1: + raise OverflowError("Hit max or min date") + except (ValueError, OverflowError, AttributeError) as err: + msg = "Cannot deserialize datetime object." + raise DeserializationError(msg) from err + return date_obj + + @staticmethod + def deserialize_unix(attr): + """Serialize Datetime object into IntTime format. + This is represented as seconds. + + :param int attr: Object to be serialized. + :return: Deserialized datetime + :rtype: Datetime + :raises DeserializationError: if format invalid + """ + if isinstance(attr, ET.Element): + attr = int(attr.text) # type: ignore + try: + attr = int(attr) + date_obj = datetime.datetime.fromtimestamp(attr, TZ_UTC) + except ValueError as err: + msg = "Cannot deserialize to unix datetime object." + raise DeserializationError(msg) from err + return date_obj diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/UrlVersionTolerant/urlversiontolerant/aio/_client.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/UrlVersionTolerant/urlversiontolerant/aio/_client.py index dd79adb1dcb..0d21d035505 100644 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/UrlVersionTolerant/urlversiontolerant/aio/_client.py +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/UrlVersionTolerant/urlversiontolerant/aio/_client.py @@ -14,7 +14,7 @@ from azure.core.pipeline import policies from azure.core.rest import AsyncHttpResponse, HttpRequest -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import AutoRestUrlTestServiceConfiguration from .operations import PathItemsOperations, PathsOperations, QueriesOperations diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/UrlVersionTolerant/urlversiontolerant/aio/operations/_operations.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/UrlVersionTolerant/urlversiontolerant/aio/operations/_operations.py index 76253c79e43..30b93faf84d 100644 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/UrlVersionTolerant/urlversiontolerant/aio/operations/_operations.py +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/UrlVersionTolerant/urlversiontolerant/aio/operations/_operations.py @@ -24,7 +24,7 @@ from azure.core.tracing.decorator_async import distributed_trace_async from azure.core.utils import case_insensitive_dict -from ..._serialization import Deserializer, Serializer +from ..._utils.serialization import Deserializer, Serializer from ...operations._operations import ( build_path_items_get_all_with_values_request, build_path_items_get_global_and_local_query_null_request, diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/UrlVersionTolerant/urlversiontolerant/operations/_operations.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/UrlVersionTolerant/urlversiontolerant/operations/_operations.py index e8ea6b644e6..79c3f1365a4 100644 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/UrlVersionTolerant/urlversiontolerant/operations/_operations.py +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/UrlVersionTolerant/urlversiontolerant/operations/_operations.py @@ -25,7 +25,7 @@ from azure.core.utils import case_insensitive_dict from .._configuration import AutoRestUrlTestServiceConfiguration -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ValidationVersionTolerant/validationversiontolerant/_client.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ValidationVersionTolerant/validationversiontolerant/_client.py index f68cec1e0a5..dacbec74c06 100644 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ValidationVersionTolerant/validationversiontolerant/_client.py +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ValidationVersionTolerant/validationversiontolerant/_client.py @@ -16,7 +16,7 @@ from ._configuration import AutoRestValidationTestConfiguration from ._operations import AutoRestValidationTestOperationsMixin -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer class AutoRestValidationTest(AutoRestValidationTestOperationsMixin): diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ValidationVersionTolerant/validationversiontolerant/_operations/_operations.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ValidationVersionTolerant/validationversiontolerant/_operations/_operations.py index 60059e1c344..e36459eb9d8 100644 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ValidationVersionTolerant/validationversiontolerant/_operations/_operations.py +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ValidationVersionTolerant/validationversiontolerant/_operations/_operations.py @@ -9,6 +9,7 @@ from io import IOBase from typing import Any, Callable, Dict, IO, Literal, Optional, TypeVar, Union, cast, overload +from azure.core import PipelineClient from azure.core.exceptions import ( ClientAuthenticationError, HttpResponseError, @@ -22,8 +23,9 @@ from azure.core.tracing.decorator import distributed_trace from azure.core.utils import case_insensitive_dict -from .._serialization import Serializer -from .._vendor import AutoRestValidationTestMixinABC +from .._configuration import AutoRestValidationTestConfiguration +from .._utils.serialization import Serializer +from .._utils.utils import ClientMixinABC JSON = MutableMapping[str, Any] T = TypeVar("T") @@ -136,7 +138,7 @@ def build_auto_rest_validation_test_post_with_constant_in_body_request( # pylin return HttpRequest(method="POST", url=_url, headers=_headers, **kwargs) -class AutoRestValidationTestOperationsMixin(AutoRestValidationTestMixinABC): +class AutoRestValidationTestOperationsMixin(ClientMixinABC[PipelineClient, AutoRestValidationTestConfiguration]): @distributed_trace def validation_of_method_parameters(self, resource_group_name: str, id: int, **kwargs: Any) -> JSON: diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ValidationVersionTolerant/validationversiontolerant/_utils/__init__.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ValidationVersionTolerant/validationversiontolerant/_utils/__init__.py new file mode 100644 index 00000000000..0af9b28f660 --- /dev/null +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ValidationVersionTolerant/validationversiontolerant/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ValidationVersionTolerant/validationversiontolerant/_utils/serialization.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ValidationVersionTolerant/validationversiontolerant/_utils/serialization.py new file mode 100644 index 00000000000..f5187701d7b --- /dev/null +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ValidationVersionTolerant/validationversiontolerant/_utils/serialization.py @@ -0,0 +1,2032 @@ +# pylint: disable=line-too-long,useless-suppression,too-many-lines +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +# pyright: reportUnnecessaryTypeIgnoreComment=false + +from base64 import b64decode, b64encode +import calendar +import datetime +import decimal +import email +from enum import Enum +import json +import logging +import re +import sys +import codecs +from typing import ( + Dict, + Any, + cast, + Optional, + Union, + AnyStr, + IO, + Mapping, + Callable, + MutableMapping, + List, +) + +try: + from urllib import quote # type: ignore +except ImportError: + from urllib.parse import quote +import xml.etree.ElementTree as ET + +import isodate # type: ignore +from typing_extensions import Self + +from azure.core.exceptions import DeserializationError, SerializationError +from azure.core.serialization import NULL as CoreNull + +_BOM = codecs.BOM_UTF8.decode(encoding="utf-8") + +JSON = MutableMapping[str, Any] + + +class RawDeserializer: + + # Accept "text" because we're open minded people... + JSON_REGEXP = re.compile(r"^(application|text)/([a-z+.]+\+)?json$") + + # Name used in context + CONTEXT_NAME = "deserialized_data" + + @classmethod + def deserialize_from_text(cls, data: Optional[Union[AnyStr, IO]], content_type: Optional[str] = None) -> Any: + """Decode data according to content-type. + + Accept a stream of data as well, but will be load at once in memory for now. + + If no content-type, will return the string version (not bytes, not stream) + + :param data: Input, could be bytes or stream (will be decoded with UTF8) or text + :type data: str or bytes or IO + :param str content_type: The content type. + :return: The deserialized data. + :rtype: object + """ + if hasattr(data, "read"): + # Assume a stream + data = cast(IO, data).read() + + if isinstance(data, bytes): + data_as_str = data.decode(encoding="utf-8-sig") + else: + # Explain to mypy the correct type. + data_as_str = cast(str, data) + + # Remove Byte Order Mark if present in string + data_as_str = data_as_str.lstrip(_BOM) + + if content_type is None: + return data + + if cls.JSON_REGEXP.match(content_type): + try: + return json.loads(data_as_str) + except ValueError as err: + raise DeserializationError("JSON is invalid: {}".format(err), err) from err + elif "xml" in (content_type or []): + try: + + try: + if isinstance(data, unicode): # type: ignore + # If I'm Python 2.7 and unicode XML will scream if I try a "fromstring" on unicode string + data_as_str = data_as_str.encode(encoding="utf-8") # type: ignore + except NameError: + pass + + return ET.fromstring(data_as_str) # nosec + except ET.ParseError as err: + # It might be because the server has an issue, and returned JSON with + # content-type XML.... + # So let's try a JSON load, and if it's still broken + # let's flow the initial exception + def _json_attemp(data): + try: + return True, json.loads(data) + except ValueError: + return False, None # Don't care about this one + + success, json_result = _json_attemp(data) + if success: + return json_result + # If i'm here, it's not JSON, it's not XML, let's scream + # and raise the last context in this block (the XML exception) + # The function hack is because Py2.7 messes up with exception + # context otherwise. + _LOGGER.critical("Wasn't XML not JSON, failing") + raise DeserializationError("XML is invalid") from err + elif content_type.startswith("text/"): + return data_as_str + raise DeserializationError("Cannot deserialize content-type: {}".format(content_type)) + + @classmethod + def deserialize_from_http_generics(cls, body_bytes: Optional[Union[AnyStr, IO]], headers: Mapping) -> Any: + """Deserialize from HTTP response. + + Use bytes and headers to NOT use any requests/aiohttp or whatever + specific implementation. + Headers will tested for "content-type" + + :param bytes body_bytes: The body of the response. + :param dict headers: The headers of the response. + :returns: The deserialized data. + :rtype: object + """ + # Try to use content-type from headers if available + content_type = None + if "content-type" in headers: + content_type = headers["content-type"].split(";")[0].strip().lower() + # Ouch, this server did not declare what it sent... + # Let's guess it's JSON... + # Also, since Autorest was considering that an empty body was a valid JSON, + # need that test as well.... + else: + content_type = "application/json" + + if body_bytes: + return cls.deserialize_from_text(body_bytes, content_type) + return None + + +_LOGGER = logging.getLogger(__name__) + +try: + _long_type = long # type: ignore +except NameError: + _long_type = int + +TZ_UTC = datetime.timezone.utc + +_FLATTEN = re.compile(r"(? None: + self.additional_properties: Optional[Dict[str, Any]] = {} + for k in kwargs: # pylint: disable=consider-using-dict-items + if k not in self._attribute_map: + _LOGGER.warning("%s is not a known attribute of class %s and will be ignored", k, self.__class__) + elif k in self._validation and self._validation[k].get("readonly", False): + _LOGGER.warning("Readonly attribute %s will be ignored in class %s", k, self.__class__) + else: + setattr(self, k, kwargs[k]) + + def __eq__(self, other: Any) -> bool: + """Compare objects by comparing all attributes. + + :param object other: The object to compare + :returns: True if objects are equal + :rtype: bool + """ + if isinstance(other, self.__class__): + return self.__dict__ == other.__dict__ + return False + + def __ne__(self, other: Any) -> bool: + """Compare objects by comparing all attributes. + + :param object other: The object to compare + :returns: True if objects are not equal + :rtype: bool + """ + return not self.__eq__(other) + + def __str__(self) -> str: + return str(self.__dict__) + + @classmethod + def enable_additional_properties_sending(cls) -> None: + cls._attribute_map["additional_properties"] = {"key": "", "type": "{object}"} + + @classmethod + def is_xml_model(cls) -> bool: + try: + cls._xml_map # type: ignore + except AttributeError: + return False + return True + + @classmethod + def _create_xml_node(cls): + """Create XML node. + + :returns: The XML node + :rtype: xml.etree.ElementTree.Element + """ + try: + xml_map = cls._xml_map # type: ignore + except AttributeError: + xml_map = {} + + return _create_xml_node(xml_map.get("name", cls.__name__), xml_map.get("prefix", None), xml_map.get("ns", None)) + + def serialize(self, keep_readonly: bool = False, **kwargs: Any) -> JSON: + """Return the JSON that would be sent to server from this model. + + This is an alias to `as_dict(full_restapi_key_transformer, keep_readonly=False)`. + + If you want XML serialization, you can pass the kwargs is_xml=True. + + :param bool keep_readonly: If you want to serialize the readonly attributes + :returns: A dict JSON compatible object + :rtype: dict + """ + serializer = Serializer(self._infer_class_models()) + return serializer._serialize( # type: ignore # pylint: disable=protected-access + self, keep_readonly=keep_readonly, **kwargs + ) + + def as_dict( + self, + keep_readonly: bool = True, + key_transformer: Callable[[str, Dict[str, Any], Any], Any] = attribute_transformer, + **kwargs: Any + ) -> JSON: + """Return a dict that can be serialized using json.dump. + + Advanced usage might optionally use a callback as parameter: + + .. code::python + + def my_key_transformer(key, attr_desc, value): + return key + + Key is the attribute name used in Python. Attr_desc + is a dict of metadata. Currently contains 'type' with the + msrest type and 'key' with the RestAPI encoded key. + Value is the current value in this object. + + The string returned will be used to serialize the key. + If the return type is a list, this is considered hierarchical + result dict. + + See the three examples in this file: + + - attribute_transformer + - full_restapi_key_transformer + - last_restapi_key_transformer + + If you want XML serialization, you can pass the kwargs is_xml=True. + + :param bool keep_readonly: If you want to serialize the readonly attributes + :param function key_transformer: A key transformer function. + :returns: A dict JSON compatible object + :rtype: dict + """ + serializer = Serializer(self._infer_class_models()) + return serializer._serialize( # type: ignore # pylint: disable=protected-access + self, key_transformer=key_transformer, keep_readonly=keep_readonly, **kwargs + ) + + @classmethod + def _infer_class_models(cls): + try: + str_models = cls.__module__.rsplit(".", 1)[0] + models = sys.modules[str_models] + client_models = {k: v for k, v in models.__dict__.items() if isinstance(v, type)} + if cls.__name__ not in client_models: + raise ValueError("Not Autorest generated code") + except Exception: # pylint: disable=broad-exception-caught + # Assume it's not Autorest generated (tests?). Add ourselves as dependencies. + client_models = {cls.__name__: cls} + return client_models + + @classmethod + def deserialize(cls, data: Any, content_type: Optional[str] = None) -> Self: + """Parse a str using the RestAPI syntax and return a model. + + :param str data: A str using RestAPI structure. JSON by default. + :param str content_type: JSON by default, set application/xml if XML. + :returns: An instance of this model + :raises DeserializationError: if something went wrong + :rtype: Self + """ + deserializer = Deserializer(cls._infer_class_models()) + return deserializer(cls.__name__, data, content_type=content_type) # type: ignore + + @classmethod + def from_dict( + cls, + data: Any, + key_extractors: Optional[Callable[[str, Dict[str, Any], Any], Any]] = None, + content_type: Optional[str] = None, + ) -> Self: + """Parse a dict using given key extractor return a model. + + By default consider key + extractors (rest_key_case_insensitive_extractor, attribute_key_case_insensitive_extractor + and last_rest_key_case_insensitive_extractor) + + :param dict data: A dict using RestAPI structure + :param function key_extractors: A key extractor function. + :param str content_type: JSON by default, set application/xml if XML. + :returns: An instance of this model + :raises DeserializationError: if something went wrong + :rtype: Self + """ + deserializer = Deserializer(cls._infer_class_models()) + deserializer.key_extractors = ( # type: ignore + [ # type: ignore + attribute_key_case_insensitive_extractor, + rest_key_case_insensitive_extractor, + last_rest_key_case_insensitive_extractor, + ] + if key_extractors is None + else key_extractors + ) + return deserializer(cls.__name__, data, content_type=content_type) # type: ignore + + @classmethod + def _flatten_subtype(cls, key, objects): + if "_subtype_map" not in cls.__dict__: + return {} + result = dict(cls._subtype_map[key]) + for valuetype in cls._subtype_map[key].values(): + result.update(objects[valuetype]._flatten_subtype(key, objects)) # pylint: disable=protected-access + return result + + @classmethod + def _classify(cls, response, objects): + """Check the class _subtype_map for any child classes. + We want to ignore any inherited _subtype_maps. + + :param dict response: The initial data + :param dict objects: The class objects + :returns: The class to be used + :rtype: class + """ + for subtype_key in cls.__dict__.get("_subtype_map", {}).keys(): + subtype_value = None + + if not isinstance(response, ET.Element): + rest_api_response_key = cls._get_rest_key_parts(subtype_key)[-1] + subtype_value = response.get(rest_api_response_key, None) or response.get(subtype_key, None) + else: + subtype_value = xml_key_extractor(subtype_key, cls._attribute_map[subtype_key], response) + if subtype_value: + # Try to match base class. Can be class name only + # (bug to fix in Autorest to support x-ms-discriminator-name) + if cls.__name__ == subtype_value: + return cls + flatten_mapping_type = cls._flatten_subtype(subtype_key, objects) + try: + return objects[flatten_mapping_type[subtype_value]] # type: ignore + except KeyError: + _LOGGER.warning( + "Subtype value %s has no mapping, use base class %s.", + subtype_value, + cls.__name__, + ) + break + else: + _LOGGER.warning("Discriminator %s is absent or null, use base class %s.", subtype_key, cls.__name__) + break + return cls + + @classmethod + def _get_rest_key_parts(cls, attr_key): + """Get the RestAPI key of this attr, split it and decode part + :param str attr_key: Attribute key must be in attribute_map. + :returns: A list of RestAPI part + :rtype: list + """ + rest_split_key = _FLATTEN.split(cls._attribute_map[attr_key]["key"]) + return [_decode_attribute_map_key(key_part) for key_part in rest_split_key] + + +def _decode_attribute_map_key(key): + """This decode a key in an _attribute_map to the actual key we want to look at + inside the received data. + + :param str key: A key string from the generated code + :returns: The decoded key + :rtype: str + """ + return key.replace("\\.", ".") + + +class Serializer: # pylint: disable=too-many-public-methods + """Request object model serializer.""" + + basic_types = {str: "str", int: "int", bool: "bool", float: "float"} + + _xml_basic_types_serializers = {"bool": lambda x: str(x).lower()} + days = {0: "Mon", 1: "Tue", 2: "Wed", 3: "Thu", 4: "Fri", 5: "Sat", 6: "Sun"} + months = { + 1: "Jan", + 2: "Feb", + 3: "Mar", + 4: "Apr", + 5: "May", + 6: "Jun", + 7: "Jul", + 8: "Aug", + 9: "Sep", + 10: "Oct", + 11: "Nov", + 12: "Dec", + } + validation = { + "min_length": lambda x, y: len(x) < y, + "max_length": lambda x, y: len(x) > y, + "minimum": lambda x, y: x < y, + "maximum": lambda x, y: x > y, + "minimum_ex": lambda x, y: x <= y, + "maximum_ex": lambda x, y: x >= y, + "min_items": lambda x, y: len(x) < y, + "max_items": lambda x, y: len(x) > y, + "pattern": lambda x, y: not re.match(y, x, re.UNICODE), + "unique": lambda x, y: len(x) != len(set(x)), + "multiple": lambda x, y: x % y != 0, + } + + def __init__(self, classes: Optional[Mapping[str, type]] = None) -> None: + self.serialize_type = { + "iso-8601": Serializer.serialize_iso, + "rfc-1123": Serializer.serialize_rfc, + "unix-time": Serializer.serialize_unix, + "duration": Serializer.serialize_duration, + "date": Serializer.serialize_date, + "time": Serializer.serialize_time, + "decimal": Serializer.serialize_decimal, + "long": Serializer.serialize_long, + "bytearray": Serializer.serialize_bytearray, + "base64": Serializer.serialize_base64, + "object": self.serialize_object, + "[]": self.serialize_iter, + "{}": self.serialize_dict, + } + self.dependencies: Dict[str, type] = dict(classes) if classes else {} + self.key_transformer = full_restapi_key_transformer + self.client_side_validation = True + + def _serialize( # pylint: disable=too-many-nested-blocks, too-many-branches, too-many-statements, too-many-locals + self, target_obj, data_type=None, **kwargs + ): + """Serialize data into a string according to type. + + :param object target_obj: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str, dict + :raises SerializationError: if serialization fails. + :returns: The serialized data. + """ + key_transformer = kwargs.get("key_transformer", self.key_transformer) + keep_readonly = kwargs.get("keep_readonly", False) + if target_obj is None: + return None + + attr_name = None + class_name = target_obj.__class__.__name__ + + if data_type: + return self.serialize_data(target_obj, data_type, **kwargs) + + if not hasattr(target_obj, "_attribute_map"): + data_type = type(target_obj).__name__ + if data_type in self.basic_types.values(): + return self.serialize_data(target_obj, data_type, **kwargs) + + # Force "is_xml" kwargs if we detect a XML model + try: + is_xml_model_serialization = kwargs["is_xml"] + except KeyError: + is_xml_model_serialization = kwargs.setdefault("is_xml", target_obj.is_xml_model()) + + serialized = {} + if is_xml_model_serialization: + serialized = target_obj._create_xml_node() # pylint: disable=protected-access + try: + attributes = target_obj._attribute_map # pylint: disable=protected-access + for attr, attr_desc in attributes.items(): + attr_name = attr + if not keep_readonly and target_obj._validation.get( # pylint: disable=protected-access + attr_name, {} + ).get("readonly", False): + continue + + if attr_name == "additional_properties" and attr_desc["key"] == "": + if target_obj.additional_properties is not None: + serialized.update(target_obj.additional_properties) + continue + try: + + orig_attr = getattr(target_obj, attr) + if is_xml_model_serialization: + pass # Don't provide "transformer" for XML for now. Keep "orig_attr" + else: # JSON + keys, orig_attr = key_transformer(attr, attr_desc.copy(), orig_attr) + keys = keys if isinstance(keys, list) else [keys] + + kwargs["serialization_ctxt"] = attr_desc + new_attr = self.serialize_data(orig_attr, attr_desc["type"], **kwargs) + + if is_xml_model_serialization: + xml_desc = attr_desc.get("xml", {}) + xml_name = xml_desc.get("name", attr_desc["key"]) + xml_prefix = xml_desc.get("prefix", None) + xml_ns = xml_desc.get("ns", None) + if xml_desc.get("attr", False): + if xml_ns: + ET.register_namespace(xml_prefix, xml_ns) + xml_name = "{{{}}}{}".format(xml_ns, xml_name) + serialized.set(xml_name, new_attr) # type: ignore + continue + if xml_desc.get("text", False): + serialized.text = new_attr # type: ignore + continue + if isinstance(new_attr, list): + serialized.extend(new_attr) # type: ignore + elif isinstance(new_attr, ET.Element): + # If the down XML has no XML/Name, + # we MUST replace the tag with the local tag. But keeping the namespaces. + if "name" not in getattr(orig_attr, "_xml_map", {}): + splitted_tag = new_attr.tag.split("}") + if len(splitted_tag) == 2: # Namespace + new_attr.tag = "}".join([splitted_tag[0], xml_name]) + else: + new_attr.tag = xml_name + serialized.append(new_attr) # type: ignore + else: # That's a basic type + # Integrate namespace if necessary + local_node = _create_xml_node(xml_name, xml_prefix, xml_ns) + local_node.text = str(new_attr) + serialized.append(local_node) # type: ignore + else: # JSON + for k in reversed(keys): # type: ignore + new_attr = {k: new_attr} + + _new_attr = new_attr + _serialized = serialized + for k in keys: # type: ignore + if k not in _serialized: + _serialized.update(_new_attr) # type: ignore + _new_attr = _new_attr[k] # type: ignore + _serialized = _serialized[k] + except ValueError as err: + if isinstance(err, SerializationError): + raise + + except (AttributeError, KeyError, TypeError) as err: + msg = "Attribute {} in object {} cannot be serialized.\n{}".format(attr_name, class_name, str(target_obj)) + raise SerializationError(msg) from err + return serialized + + def body(self, data, data_type, **kwargs): + """Serialize data intended for a request body. + + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: dict + :raises SerializationError: if serialization fails. + :raises ValueError: if data is None + :returns: The serialized request body + """ + + # Just in case this is a dict + internal_data_type_str = data_type.strip("[]{}") + internal_data_type = self.dependencies.get(internal_data_type_str, None) + try: + is_xml_model_serialization = kwargs["is_xml"] + except KeyError: + if internal_data_type and issubclass(internal_data_type, Model): + is_xml_model_serialization = kwargs.setdefault("is_xml", internal_data_type.is_xml_model()) + else: + is_xml_model_serialization = False + if internal_data_type and not isinstance(internal_data_type, Enum): + try: + deserializer = Deserializer(self.dependencies) + # Since it's on serialization, it's almost sure that format is not JSON REST + # We're not able to deal with additional properties for now. + deserializer.additional_properties_detection = False + if is_xml_model_serialization: + deserializer.key_extractors = [ # type: ignore + attribute_key_case_insensitive_extractor, + ] + else: + deserializer.key_extractors = [ + rest_key_case_insensitive_extractor, + attribute_key_case_insensitive_extractor, + last_rest_key_case_insensitive_extractor, + ] + data = deserializer._deserialize(data_type, data) # pylint: disable=protected-access + except DeserializationError as err: + raise SerializationError("Unable to build a model: " + str(err)) from err + + return self._serialize(data, data_type, **kwargs) + + def url(self, name, data, data_type, **kwargs): + """Serialize data intended for a URL path. + + :param str name: The name of the URL path parameter. + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str + :returns: The serialized URL path + :raises TypeError: if serialization fails. + :raises ValueError: if data is None + """ + try: + output = self.serialize_data(data, data_type, **kwargs) + if data_type == "bool": + output = json.dumps(output) + + if kwargs.get("skip_quote") is True: + output = str(output) + output = output.replace("{", quote("{")).replace("}", quote("}")) + else: + output = quote(str(output), safe="") + except SerializationError as exc: + raise TypeError("{} must be type {}.".format(name, data_type)) from exc + return output + + def query(self, name, data, data_type, **kwargs): + """Serialize data intended for a URL query. + + :param str name: The name of the query parameter. + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str, list + :raises TypeError: if serialization fails. + :raises ValueError: if data is None + :returns: The serialized query parameter + """ + try: + # Treat the list aside, since we don't want to encode the div separator + if data_type.startswith("["): + internal_data_type = data_type[1:-1] + do_quote = not kwargs.get("skip_quote", False) + return self.serialize_iter(data, internal_data_type, do_quote=do_quote, **kwargs) + + # Not a list, regular serialization + output = self.serialize_data(data, data_type, **kwargs) + if data_type == "bool": + output = json.dumps(output) + if kwargs.get("skip_quote") is True: + output = str(output) + else: + output = quote(str(output), safe="") + except SerializationError as exc: + raise TypeError("{} must be type {}.".format(name, data_type)) from exc + return str(output) + + def header(self, name, data, data_type, **kwargs): + """Serialize data intended for a request header. + + :param str name: The name of the header. + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str + :raises TypeError: if serialization fails. + :raises ValueError: if data is None + :returns: The serialized header + """ + try: + if data_type in ["[str]"]: + data = ["" if d is None else d for d in data] + + output = self.serialize_data(data, data_type, **kwargs) + if data_type == "bool": + output = json.dumps(output) + except SerializationError as exc: + raise TypeError("{} must be type {}.".format(name, data_type)) from exc + return str(output) + + def serialize_data(self, data, data_type, **kwargs): + """Serialize generic data according to supplied data type. + + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :raises AttributeError: if required data is None. + :raises ValueError: if data is None + :raises SerializationError: if serialization fails. + :returns: The serialized data. + :rtype: str, int, float, bool, dict, list + """ + if data is None: + raise ValueError("No value for given attribute") + + try: + if data is CoreNull: + return None + if data_type in self.basic_types.values(): + return self.serialize_basic(data, data_type, **kwargs) + + if data_type in self.serialize_type: + return self.serialize_type[data_type](data, **kwargs) + + # If dependencies is empty, try with current data class + # It has to be a subclass of Enum anyway + enum_type = self.dependencies.get(data_type, data.__class__) + if issubclass(enum_type, Enum): + return Serializer.serialize_enum(data, enum_obj=enum_type) + + iter_type = data_type[0] + data_type[-1] + if iter_type in self.serialize_type: + return self.serialize_type[iter_type](data, data_type[1:-1], **kwargs) + + except (ValueError, TypeError) as err: + msg = "Unable to serialize value: {!r} as type: {!r}." + raise SerializationError(msg.format(data, data_type)) from err + return self._serialize(data, **kwargs) + + @classmethod + def _get_custom_serializers(cls, data_type, **kwargs): # pylint: disable=inconsistent-return-statements + custom_serializer = kwargs.get("basic_types_serializers", {}).get(data_type) + if custom_serializer: + return custom_serializer + if kwargs.get("is_xml", False): + return cls._xml_basic_types_serializers.get(data_type) + + @classmethod + def serialize_basic(cls, data, data_type, **kwargs): + """Serialize basic builting data type. + Serializes objects to str, int, float or bool. + + Possible kwargs: + - basic_types_serializers dict[str, callable] : If set, use the callable as serializer + - is_xml bool : If set, use xml_basic_types_serializers + + :param obj data: Object to be serialized. + :param str data_type: Type of object in the iterable. + :rtype: str, int, float, bool + :return: serialized object + """ + custom_serializer = cls._get_custom_serializers(data_type, **kwargs) + if custom_serializer: + return custom_serializer(data) + if data_type == "str": + return cls.serialize_unicode(data) + return eval(data_type)(data) # nosec # pylint: disable=eval-used + + @classmethod + def serialize_unicode(cls, data): + """Special handling for serializing unicode strings in Py2. + Encode to UTF-8 if unicode, otherwise handle as a str. + + :param str data: Object to be serialized. + :rtype: str + :return: serialized object + """ + try: # If I received an enum, return its value + return data.value + except AttributeError: + pass + + try: + if isinstance(data, unicode): # type: ignore + # Don't change it, JSON and XML ElementTree are totally able + # to serialize correctly u'' strings + return data + except NameError: + return str(data) + return str(data) + + def serialize_iter(self, data, iter_type, div=None, **kwargs): + """Serialize iterable. + + Supported kwargs: + - serialization_ctxt dict : The current entry of _attribute_map, or same format. + serialization_ctxt['type'] should be same as data_type. + - is_xml bool : If set, serialize as XML + + :param list data: Object to be serialized. + :param str iter_type: Type of object in the iterable. + :param str div: If set, this str will be used to combine the elements + in the iterable into a combined string. Default is 'None'. + Defaults to False. + :rtype: list, str + :return: serialized iterable + """ + if isinstance(data, str): + raise SerializationError("Refuse str type as a valid iter type.") + + serialization_ctxt = kwargs.get("serialization_ctxt", {}) + is_xml = kwargs.get("is_xml", False) + + serialized = [] + for d in data: + try: + serialized.append(self.serialize_data(d, iter_type, **kwargs)) + except ValueError as err: + if isinstance(err, SerializationError): + raise + serialized.append(None) + + if kwargs.get("do_quote", False): + serialized = ["" if s is None else quote(str(s), safe="") for s in serialized] + + if div: + serialized = ["" if s is None else str(s) for s in serialized] + serialized = div.join(serialized) + + if "xml" in serialization_ctxt or is_xml: + # XML serialization is more complicated + xml_desc = serialization_ctxt.get("xml", {}) + xml_name = xml_desc.get("name") + if not xml_name: + xml_name = serialization_ctxt["key"] + + # Create a wrap node if necessary (use the fact that Element and list have "append") + is_wrapped = xml_desc.get("wrapped", False) + node_name = xml_desc.get("itemsName", xml_name) + if is_wrapped: + final_result = _create_xml_node(xml_name, xml_desc.get("prefix", None), xml_desc.get("ns", None)) + else: + final_result = [] + # All list elements to "local_node" + for el in serialized: + if isinstance(el, ET.Element): + el_node = el + else: + el_node = _create_xml_node(node_name, xml_desc.get("prefix", None), xml_desc.get("ns", None)) + if el is not None: # Otherwise it writes "None" :-p + el_node.text = str(el) + final_result.append(el_node) + return final_result + return serialized + + def serialize_dict(self, attr, dict_type, **kwargs): + """Serialize a dictionary of objects. + + :param dict attr: Object to be serialized. + :param str dict_type: Type of object in the dictionary. + :rtype: dict + :return: serialized dictionary + """ + serialization_ctxt = kwargs.get("serialization_ctxt", {}) + serialized = {} + for key, value in attr.items(): + try: + serialized[self.serialize_unicode(key)] = self.serialize_data(value, dict_type, **kwargs) + except ValueError as err: + if isinstance(err, SerializationError): + raise + serialized[self.serialize_unicode(key)] = None + + if "xml" in serialization_ctxt: + # XML serialization is more complicated + xml_desc = serialization_ctxt["xml"] + xml_name = xml_desc["name"] + + final_result = _create_xml_node(xml_name, xml_desc.get("prefix", None), xml_desc.get("ns", None)) + for key, value in serialized.items(): + ET.SubElement(final_result, key).text = value + return final_result + + return serialized + + def serialize_object(self, attr, **kwargs): # pylint: disable=too-many-return-statements + """Serialize a generic object. + This will be handled as a dictionary. If object passed in is not + a basic type (str, int, float, dict, list) it will simply be + cast to str. + + :param dict attr: Object to be serialized. + :rtype: dict or str + :return: serialized object + """ + if attr is None: + return None + if isinstance(attr, ET.Element): + return attr + obj_type = type(attr) + if obj_type in self.basic_types: + return self.serialize_basic(attr, self.basic_types[obj_type], **kwargs) + if obj_type is _long_type: + return self.serialize_long(attr) + if obj_type is str: + return self.serialize_unicode(attr) + if obj_type is datetime.datetime: + return self.serialize_iso(attr) + if obj_type is datetime.date: + return self.serialize_date(attr) + if obj_type is datetime.time: + return self.serialize_time(attr) + if obj_type is datetime.timedelta: + return self.serialize_duration(attr) + if obj_type is decimal.Decimal: + return self.serialize_decimal(attr) + + # If it's a model or I know this dependency, serialize as a Model + if obj_type in self.dependencies.values() or isinstance(attr, Model): + return self._serialize(attr) + + if obj_type == dict: + serialized = {} + for key, value in attr.items(): + try: + serialized[self.serialize_unicode(key)] = self.serialize_object(value, **kwargs) + except ValueError: + serialized[self.serialize_unicode(key)] = None + return serialized + + if obj_type == list: + serialized = [] + for obj in attr: + try: + serialized.append(self.serialize_object(obj, **kwargs)) + except ValueError: + pass + return serialized + return str(attr) + + @staticmethod + def serialize_enum(attr, enum_obj=None): + try: + result = attr.value + except AttributeError: + result = attr + try: + enum_obj(result) # type: ignore + return result + except ValueError as exc: + for enum_value in enum_obj: # type: ignore + if enum_value.value.lower() == str(attr).lower(): + return enum_value.value + error = "{!r} is not valid value for enum {!r}" + raise SerializationError(error.format(attr, enum_obj)) from exc + + @staticmethod + def serialize_bytearray(attr, **kwargs): # pylint: disable=unused-argument + """Serialize bytearray into base-64 string. + + :param str attr: Object to be serialized. + :rtype: str + :return: serialized base64 + """ + return b64encode(attr).decode() + + @staticmethod + def serialize_base64(attr, **kwargs): # pylint: disable=unused-argument + """Serialize str into base-64 string. + + :param str attr: Object to be serialized. + :rtype: str + :return: serialized base64 + """ + encoded = b64encode(attr).decode("ascii") + return encoded.strip("=").replace("+", "-").replace("/", "_") + + @staticmethod + def serialize_decimal(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Decimal object to float. + + :param decimal attr: Object to be serialized. + :rtype: float + :return: serialized decimal + """ + return float(attr) + + @staticmethod + def serialize_long(attr, **kwargs): # pylint: disable=unused-argument + """Serialize long (Py2) or int (Py3). + + :param int attr: Object to be serialized. + :rtype: int/long + :return: serialized long + """ + return _long_type(attr) + + @staticmethod + def serialize_date(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Date object into ISO-8601 formatted string. + + :param Date attr: Object to be serialized. + :rtype: str + :return: serialized date + """ + if isinstance(attr, str): + attr = isodate.parse_date(attr) + t = "{:04}-{:02}-{:02}".format(attr.year, attr.month, attr.day) + return t + + @staticmethod + def serialize_time(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Time object into ISO-8601 formatted string. + + :param datetime.time attr: Object to be serialized. + :rtype: str + :return: serialized time + """ + if isinstance(attr, str): + attr = isodate.parse_time(attr) + t = "{:02}:{:02}:{:02}".format(attr.hour, attr.minute, attr.second) + if attr.microsecond: + t += ".{:02}".format(attr.microsecond) + return t + + @staticmethod + def serialize_duration(attr, **kwargs): # pylint: disable=unused-argument + """Serialize TimeDelta object into ISO-8601 formatted string. + + :param TimeDelta attr: Object to be serialized. + :rtype: str + :return: serialized duration + """ + if isinstance(attr, str): + attr = isodate.parse_duration(attr) + return isodate.duration_isoformat(attr) + + @staticmethod + def serialize_rfc(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Datetime object into RFC-1123 formatted string. + + :param Datetime attr: Object to be serialized. + :rtype: str + :raises TypeError: if format invalid. + :return: serialized rfc + """ + try: + if not attr.tzinfo: + _LOGGER.warning("Datetime with no tzinfo will be considered UTC.") + utc = attr.utctimetuple() + except AttributeError as exc: + raise TypeError("RFC1123 object must be valid Datetime object.") from exc + + return "{}, {:02} {} {:04} {:02}:{:02}:{:02} GMT".format( + Serializer.days[utc.tm_wday], + utc.tm_mday, + Serializer.months[utc.tm_mon], + utc.tm_year, + utc.tm_hour, + utc.tm_min, + utc.tm_sec, + ) + + @staticmethod + def serialize_iso(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Datetime object into ISO-8601 formatted string. + + :param Datetime attr: Object to be serialized. + :rtype: str + :raises SerializationError: if format invalid. + :return: serialized iso + """ + if isinstance(attr, str): + attr = isodate.parse_datetime(attr) + try: + if not attr.tzinfo: + _LOGGER.warning("Datetime with no tzinfo will be considered UTC.") + utc = attr.utctimetuple() + if utc.tm_year > 9999 or utc.tm_year < 1: + raise OverflowError("Hit max or min date") + + microseconds = str(attr.microsecond).rjust(6, "0").rstrip("0").ljust(3, "0") + if microseconds: + microseconds = "." + microseconds + date = "{:04}-{:02}-{:02}T{:02}:{:02}:{:02}".format( + utc.tm_year, utc.tm_mon, utc.tm_mday, utc.tm_hour, utc.tm_min, utc.tm_sec + ) + return date + microseconds + "Z" + except (ValueError, OverflowError) as err: + msg = "Unable to serialize datetime object." + raise SerializationError(msg) from err + except AttributeError as err: + msg = "ISO-8601 object must be valid Datetime object." + raise TypeError(msg) from err + + @staticmethod + def serialize_unix(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Datetime object into IntTime format. + This is represented as seconds. + + :param Datetime attr: Object to be serialized. + :rtype: int + :raises SerializationError: if format invalid + :return: serialied unix + """ + if isinstance(attr, int): + return attr + try: + if not attr.tzinfo: + _LOGGER.warning("Datetime with no tzinfo will be considered UTC.") + return int(calendar.timegm(attr.utctimetuple())) + except AttributeError as exc: + raise TypeError("Unix time object must be valid Datetime object.") from exc + + +def rest_key_extractor(attr, attr_desc, data): # pylint: disable=unused-argument + key = attr_desc["key"] + working_data = data + + while "." in key: + # Need the cast, as for some reasons "split" is typed as list[str | Any] + dict_keys = cast(List[str], _FLATTEN.split(key)) + if len(dict_keys) == 1: + key = _decode_attribute_map_key(dict_keys[0]) + break + working_key = _decode_attribute_map_key(dict_keys[0]) + working_data = working_data.get(working_key, data) + if working_data is None: + # If at any point while following flatten JSON path see None, it means + # that all properties under are None as well + return None + key = ".".join(dict_keys[1:]) + + return working_data.get(key) + + +def rest_key_case_insensitive_extractor( # pylint: disable=unused-argument, inconsistent-return-statements + attr, attr_desc, data +): + key = attr_desc["key"] + working_data = data + + while "." in key: + dict_keys = _FLATTEN.split(key) + if len(dict_keys) == 1: + key = _decode_attribute_map_key(dict_keys[0]) + break + working_key = _decode_attribute_map_key(dict_keys[0]) + working_data = attribute_key_case_insensitive_extractor(working_key, None, working_data) + if working_data is None: + # If at any point while following flatten JSON path see None, it means + # that all properties under are None as well + return None + key = ".".join(dict_keys[1:]) + + if working_data: + return attribute_key_case_insensitive_extractor(key, None, working_data) + + +def last_rest_key_extractor(attr, attr_desc, data): # pylint: disable=unused-argument + """Extract the attribute in "data" based on the last part of the JSON path key. + + :param str attr: The attribute to extract + :param dict attr_desc: The attribute description + :param dict data: The data to extract from + :rtype: object + :returns: The extracted attribute + """ + key = attr_desc["key"] + dict_keys = _FLATTEN.split(key) + return attribute_key_extractor(dict_keys[-1], None, data) + + +def last_rest_key_case_insensitive_extractor(attr, attr_desc, data): # pylint: disable=unused-argument + """Extract the attribute in "data" based on the last part of the JSON path key. + + This is the case insensitive version of "last_rest_key_extractor" + :param str attr: The attribute to extract + :param dict attr_desc: The attribute description + :param dict data: The data to extract from + :rtype: object + :returns: The extracted attribute + """ + key = attr_desc["key"] + dict_keys = _FLATTEN.split(key) + return attribute_key_case_insensitive_extractor(dict_keys[-1], None, data) + + +def attribute_key_extractor(attr, _, data): + return data.get(attr) + + +def attribute_key_case_insensitive_extractor(attr, _, data): + found_key = None + lower_attr = attr.lower() + for key in data: + if lower_attr == key.lower(): + found_key = key + break + + return data.get(found_key) + + +def _extract_name_from_internal_type(internal_type): + """Given an internal type XML description, extract correct XML name with namespace. + + :param dict internal_type: An model type + :rtype: tuple + :returns: A tuple XML name + namespace dict + """ + internal_type_xml_map = getattr(internal_type, "_xml_map", {}) + xml_name = internal_type_xml_map.get("name", internal_type.__name__) + xml_ns = internal_type_xml_map.get("ns", None) + if xml_ns: + xml_name = "{{{}}}{}".format(xml_ns, xml_name) + return xml_name + + +def xml_key_extractor(attr, attr_desc, data): # pylint: disable=unused-argument,too-many-return-statements + if isinstance(data, dict): + return None + + # Test if this model is XML ready first + if not isinstance(data, ET.Element): + return None + + xml_desc = attr_desc.get("xml", {}) + xml_name = xml_desc.get("name", attr_desc["key"]) + + # Look for a children + is_iter_type = attr_desc["type"].startswith("[") + is_wrapped = xml_desc.get("wrapped", False) + internal_type = attr_desc.get("internalType", None) + internal_type_xml_map = getattr(internal_type, "_xml_map", {}) + + # Integrate namespace if necessary + xml_ns = xml_desc.get("ns", internal_type_xml_map.get("ns", None)) + if xml_ns: + xml_name = "{{{}}}{}".format(xml_ns, xml_name) + + # If it's an attribute, that's simple + if xml_desc.get("attr", False): + return data.get(xml_name) + + # If it's x-ms-text, that's simple too + if xml_desc.get("text", False): + return data.text + + # Scenario where I take the local name: + # - Wrapped node + # - Internal type is an enum (considered basic types) + # - Internal type has no XML/Name node + if is_wrapped or (internal_type and (issubclass(internal_type, Enum) or "name" not in internal_type_xml_map)): + children = data.findall(xml_name) + # If internal type has a local name and it's not a list, I use that name + elif not is_iter_type and internal_type and "name" in internal_type_xml_map: + xml_name = _extract_name_from_internal_type(internal_type) + children = data.findall(xml_name) + # That's an array + else: + if internal_type: # Complex type, ignore itemsName and use the complex type name + items_name = _extract_name_from_internal_type(internal_type) + else: + items_name = xml_desc.get("itemsName", xml_name) + children = data.findall(items_name) + + if len(children) == 0: + if is_iter_type: + if is_wrapped: + return None # is_wrapped no node, we want None + return [] # not wrapped, assume empty list + return None # Assume it's not there, maybe an optional node. + + # If is_iter_type and not wrapped, return all found children + if is_iter_type: + if not is_wrapped: + return children + # Iter and wrapped, should have found one node only (the wrap one) + if len(children) != 1: + raise DeserializationError( + "Tried to deserialize an array not wrapped, and found several nodes '{}'. Maybe you should declare this array as wrapped?".format( + xml_name + ) + ) + return list(children[0]) # Might be empty list and that's ok. + + # Here it's not a itertype, we should have found one element only or empty + if len(children) > 1: + raise DeserializationError("Find several XML '{}' where it was not expected".format(xml_name)) + return children[0] + + +class Deserializer: + """Response object model deserializer. + + :param dict classes: Class type dictionary for deserializing complex types. + :ivar list key_extractors: Ordered list of extractors to be used by this deserializer. + """ + + basic_types = {str: "str", int: "int", bool: "bool", float: "float"} + + valid_date = re.compile(r"\d{4}[-]\d{2}[-]\d{2}T\d{2}:\d{2}:\d{2}\.?\d*Z?[-+]?[\d{2}]?:?[\d{2}]?") + + def __init__(self, classes: Optional[Mapping[str, type]] = None) -> None: + self.deserialize_type = { + "iso-8601": Deserializer.deserialize_iso, + "rfc-1123": Deserializer.deserialize_rfc, + "unix-time": Deserializer.deserialize_unix, + "duration": Deserializer.deserialize_duration, + "date": Deserializer.deserialize_date, + "time": Deserializer.deserialize_time, + "decimal": Deserializer.deserialize_decimal, + "long": Deserializer.deserialize_long, + "bytearray": Deserializer.deserialize_bytearray, + "base64": Deserializer.deserialize_base64, + "object": self.deserialize_object, + "[]": self.deserialize_iter, + "{}": self.deserialize_dict, + } + self.deserialize_expected_types = { + "duration": (isodate.Duration, datetime.timedelta), + "iso-8601": (datetime.datetime), + } + self.dependencies: Dict[str, type] = dict(classes) if classes else {} + self.key_extractors = [rest_key_extractor, xml_key_extractor] + # Additional properties only works if the "rest_key_extractor" is used to + # extract the keys. Making it to work whatever the key extractor is too much + # complicated, with no real scenario for now. + # So adding a flag to disable additional properties detection. This flag should be + # used if your expect the deserialization to NOT come from a JSON REST syntax. + # Otherwise, result are unexpected + self.additional_properties_detection = True + + def __call__(self, target_obj, response_data, content_type=None): + """Call the deserializer to process a REST response. + + :param str target_obj: Target data type to deserialize to. + :param requests.Response response_data: REST response object. + :param str content_type: Swagger "produces" if available. + :raises DeserializationError: if deserialization fails. + :return: Deserialized object. + :rtype: object + """ + data = self._unpack_content(response_data, content_type) + return self._deserialize(target_obj, data) + + def _deserialize(self, target_obj, data): # pylint: disable=inconsistent-return-statements + """Call the deserializer on a model. + + Data needs to be already deserialized as JSON or XML ElementTree + + :param str target_obj: Target data type to deserialize to. + :param object data: Object to deserialize. + :raises DeserializationError: if deserialization fails. + :return: Deserialized object. + :rtype: object + """ + # This is already a model, go recursive just in case + if hasattr(data, "_attribute_map"): + constants = [name for name, config in getattr(data, "_validation", {}).items() if config.get("constant")] + try: + for attr, mapconfig in data._attribute_map.items(): # pylint: disable=protected-access + if attr in constants: + continue + value = getattr(data, attr) + if value is None: + continue + local_type = mapconfig["type"] + internal_data_type = local_type.strip("[]{}") + if internal_data_type not in self.dependencies or isinstance(internal_data_type, Enum): + continue + setattr(data, attr, self._deserialize(local_type, value)) + return data + except AttributeError: + return + + response, class_name = self._classify_target(target_obj, data) + + if isinstance(response, str): + return self.deserialize_data(data, response) + if isinstance(response, type) and issubclass(response, Enum): + return self.deserialize_enum(data, response) + + if data is None or data is CoreNull: + return data + try: + attributes = response._attribute_map # type: ignore # pylint: disable=protected-access + d_attrs = {} + for attr, attr_desc in attributes.items(): + # Check empty string. If it's not empty, someone has a real "additionalProperties"... + if attr == "additional_properties" and attr_desc["key"] == "": + continue + raw_value = None + # Enhance attr_desc with some dynamic data + attr_desc = attr_desc.copy() # Do a copy, do not change the real one + internal_data_type = attr_desc["type"].strip("[]{}") + if internal_data_type in self.dependencies: + attr_desc["internalType"] = self.dependencies[internal_data_type] + + for key_extractor in self.key_extractors: + found_value = key_extractor(attr, attr_desc, data) + if found_value is not None: + if raw_value is not None and raw_value != found_value: + msg = ( + "Ignoring extracted value '%s' from %s for key '%s'" + " (duplicate extraction, follow extractors order)" + ) + _LOGGER.warning(msg, found_value, key_extractor, attr) + continue + raw_value = found_value + + value = self.deserialize_data(raw_value, attr_desc["type"]) + d_attrs[attr] = value + except (AttributeError, TypeError, KeyError) as err: + msg = "Unable to deserialize to object: " + class_name # type: ignore + raise DeserializationError(msg) from err + additional_properties = self._build_additional_properties(attributes, data) + return self._instantiate_model(response, d_attrs, additional_properties) + + def _build_additional_properties(self, attribute_map, data): + if not self.additional_properties_detection: + return None + if "additional_properties" in attribute_map and attribute_map.get("additional_properties", {}).get("key") != "": + # Check empty string. If it's not empty, someone has a real "additionalProperties" + return None + if isinstance(data, ET.Element): + data = {el.tag: el.text for el in data} + + known_keys = { + _decode_attribute_map_key(_FLATTEN.split(desc["key"])[0]) + for desc in attribute_map.values() + if desc["key"] != "" + } + present_keys = set(data.keys()) + missing_keys = present_keys - known_keys + return {key: data[key] for key in missing_keys} + + def _classify_target(self, target, data): + """Check to see whether the deserialization target object can + be classified into a subclass. + Once classification has been determined, initialize object. + + :param str target: The target object type to deserialize to. + :param str/dict data: The response data to deserialize. + :return: The classified target object and its class name. + :rtype: tuple + """ + if target is None: + return None, None + + if isinstance(target, str): + try: + target = self.dependencies[target] + except KeyError: + return target, target + + try: + target = target._classify(data, self.dependencies) # type: ignore # pylint: disable=protected-access + except AttributeError: + pass # Target is not a Model, no classify + return target, target.__class__.__name__ # type: ignore + + def failsafe_deserialize(self, target_obj, data, content_type=None): + """Ignores any errors encountered in deserialization, + and falls back to not deserializing the object. Recommended + for use in error deserialization, as we want to return the + HttpResponseError to users, and not have them deal with + a deserialization error. + + :param str target_obj: The target object type to deserialize to. + :param str/dict data: The response data to deserialize. + :param str content_type: Swagger "produces" if available. + :return: Deserialized object. + :rtype: object + """ + try: + return self(target_obj, data, content_type=content_type) + except: # pylint: disable=bare-except + _LOGGER.debug( + "Ran into a deserialization error. Ignoring since this is failsafe deserialization", exc_info=True + ) + return None + + @staticmethod + def _unpack_content(raw_data, content_type=None): + """Extract the correct structure for deserialization. + + If raw_data is a PipelineResponse, try to extract the result of RawDeserializer. + if we can't, raise. Your Pipeline should have a RawDeserializer. + + If not a pipeline response and raw_data is bytes or string, use content-type + to decode it. If no content-type, try JSON. + + If raw_data is something else, bypass all logic and return it directly. + + :param obj raw_data: Data to be processed. + :param str content_type: How to parse if raw_data is a string/bytes. + :raises JSONDecodeError: If JSON is requested and parsing is impossible. + :raises UnicodeDecodeError: If bytes is not UTF8 + :rtype: object + :return: Unpacked content. + """ + # Assume this is enough to detect a Pipeline Response without importing it + context = getattr(raw_data, "context", {}) + if context: + if RawDeserializer.CONTEXT_NAME in context: + return context[RawDeserializer.CONTEXT_NAME] + raise ValueError("This pipeline didn't have the RawDeserializer policy; can't deserialize") + + # Assume this is enough to recognize universal_http.ClientResponse without importing it + if hasattr(raw_data, "body"): + return RawDeserializer.deserialize_from_http_generics(raw_data.text(), raw_data.headers) + + # Assume this enough to recognize requests.Response without importing it. + if hasattr(raw_data, "_content_consumed"): + return RawDeserializer.deserialize_from_http_generics(raw_data.text, raw_data.headers) + + if isinstance(raw_data, (str, bytes)) or hasattr(raw_data, "read"): + return RawDeserializer.deserialize_from_text(raw_data, content_type) # type: ignore + return raw_data + + def _instantiate_model(self, response, attrs, additional_properties=None): + """Instantiate a response model passing in deserialized args. + + :param Response response: The response model class. + :param dict attrs: The deserialized response attributes. + :param dict additional_properties: Additional properties to be set. + :rtype: Response + :return: The instantiated response model. + """ + if callable(response): + subtype = getattr(response, "_subtype_map", {}) + try: + readonly = [ + k + for k, v in response._validation.items() # pylint: disable=protected-access # type: ignore + if v.get("readonly") + ] + const = [ + k + for k, v in response._validation.items() # pylint: disable=protected-access # type: ignore + if v.get("constant") + ] + kwargs = {k: v for k, v in attrs.items() if k not in subtype and k not in readonly + const} + response_obj = response(**kwargs) + for attr in readonly: + setattr(response_obj, attr, attrs.get(attr)) + if additional_properties: + response_obj.additional_properties = additional_properties # type: ignore + return response_obj + except TypeError as err: + msg = "Unable to deserialize {} into model {}. ".format(kwargs, response) # type: ignore + raise DeserializationError(msg + str(err)) from err + else: + try: + for attr, value in attrs.items(): + setattr(response, attr, value) + return response + except Exception as exp: + msg = "Unable to populate response model. " + msg += "Type: {}, Error: {}".format(type(response), exp) + raise DeserializationError(msg) from exp + + def deserialize_data(self, data, data_type): # pylint: disable=too-many-return-statements + """Process data for deserialization according to data type. + + :param str data: The response string to be deserialized. + :param str data_type: The type to deserialize to. + :raises DeserializationError: if deserialization fails. + :return: Deserialized object. + :rtype: object + """ + if data is None: + return data + + try: + if not data_type: + return data + if data_type in self.basic_types.values(): + return self.deserialize_basic(data, data_type) + if data_type in self.deserialize_type: + if isinstance(data, self.deserialize_expected_types.get(data_type, tuple())): + return data + + is_a_text_parsing_type = lambda x: x not in [ # pylint: disable=unnecessary-lambda-assignment + "object", + "[]", + r"{}", + ] + if isinstance(data, ET.Element) and is_a_text_parsing_type(data_type) and not data.text: + return None + data_val = self.deserialize_type[data_type](data) + return data_val + + iter_type = data_type[0] + data_type[-1] + if iter_type in self.deserialize_type: + return self.deserialize_type[iter_type](data, data_type[1:-1]) + + obj_type = self.dependencies[data_type] + if issubclass(obj_type, Enum): + if isinstance(data, ET.Element): + data = data.text + return self.deserialize_enum(data, obj_type) + + except (ValueError, TypeError, AttributeError) as err: + msg = "Unable to deserialize response data." + msg += " Data: {}, {}".format(data, data_type) + raise DeserializationError(msg) from err + return self._deserialize(obj_type, data) + + def deserialize_iter(self, attr, iter_type): + """Deserialize an iterable. + + :param list attr: Iterable to be deserialized. + :param str iter_type: The type of object in the iterable. + :return: Deserialized iterable. + :rtype: list + """ + if attr is None: + return None + if isinstance(attr, ET.Element): # If I receive an element here, get the children + attr = list(attr) + if not isinstance(attr, (list, set)): + raise DeserializationError("Cannot deserialize as [{}] an object of type {}".format(iter_type, type(attr))) + return [self.deserialize_data(a, iter_type) for a in attr] + + def deserialize_dict(self, attr, dict_type): + """Deserialize a dictionary. + + :param dict/list attr: Dictionary to be deserialized. Also accepts + a list of key, value pairs. + :param str dict_type: The object type of the items in the dictionary. + :return: Deserialized dictionary. + :rtype: dict + """ + if isinstance(attr, list): + return {x["key"]: self.deserialize_data(x["value"], dict_type) for x in attr} + + if isinstance(attr, ET.Element): + # Transform value into {"Key": "value"} + attr = {el.tag: el.text for el in attr} + return {k: self.deserialize_data(v, dict_type) for k, v in attr.items()} + + def deserialize_object(self, attr, **kwargs): # pylint: disable=too-many-return-statements + """Deserialize a generic object. + This will be handled as a dictionary. + + :param dict attr: Dictionary to be deserialized. + :return: Deserialized object. + :rtype: dict + :raises TypeError: if non-builtin datatype encountered. + """ + if attr is None: + return None + if isinstance(attr, ET.Element): + # Do no recurse on XML, just return the tree as-is + return attr + if isinstance(attr, str): + return self.deserialize_basic(attr, "str") + obj_type = type(attr) + if obj_type in self.basic_types: + return self.deserialize_basic(attr, self.basic_types[obj_type]) + if obj_type is _long_type: + return self.deserialize_long(attr) + + if obj_type == dict: + deserialized = {} + for key, value in attr.items(): + try: + deserialized[key] = self.deserialize_object(value, **kwargs) + except ValueError: + deserialized[key] = None + return deserialized + + if obj_type == list: + deserialized = [] + for obj in attr: + try: + deserialized.append(self.deserialize_object(obj, **kwargs)) + except ValueError: + pass + return deserialized + + error = "Cannot deserialize generic object with type: " + raise TypeError(error + str(obj_type)) + + def deserialize_basic(self, attr, data_type): # pylint: disable=too-many-return-statements + """Deserialize basic builtin data type from string. + Will attempt to convert to str, int, float and bool. + This function will also accept '1', '0', 'true' and 'false' as + valid bool values. + + :param str attr: response string to be deserialized. + :param str data_type: deserialization data type. + :return: Deserialized basic type. + :rtype: str, int, float or bool + :raises TypeError: if string format is not valid. + """ + # If we're here, data is supposed to be a basic type. + # If it's still an XML node, take the text + if isinstance(attr, ET.Element): + attr = attr.text + if not attr: + if data_type == "str": + # None or '', node is empty string. + return "" + # None or '', node with a strong type is None. + # Don't try to model "empty bool" or "empty int" + return None + + if data_type == "bool": + if attr in [True, False, 1, 0]: + return bool(attr) + if isinstance(attr, str): + if attr.lower() in ["true", "1"]: + return True + if attr.lower() in ["false", "0"]: + return False + raise TypeError("Invalid boolean value: {}".format(attr)) + + if data_type == "str": + return self.deserialize_unicode(attr) + return eval(data_type)(attr) # nosec # pylint: disable=eval-used + + @staticmethod + def deserialize_unicode(data): + """Preserve unicode objects in Python 2, otherwise return data + as a string. + + :param str data: response string to be deserialized. + :return: Deserialized string. + :rtype: str or unicode + """ + # We might be here because we have an enum modeled as string, + # and we try to deserialize a partial dict with enum inside + if isinstance(data, Enum): + return data + + # Consider this is real string + try: + if isinstance(data, unicode): # type: ignore + return data + except NameError: + return str(data) + return str(data) + + @staticmethod + def deserialize_enum(data, enum_obj): + """Deserialize string into enum object. + + If the string is not a valid enum value it will be returned as-is + and a warning will be logged. + + :param str data: Response string to be deserialized. If this value is + None or invalid it will be returned as-is. + :param Enum enum_obj: Enum object to deserialize to. + :return: Deserialized enum object. + :rtype: Enum + """ + if isinstance(data, enum_obj) or data is None: + return data + if isinstance(data, Enum): + data = data.value + if isinstance(data, int): + # Workaround. We might consider remove it in the future. + try: + return list(enum_obj.__members__.values())[data] + except IndexError as exc: + error = "{!r} is not a valid index for enum {!r}" + raise DeserializationError(error.format(data, enum_obj)) from exc + try: + return enum_obj(str(data)) + except ValueError: + for enum_value in enum_obj: + if enum_value.value.lower() == str(data).lower(): + return enum_value + # We don't fail anymore for unknown value, we deserialize as a string + _LOGGER.warning("Deserializer is not able to find %s as valid enum in %s", data, enum_obj) + return Deserializer.deserialize_unicode(data) + + @staticmethod + def deserialize_bytearray(attr): + """Deserialize string into bytearray. + + :param str attr: response string to be deserialized. + :return: Deserialized bytearray + :rtype: bytearray + :raises TypeError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + return bytearray(b64decode(attr)) # type: ignore + + @staticmethod + def deserialize_base64(attr): + """Deserialize base64 encoded string into string. + + :param str attr: response string to be deserialized. + :return: Deserialized base64 string + :rtype: bytearray + :raises TypeError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + padding = "=" * (3 - (len(attr) + 3) % 4) # type: ignore + attr = attr + padding # type: ignore + encoded = attr.replace("-", "+").replace("_", "/") + return b64decode(encoded) + + @staticmethod + def deserialize_decimal(attr): + """Deserialize string into Decimal object. + + :param str attr: response string to be deserialized. + :return: Deserialized decimal + :raises DeserializationError: if string format invalid. + :rtype: decimal + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + return decimal.Decimal(str(attr)) # type: ignore + except decimal.DecimalException as err: + msg = "Invalid decimal {}".format(attr) + raise DeserializationError(msg) from err + + @staticmethod + def deserialize_long(attr): + """Deserialize string into long (Py2) or int (Py3). + + :param str attr: response string to be deserialized. + :return: Deserialized int + :rtype: long or int + :raises ValueError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + return _long_type(attr) # type: ignore + + @staticmethod + def deserialize_duration(attr): + """Deserialize ISO-8601 formatted string into TimeDelta object. + + :param str attr: response string to be deserialized. + :return: Deserialized duration + :rtype: TimeDelta + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + duration = isodate.parse_duration(attr) + except (ValueError, OverflowError, AttributeError) as err: + msg = "Cannot deserialize duration object." + raise DeserializationError(msg) from err + return duration + + @staticmethod + def deserialize_date(attr): + """Deserialize ISO-8601 formatted string into Date object. + + :param str attr: response string to be deserialized. + :return: Deserialized date + :rtype: Date + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + if re.search(r"[^\W\d_]", attr, re.I + re.U): # type: ignore + raise DeserializationError("Date must have only digits and -. Received: %s" % attr) + # This must NOT use defaultmonth/defaultday. Using None ensure this raises an exception. + return isodate.parse_date(attr, defaultmonth=0, defaultday=0) + + @staticmethod + def deserialize_time(attr): + """Deserialize ISO-8601 formatted string into time object. + + :param str attr: response string to be deserialized. + :return: Deserialized time + :rtype: datetime.time + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + if re.search(r"[^\W\d_]", attr, re.I + re.U): # type: ignore + raise DeserializationError("Date must have only digits and -. Received: %s" % attr) + return isodate.parse_time(attr) + + @staticmethod + def deserialize_rfc(attr): + """Deserialize RFC-1123 formatted string into Datetime object. + + :param str attr: response string to be deserialized. + :return: Deserialized RFC datetime + :rtype: Datetime + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + parsed_date = email.utils.parsedate_tz(attr) # type: ignore + date_obj = datetime.datetime( + *parsed_date[:6], tzinfo=datetime.timezone(datetime.timedelta(minutes=(parsed_date[9] or 0) / 60)) + ) + if not date_obj.tzinfo: + date_obj = date_obj.astimezone(tz=TZ_UTC) + except ValueError as err: + msg = "Cannot deserialize to rfc datetime object." + raise DeserializationError(msg) from err + return date_obj + + @staticmethod + def deserialize_iso(attr): + """Deserialize ISO-8601 formatted string into Datetime object. + + :param str attr: response string to be deserialized. + :return: Deserialized ISO datetime + :rtype: Datetime + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + attr = attr.upper() # type: ignore + match = Deserializer.valid_date.match(attr) + if not match: + raise ValueError("Invalid datetime string: " + attr) + + check_decimal = attr.split(".") + if len(check_decimal) > 1: + decimal_str = "" + for digit in check_decimal[1]: + if digit.isdigit(): + decimal_str += digit + else: + break + if len(decimal_str) > 6: + attr = attr.replace(decimal_str, decimal_str[0:6]) + + date_obj = isodate.parse_datetime(attr) + test_utc = date_obj.utctimetuple() + if test_utc.tm_year > 9999 or test_utc.tm_year < 1: + raise OverflowError("Hit max or min date") + except (ValueError, OverflowError, AttributeError) as err: + msg = "Cannot deserialize datetime object." + raise DeserializationError(msg) from err + return date_obj + + @staticmethod + def deserialize_unix(attr): + """Serialize Datetime object into IntTime format. + This is represented as seconds. + + :param int attr: Object to be serialized. + :return: Deserialized datetime + :rtype: Datetime + :raises DeserializationError: if format invalid + """ + if isinstance(attr, ET.Element): + attr = int(attr.text) # type: ignore + try: + attr = int(attr) + date_obj = datetime.datetime.fromtimestamp(attr, TZ_UTC) + except ValueError as err: + msg = "Cannot deserialize to unix datetime object." + raise DeserializationError(msg) from err + return date_obj diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ValidationVersionTolerant/validationversiontolerant/_utils/utils.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ValidationVersionTolerant/validationversiontolerant/_utils/utils.py new file mode 100644 index 00000000000..39b612f39a9 --- /dev/null +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ValidationVersionTolerant/validationversiontolerant/_utils/utils.py @@ -0,0 +1,25 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from abc import ABC +from typing import Generic, TYPE_CHECKING, TypeVar + +if TYPE_CHECKING: + from .serialization import Deserializer, Serializer + + +TClient = TypeVar("TClient") +TConfig = TypeVar("TConfig") + + +class ClientMixinABC(ABC, Generic[TClient, TConfig]): + """DO NOT use this class. It is for internal typing use only.""" + + _client: TClient + _config: TConfig + _serialize: "Serializer" + _deserialize: "Deserializer" diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ValidationVersionTolerant/validationversiontolerant/_vendor.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ValidationVersionTolerant/validationversiontolerant/_vendor.py deleted file mode 100644 index 9bbcf1c713e..00000000000 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ValidationVersionTolerant/validationversiontolerant/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) AutoRest Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import AutoRestValidationTestConfiguration - -if TYPE_CHECKING: - from azure.core import PipelineClient - - from ._serialization import Deserializer, Serializer - - -class AutoRestValidationTestMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "PipelineClient" - _config: AutoRestValidationTestConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ValidationVersionTolerant/validationversiontolerant/aio/_client.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ValidationVersionTolerant/validationversiontolerant/aio/_client.py index aa6041f1d75..28dd473abe0 100644 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ValidationVersionTolerant/validationversiontolerant/aio/_client.py +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ValidationVersionTolerant/validationversiontolerant/aio/_client.py @@ -14,7 +14,7 @@ from azure.core.pipeline import policies from azure.core.rest import AsyncHttpResponse, HttpRequest -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import AutoRestValidationTestConfiguration from ._operations import AutoRestValidationTestOperationsMixin diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ValidationVersionTolerant/validationversiontolerant/aio/_operations/_operations.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ValidationVersionTolerant/validationversiontolerant/aio/_operations/_operations.py index 51f683fe59e..0bf68b0401e 100644 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ValidationVersionTolerant/validationversiontolerant/aio/_operations/_operations.py +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ValidationVersionTolerant/validationversiontolerant/aio/_operations/_operations.py @@ -10,6 +10,7 @@ from io import IOBase from typing import Any, Callable, Dict, IO, Literal, Optional, TypeVar, Union, cast, overload +from azure.core import AsyncPipelineClient from azure.core.exceptions import ( ClientAuthenticationError, HttpResponseError, @@ -29,14 +30,15 @@ build_auto_rest_validation_test_validation_of_body_request, build_auto_rest_validation_test_validation_of_method_parameters_request, ) -from .._vendor import AutoRestValidationTestMixinABC +from ..._utils.utils import ClientMixinABC +from .._configuration import AutoRestValidationTestConfiguration JSON = MutableMapping[str, Any] T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, AsyncHttpResponse], T, Dict[str, Any]], Any]] -class AutoRestValidationTestOperationsMixin(AutoRestValidationTestMixinABC): +class AutoRestValidationTestOperationsMixin(ClientMixinABC[AsyncPipelineClient, AutoRestValidationTestConfiguration]): @distributed_trace_async async def validation_of_method_parameters(self, resource_group_name: str, id: int, **kwargs: Any) -> JSON: diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ValidationVersionTolerant/validationversiontolerant/aio/_vendor.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ValidationVersionTolerant/validationversiontolerant/aio/_vendor.py deleted file mode 100644 index 45c768f1db5..00000000000 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/ValidationVersionTolerant/validationversiontolerant/aio/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) AutoRest Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import AutoRestValidationTestConfiguration - -if TYPE_CHECKING: - from azure.core import AsyncPipelineClient - - from .._serialization import Deserializer, Serializer - - -class AutoRestValidationTestMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "AsyncPipelineClient" - _config: AutoRestValidationTestConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/XmlVersionTolerant/xmlserviceversiontolerant/_client.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/XmlVersionTolerant/xmlserviceversiontolerant/_client.py index 32160d6fe38..6c6d3ffcde3 100644 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/XmlVersionTolerant/xmlserviceversiontolerant/_client.py +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/XmlVersionTolerant/xmlserviceversiontolerant/_client.py @@ -16,7 +16,7 @@ from . import models as _models from ._configuration import AutoRestSwaggerBATXMLServiceConfiguration -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer from .operations import XmlOperations diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/XmlVersionTolerant/xmlserviceversiontolerant/_utils/__init__.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/XmlVersionTolerant/xmlserviceversiontolerant/_utils/__init__.py new file mode 100644 index 00000000000..0af9b28f660 --- /dev/null +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/XmlVersionTolerant/xmlserviceversiontolerant/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/XmlVersionTolerant/xmlserviceversiontolerant/_utils/serialization.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/XmlVersionTolerant/xmlserviceversiontolerant/_utils/serialization.py new file mode 100644 index 00000000000..f5187701d7b --- /dev/null +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/XmlVersionTolerant/xmlserviceversiontolerant/_utils/serialization.py @@ -0,0 +1,2032 @@ +# pylint: disable=line-too-long,useless-suppression,too-many-lines +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +# pyright: reportUnnecessaryTypeIgnoreComment=false + +from base64 import b64decode, b64encode +import calendar +import datetime +import decimal +import email +from enum import Enum +import json +import logging +import re +import sys +import codecs +from typing import ( + Dict, + Any, + cast, + Optional, + Union, + AnyStr, + IO, + Mapping, + Callable, + MutableMapping, + List, +) + +try: + from urllib import quote # type: ignore +except ImportError: + from urllib.parse import quote +import xml.etree.ElementTree as ET + +import isodate # type: ignore +from typing_extensions import Self + +from azure.core.exceptions import DeserializationError, SerializationError +from azure.core.serialization import NULL as CoreNull + +_BOM = codecs.BOM_UTF8.decode(encoding="utf-8") + +JSON = MutableMapping[str, Any] + + +class RawDeserializer: + + # Accept "text" because we're open minded people... + JSON_REGEXP = re.compile(r"^(application|text)/([a-z+.]+\+)?json$") + + # Name used in context + CONTEXT_NAME = "deserialized_data" + + @classmethod + def deserialize_from_text(cls, data: Optional[Union[AnyStr, IO]], content_type: Optional[str] = None) -> Any: + """Decode data according to content-type. + + Accept a stream of data as well, but will be load at once in memory for now. + + If no content-type, will return the string version (not bytes, not stream) + + :param data: Input, could be bytes or stream (will be decoded with UTF8) or text + :type data: str or bytes or IO + :param str content_type: The content type. + :return: The deserialized data. + :rtype: object + """ + if hasattr(data, "read"): + # Assume a stream + data = cast(IO, data).read() + + if isinstance(data, bytes): + data_as_str = data.decode(encoding="utf-8-sig") + else: + # Explain to mypy the correct type. + data_as_str = cast(str, data) + + # Remove Byte Order Mark if present in string + data_as_str = data_as_str.lstrip(_BOM) + + if content_type is None: + return data + + if cls.JSON_REGEXP.match(content_type): + try: + return json.loads(data_as_str) + except ValueError as err: + raise DeserializationError("JSON is invalid: {}".format(err), err) from err + elif "xml" in (content_type or []): + try: + + try: + if isinstance(data, unicode): # type: ignore + # If I'm Python 2.7 and unicode XML will scream if I try a "fromstring" on unicode string + data_as_str = data_as_str.encode(encoding="utf-8") # type: ignore + except NameError: + pass + + return ET.fromstring(data_as_str) # nosec + except ET.ParseError as err: + # It might be because the server has an issue, and returned JSON with + # content-type XML.... + # So let's try a JSON load, and if it's still broken + # let's flow the initial exception + def _json_attemp(data): + try: + return True, json.loads(data) + except ValueError: + return False, None # Don't care about this one + + success, json_result = _json_attemp(data) + if success: + return json_result + # If i'm here, it's not JSON, it's not XML, let's scream + # and raise the last context in this block (the XML exception) + # The function hack is because Py2.7 messes up with exception + # context otherwise. + _LOGGER.critical("Wasn't XML not JSON, failing") + raise DeserializationError("XML is invalid") from err + elif content_type.startswith("text/"): + return data_as_str + raise DeserializationError("Cannot deserialize content-type: {}".format(content_type)) + + @classmethod + def deserialize_from_http_generics(cls, body_bytes: Optional[Union[AnyStr, IO]], headers: Mapping) -> Any: + """Deserialize from HTTP response. + + Use bytes and headers to NOT use any requests/aiohttp or whatever + specific implementation. + Headers will tested for "content-type" + + :param bytes body_bytes: The body of the response. + :param dict headers: The headers of the response. + :returns: The deserialized data. + :rtype: object + """ + # Try to use content-type from headers if available + content_type = None + if "content-type" in headers: + content_type = headers["content-type"].split(";")[0].strip().lower() + # Ouch, this server did not declare what it sent... + # Let's guess it's JSON... + # Also, since Autorest was considering that an empty body was a valid JSON, + # need that test as well.... + else: + content_type = "application/json" + + if body_bytes: + return cls.deserialize_from_text(body_bytes, content_type) + return None + + +_LOGGER = logging.getLogger(__name__) + +try: + _long_type = long # type: ignore +except NameError: + _long_type = int + +TZ_UTC = datetime.timezone.utc + +_FLATTEN = re.compile(r"(? None: + self.additional_properties: Optional[Dict[str, Any]] = {} + for k in kwargs: # pylint: disable=consider-using-dict-items + if k not in self._attribute_map: + _LOGGER.warning("%s is not a known attribute of class %s and will be ignored", k, self.__class__) + elif k in self._validation and self._validation[k].get("readonly", False): + _LOGGER.warning("Readonly attribute %s will be ignored in class %s", k, self.__class__) + else: + setattr(self, k, kwargs[k]) + + def __eq__(self, other: Any) -> bool: + """Compare objects by comparing all attributes. + + :param object other: The object to compare + :returns: True if objects are equal + :rtype: bool + """ + if isinstance(other, self.__class__): + return self.__dict__ == other.__dict__ + return False + + def __ne__(self, other: Any) -> bool: + """Compare objects by comparing all attributes. + + :param object other: The object to compare + :returns: True if objects are not equal + :rtype: bool + """ + return not self.__eq__(other) + + def __str__(self) -> str: + return str(self.__dict__) + + @classmethod + def enable_additional_properties_sending(cls) -> None: + cls._attribute_map["additional_properties"] = {"key": "", "type": "{object}"} + + @classmethod + def is_xml_model(cls) -> bool: + try: + cls._xml_map # type: ignore + except AttributeError: + return False + return True + + @classmethod + def _create_xml_node(cls): + """Create XML node. + + :returns: The XML node + :rtype: xml.etree.ElementTree.Element + """ + try: + xml_map = cls._xml_map # type: ignore + except AttributeError: + xml_map = {} + + return _create_xml_node(xml_map.get("name", cls.__name__), xml_map.get("prefix", None), xml_map.get("ns", None)) + + def serialize(self, keep_readonly: bool = False, **kwargs: Any) -> JSON: + """Return the JSON that would be sent to server from this model. + + This is an alias to `as_dict(full_restapi_key_transformer, keep_readonly=False)`. + + If you want XML serialization, you can pass the kwargs is_xml=True. + + :param bool keep_readonly: If you want to serialize the readonly attributes + :returns: A dict JSON compatible object + :rtype: dict + """ + serializer = Serializer(self._infer_class_models()) + return serializer._serialize( # type: ignore # pylint: disable=protected-access + self, keep_readonly=keep_readonly, **kwargs + ) + + def as_dict( + self, + keep_readonly: bool = True, + key_transformer: Callable[[str, Dict[str, Any], Any], Any] = attribute_transformer, + **kwargs: Any + ) -> JSON: + """Return a dict that can be serialized using json.dump. + + Advanced usage might optionally use a callback as parameter: + + .. code::python + + def my_key_transformer(key, attr_desc, value): + return key + + Key is the attribute name used in Python. Attr_desc + is a dict of metadata. Currently contains 'type' with the + msrest type and 'key' with the RestAPI encoded key. + Value is the current value in this object. + + The string returned will be used to serialize the key. + If the return type is a list, this is considered hierarchical + result dict. + + See the three examples in this file: + + - attribute_transformer + - full_restapi_key_transformer + - last_restapi_key_transformer + + If you want XML serialization, you can pass the kwargs is_xml=True. + + :param bool keep_readonly: If you want to serialize the readonly attributes + :param function key_transformer: A key transformer function. + :returns: A dict JSON compatible object + :rtype: dict + """ + serializer = Serializer(self._infer_class_models()) + return serializer._serialize( # type: ignore # pylint: disable=protected-access + self, key_transformer=key_transformer, keep_readonly=keep_readonly, **kwargs + ) + + @classmethod + def _infer_class_models(cls): + try: + str_models = cls.__module__.rsplit(".", 1)[0] + models = sys.modules[str_models] + client_models = {k: v for k, v in models.__dict__.items() if isinstance(v, type)} + if cls.__name__ not in client_models: + raise ValueError("Not Autorest generated code") + except Exception: # pylint: disable=broad-exception-caught + # Assume it's not Autorest generated (tests?). Add ourselves as dependencies. + client_models = {cls.__name__: cls} + return client_models + + @classmethod + def deserialize(cls, data: Any, content_type: Optional[str] = None) -> Self: + """Parse a str using the RestAPI syntax and return a model. + + :param str data: A str using RestAPI structure. JSON by default. + :param str content_type: JSON by default, set application/xml if XML. + :returns: An instance of this model + :raises DeserializationError: if something went wrong + :rtype: Self + """ + deserializer = Deserializer(cls._infer_class_models()) + return deserializer(cls.__name__, data, content_type=content_type) # type: ignore + + @classmethod + def from_dict( + cls, + data: Any, + key_extractors: Optional[Callable[[str, Dict[str, Any], Any], Any]] = None, + content_type: Optional[str] = None, + ) -> Self: + """Parse a dict using given key extractor return a model. + + By default consider key + extractors (rest_key_case_insensitive_extractor, attribute_key_case_insensitive_extractor + and last_rest_key_case_insensitive_extractor) + + :param dict data: A dict using RestAPI structure + :param function key_extractors: A key extractor function. + :param str content_type: JSON by default, set application/xml if XML. + :returns: An instance of this model + :raises DeserializationError: if something went wrong + :rtype: Self + """ + deserializer = Deserializer(cls._infer_class_models()) + deserializer.key_extractors = ( # type: ignore + [ # type: ignore + attribute_key_case_insensitive_extractor, + rest_key_case_insensitive_extractor, + last_rest_key_case_insensitive_extractor, + ] + if key_extractors is None + else key_extractors + ) + return deserializer(cls.__name__, data, content_type=content_type) # type: ignore + + @classmethod + def _flatten_subtype(cls, key, objects): + if "_subtype_map" not in cls.__dict__: + return {} + result = dict(cls._subtype_map[key]) + for valuetype in cls._subtype_map[key].values(): + result.update(objects[valuetype]._flatten_subtype(key, objects)) # pylint: disable=protected-access + return result + + @classmethod + def _classify(cls, response, objects): + """Check the class _subtype_map for any child classes. + We want to ignore any inherited _subtype_maps. + + :param dict response: The initial data + :param dict objects: The class objects + :returns: The class to be used + :rtype: class + """ + for subtype_key in cls.__dict__.get("_subtype_map", {}).keys(): + subtype_value = None + + if not isinstance(response, ET.Element): + rest_api_response_key = cls._get_rest_key_parts(subtype_key)[-1] + subtype_value = response.get(rest_api_response_key, None) or response.get(subtype_key, None) + else: + subtype_value = xml_key_extractor(subtype_key, cls._attribute_map[subtype_key], response) + if subtype_value: + # Try to match base class. Can be class name only + # (bug to fix in Autorest to support x-ms-discriminator-name) + if cls.__name__ == subtype_value: + return cls + flatten_mapping_type = cls._flatten_subtype(subtype_key, objects) + try: + return objects[flatten_mapping_type[subtype_value]] # type: ignore + except KeyError: + _LOGGER.warning( + "Subtype value %s has no mapping, use base class %s.", + subtype_value, + cls.__name__, + ) + break + else: + _LOGGER.warning("Discriminator %s is absent or null, use base class %s.", subtype_key, cls.__name__) + break + return cls + + @classmethod + def _get_rest_key_parts(cls, attr_key): + """Get the RestAPI key of this attr, split it and decode part + :param str attr_key: Attribute key must be in attribute_map. + :returns: A list of RestAPI part + :rtype: list + """ + rest_split_key = _FLATTEN.split(cls._attribute_map[attr_key]["key"]) + return [_decode_attribute_map_key(key_part) for key_part in rest_split_key] + + +def _decode_attribute_map_key(key): + """This decode a key in an _attribute_map to the actual key we want to look at + inside the received data. + + :param str key: A key string from the generated code + :returns: The decoded key + :rtype: str + """ + return key.replace("\\.", ".") + + +class Serializer: # pylint: disable=too-many-public-methods + """Request object model serializer.""" + + basic_types = {str: "str", int: "int", bool: "bool", float: "float"} + + _xml_basic_types_serializers = {"bool": lambda x: str(x).lower()} + days = {0: "Mon", 1: "Tue", 2: "Wed", 3: "Thu", 4: "Fri", 5: "Sat", 6: "Sun"} + months = { + 1: "Jan", + 2: "Feb", + 3: "Mar", + 4: "Apr", + 5: "May", + 6: "Jun", + 7: "Jul", + 8: "Aug", + 9: "Sep", + 10: "Oct", + 11: "Nov", + 12: "Dec", + } + validation = { + "min_length": lambda x, y: len(x) < y, + "max_length": lambda x, y: len(x) > y, + "minimum": lambda x, y: x < y, + "maximum": lambda x, y: x > y, + "minimum_ex": lambda x, y: x <= y, + "maximum_ex": lambda x, y: x >= y, + "min_items": lambda x, y: len(x) < y, + "max_items": lambda x, y: len(x) > y, + "pattern": lambda x, y: not re.match(y, x, re.UNICODE), + "unique": lambda x, y: len(x) != len(set(x)), + "multiple": lambda x, y: x % y != 0, + } + + def __init__(self, classes: Optional[Mapping[str, type]] = None) -> None: + self.serialize_type = { + "iso-8601": Serializer.serialize_iso, + "rfc-1123": Serializer.serialize_rfc, + "unix-time": Serializer.serialize_unix, + "duration": Serializer.serialize_duration, + "date": Serializer.serialize_date, + "time": Serializer.serialize_time, + "decimal": Serializer.serialize_decimal, + "long": Serializer.serialize_long, + "bytearray": Serializer.serialize_bytearray, + "base64": Serializer.serialize_base64, + "object": self.serialize_object, + "[]": self.serialize_iter, + "{}": self.serialize_dict, + } + self.dependencies: Dict[str, type] = dict(classes) if classes else {} + self.key_transformer = full_restapi_key_transformer + self.client_side_validation = True + + def _serialize( # pylint: disable=too-many-nested-blocks, too-many-branches, too-many-statements, too-many-locals + self, target_obj, data_type=None, **kwargs + ): + """Serialize data into a string according to type. + + :param object target_obj: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str, dict + :raises SerializationError: if serialization fails. + :returns: The serialized data. + """ + key_transformer = kwargs.get("key_transformer", self.key_transformer) + keep_readonly = kwargs.get("keep_readonly", False) + if target_obj is None: + return None + + attr_name = None + class_name = target_obj.__class__.__name__ + + if data_type: + return self.serialize_data(target_obj, data_type, **kwargs) + + if not hasattr(target_obj, "_attribute_map"): + data_type = type(target_obj).__name__ + if data_type in self.basic_types.values(): + return self.serialize_data(target_obj, data_type, **kwargs) + + # Force "is_xml" kwargs if we detect a XML model + try: + is_xml_model_serialization = kwargs["is_xml"] + except KeyError: + is_xml_model_serialization = kwargs.setdefault("is_xml", target_obj.is_xml_model()) + + serialized = {} + if is_xml_model_serialization: + serialized = target_obj._create_xml_node() # pylint: disable=protected-access + try: + attributes = target_obj._attribute_map # pylint: disable=protected-access + for attr, attr_desc in attributes.items(): + attr_name = attr + if not keep_readonly and target_obj._validation.get( # pylint: disable=protected-access + attr_name, {} + ).get("readonly", False): + continue + + if attr_name == "additional_properties" and attr_desc["key"] == "": + if target_obj.additional_properties is not None: + serialized.update(target_obj.additional_properties) + continue + try: + + orig_attr = getattr(target_obj, attr) + if is_xml_model_serialization: + pass # Don't provide "transformer" for XML for now. Keep "orig_attr" + else: # JSON + keys, orig_attr = key_transformer(attr, attr_desc.copy(), orig_attr) + keys = keys if isinstance(keys, list) else [keys] + + kwargs["serialization_ctxt"] = attr_desc + new_attr = self.serialize_data(orig_attr, attr_desc["type"], **kwargs) + + if is_xml_model_serialization: + xml_desc = attr_desc.get("xml", {}) + xml_name = xml_desc.get("name", attr_desc["key"]) + xml_prefix = xml_desc.get("prefix", None) + xml_ns = xml_desc.get("ns", None) + if xml_desc.get("attr", False): + if xml_ns: + ET.register_namespace(xml_prefix, xml_ns) + xml_name = "{{{}}}{}".format(xml_ns, xml_name) + serialized.set(xml_name, new_attr) # type: ignore + continue + if xml_desc.get("text", False): + serialized.text = new_attr # type: ignore + continue + if isinstance(new_attr, list): + serialized.extend(new_attr) # type: ignore + elif isinstance(new_attr, ET.Element): + # If the down XML has no XML/Name, + # we MUST replace the tag with the local tag. But keeping the namespaces. + if "name" not in getattr(orig_attr, "_xml_map", {}): + splitted_tag = new_attr.tag.split("}") + if len(splitted_tag) == 2: # Namespace + new_attr.tag = "}".join([splitted_tag[0], xml_name]) + else: + new_attr.tag = xml_name + serialized.append(new_attr) # type: ignore + else: # That's a basic type + # Integrate namespace if necessary + local_node = _create_xml_node(xml_name, xml_prefix, xml_ns) + local_node.text = str(new_attr) + serialized.append(local_node) # type: ignore + else: # JSON + for k in reversed(keys): # type: ignore + new_attr = {k: new_attr} + + _new_attr = new_attr + _serialized = serialized + for k in keys: # type: ignore + if k not in _serialized: + _serialized.update(_new_attr) # type: ignore + _new_attr = _new_attr[k] # type: ignore + _serialized = _serialized[k] + except ValueError as err: + if isinstance(err, SerializationError): + raise + + except (AttributeError, KeyError, TypeError) as err: + msg = "Attribute {} in object {} cannot be serialized.\n{}".format(attr_name, class_name, str(target_obj)) + raise SerializationError(msg) from err + return serialized + + def body(self, data, data_type, **kwargs): + """Serialize data intended for a request body. + + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: dict + :raises SerializationError: if serialization fails. + :raises ValueError: if data is None + :returns: The serialized request body + """ + + # Just in case this is a dict + internal_data_type_str = data_type.strip("[]{}") + internal_data_type = self.dependencies.get(internal_data_type_str, None) + try: + is_xml_model_serialization = kwargs["is_xml"] + except KeyError: + if internal_data_type and issubclass(internal_data_type, Model): + is_xml_model_serialization = kwargs.setdefault("is_xml", internal_data_type.is_xml_model()) + else: + is_xml_model_serialization = False + if internal_data_type and not isinstance(internal_data_type, Enum): + try: + deserializer = Deserializer(self.dependencies) + # Since it's on serialization, it's almost sure that format is not JSON REST + # We're not able to deal with additional properties for now. + deserializer.additional_properties_detection = False + if is_xml_model_serialization: + deserializer.key_extractors = [ # type: ignore + attribute_key_case_insensitive_extractor, + ] + else: + deserializer.key_extractors = [ + rest_key_case_insensitive_extractor, + attribute_key_case_insensitive_extractor, + last_rest_key_case_insensitive_extractor, + ] + data = deserializer._deserialize(data_type, data) # pylint: disable=protected-access + except DeserializationError as err: + raise SerializationError("Unable to build a model: " + str(err)) from err + + return self._serialize(data, data_type, **kwargs) + + def url(self, name, data, data_type, **kwargs): + """Serialize data intended for a URL path. + + :param str name: The name of the URL path parameter. + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str + :returns: The serialized URL path + :raises TypeError: if serialization fails. + :raises ValueError: if data is None + """ + try: + output = self.serialize_data(data, data_type, **kwargs) + if data_type == "bool": + output = json.dumps(output) + + if kwargs.get("skip_quote") is True: + output = str(output) + output = output.replace("{", quote("{")).replace("}", quote("}")) + else: + output = quote(str(output), safe="") + except SerializationError as exc: + raise TypeError("{} must be type {}.".format(name, data_type)) from exc + return output + + def query(self, name, data, data_type, **kwargs): + """Serialize data intended for a URL query. + + :param str name: The name of the query parameter. + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str, list + :raises TypeError: if serialization fails. + :raises ValueError: if data is None + :returns: The serialized query parameter + """ + try: + # Treat the list aside, since we don't want to encode the div separator + if data_type.startswith("["): + internal_data_type = data_type[1:-1] + do_quote = not kwargs.get("skip_quote", False) + return self.serialize_iter(data, internal_data_type, do_quote=do_quote, **kwargs) + + # Not a list, regular serialization + output = self.serialize_data(data, data_type, **kwargs) + if data_type == "bool": + output = json.dumps(output) + if kwargs.get("skip_quote") is True: + output = str(output) + else: + output = quote(str(output), safe="") + except SerializationError as exc: + raise TypeError("{} must be type {}.".format(name, data_type)) from exc + return str(output) + + def header(self, name, data, data_type, **kwargs): + """Serialize data intended for a request header. + + :param str name: The name of the header. + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str + :raises TypeError: if serialization fails. + :raises ValueError: if data is None + :returns: The serialized header + """ + try: + if data_type in ["[str]"]: + data = ["" if d is None else d for d in data] + + output = self.serialize_data(data, data_type, **kwargs) + if data_type == "bool": + output = json.dumps(output) + except SerializationError as exc: + raise TypeError("{} must be type {}.".format(name, data_type)) from exc + return str(output) + + def serialize_data(self, data, data_type, **kwargs): + """Serialize generic data according to supplied data type. + + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :raises AttributeError: if required data is None. + :raises ValueError: if data is None + :raises SerializationError: if serialization fails. + :returns: The serialized data. + :rtype: str, int, float, bool, dict, list + """ + if data is None: + raise ValueError("No value for given attribute") + + try: + if data is CoreNull: + return None + if data_type in self.basic_types.values(): + return self.serialize_basic(data, data_type, **kwargs) + + if data_type in self.serialize_type: + return self.serialize_type[data_type](data, **kwargs) + + # If dependencies is empty, try with current data class + # It has to be a subclass of Enum anyway + enum_type = self.dependencies.get(data_type, data.__class__) + if issubclass(enum_type, Enum): + return Serializer.serialize_enum(data, enum_obj=enum_type) + + iter_type = data_type[0] + data_type[-1] + if iter_type in self.serialize_type: + return self.serialize_type[iter_type](data, data_type[1:-1], **kwargs) + + except (ValueError, TypeError) as err: + msg = "Unable to serialize value: {!r} as type: {!r}." + raise SerializationError(msg.format(data, data_type)) from err + return self._serialize(data, **kwargs) + + @classmethod + def _get_custom_serializers(cls, data_type, **kwargs): # pylint: disable=inconsistent-return-statements + custom_serializer = kwargs.get("basic_types_serializers", {}).get(data_type) + if custom_serializer: + return custom_serializer + if kwargs.get("is_xml", False): + return cls._xml_basic_types_serializers.get(data_type) + + @classmethod + def serialize_basic(cls, data, data_type, **kwargs): + """Serialize basic builting data type. + Serializes objects to str, int, float or bool. + + Possible kwargs: + - basic_types_serializers dict[str, callable] : If set, use the callable as serializer + - is_xml bool : If set, use xml_basic_types_serializers + + :param obj data: Object to be serialized. + :param str data_type: Type of object in the iterable. + :rtype: str, int, float, bool + :return: serialized object + """ + custom_serializer = cls._get_custom_serializers(data_type, **kwargs) + if custom_serializer: + return custom_serializer(data) + if data_type == "str": + return cls.serialize_unicode(data) + return eval(data_type)(data) # nosec # pylint: disable=eval-used + + @classmethod + def serialize_unicode(cls, data): + """Special handling for serializing unicode strings in Py2. + Encode to UTF-8 if unicode, otherwise handle as a str. + + :param str data: Object to be serialized. + :rtype: str + :return: serialized object + """ + try: # If I received an enum, return its value + return data.value + except AttributeError: + pass + + try: + if isinstance(data, unicode): # type: ignore + # Don't change it, JSON and XML ElementTree are totally able + # to serialize correctly u'' strings + return data + except NameError: + return str(data) + return str(data) + + def serialize_iter(self, data, iter_type, div=None, **kwargs): + """Serialize iterable. + + Supported kwargs: + - serialization_ctxt dict : The current entry of _attribute_map, or same format. + serialization_ctxt['type'] should be same as data_type. + - is_xml bool : If set, serialize as XML + + :param list data: Object to be serialized. + :param str iter_type: Type of object in the iterable. + :param str div: If set, this str will be used to combine the elements + in the iterable into a combined string. Default is 'None'. + Defaults to False. + :rtype: list, str + :return: serialized iterable + """ + if isinstance(data, str): + raise SerializationError("Refuse str type as a valid iter type.") + + serialization_ctxt = kwargs.get("serialization_ctxt", {}) + is_xml = kwargs.get("is_xml", False) + + serialized = [] + for d in data: + try: + serialized.append(self.serialize_data(d, iter_type, **kwargs)) + except ValueError as err: + if isinstance(err, SerializationError): + raise + serialized.append(None) + + if kwargs.get("do_quote", False): + serialized = ["" if s is None else quote(str(s), safe="") for s in serialized] + + if div: + serialized = ["" if s is None else str(s) for s in serialized] + serialized = div.join(serialized) + + if "xml" in serialization_ctxt or is_xml: + # XML serialization is more complicated + xml_desc = serialization_ctxt.get("xml", {}) + xml_name = xml_desc.get("name") + if not xml_name: + xml_name = serialization_ctxt["key"] + + # Create a wrap node if necessary (use the fact that Element and list have "append") + is_wrapped = xml_desc.get("wrapped", False) + node_name = xml_desc.get("itemsName", xml_name) + if is_wrapped: + final_result = _create_xml_node(xml_name, xml_desc.get("prefix", None), xml_desc.get("ns", None)) + else: + final_result = [] + # All list elements to "local_node" + for el in serialized: + if isinstance(el, ET.Element): + el_node = el + else: + el_node = _create_xml_node(node_name, xml_desc.get("prefix", None), xml_desc.get("ns", None)) + if el is not None: # Otherwise it writes "None" :-p + el_node.text = str(el) + final_result.append(el_node) + return final_result + return serialized + + def serialize_dict(self, attr, dict_type, **kwargs): + """Serialize a dictionary of objects. + + :param dict attr: Object to be serialized. + :param str dict_type: Type of object in the dictionary. + :rtype: dict + :return: serialized dictionary + """ + serialization_ctxt = kwargs.get("serialization_ctxt", {}) + serialized = {} + for key, value in attr.items(): + try: + serialized[self.serialize_unicode(key)] = self.serialize_data(value, dict_type, **kwargs) + except ValueError as err: + if isinstance(err, SerializationError): + raise + serialized[self.serialize_unicode(key)] = None + + if "xml" in serialization_ctxt: + # XML serialization is more complicated + xml_desc = serialization_ctxt["xml"] + xml_name = xml_desc["name"] + + final_result = _create_xml_node(xml_name, xml_desc.get("prefix", None), xml_desc.get("ns", None)) + for key, value in serialized.items(): + ET.SubElement(final_result, key).text = value + return final_result + + return serialized + + def serialize_object(self, attr, **kwargs): # pylint: disable=too-many-return-statements + """Serialize a generic object. + This will be handled as a dictionary. If object passed in is not + a basic type (str, int, float, dict, list) it will simply be + cast to str. + + :param dict attr: Object to be serialized. + :rtype: dict or str + :return: serialized object + """ + if attr is None: + return None + if isinstance(attr, ET.Element): + return attr + obj_type = type(attr) + if obj_type in self.basic_types: + return self.serialize_basic(attr, self.basic_types[obj_type], **kwargs) + if obj_type is _long_type: + return self.serialize_long(attr) + if obj_type is str: + return self.serialize_unicode(attr) + if obj_type is datetime.datetime: + return self.serialize_iso(attr) + if obj_type is datetime.date: + return self.serialize_date(attr) + if obj_type is datetime.time: + return self.serialize_time(attr) + if obj_type is datetime.timedelta: + return self.serialize_duration(attr) + if obj_type is decimal.Decimal: + return self.serialize_decimal(attr) + + # If it's a model or I know this dependency, serialize as a Model + if obj_type in self.dependencies.values() or isinstance(attr, Model): + return self._serialize(attr) + + if obj_type == dict: + serialized = {} + for key, value in attr.items(): + try: + serialized[self.serialize_unicode(key)] = self.serialize_object(value, **kwargs) + except ValueError: + serialized[self.serialize_unicode(key)] = None + return serialized + + if obj_type == list: + serialized = [] + for obj in attr: + try: + serialized.append(self.serialize_object(obj, **kwargs)) + except ValueError: + pass + return serialized + return str(attr) + + @staticmethod + def serialize_enum(attr, enum_obj=None): + try: + result = attr.value + except AttributeError: + result = attr + try: + enum_obj(result) # type: ignore + return result + except ValueError as exc: + for enum_value in enum_obj: # type: ignore + if enum_value.value.lower() == str(attr).lower(): + return enum_value.value + error = "{!r} is not valid value for enum {!r}" + raise SerializationError(error.format(attr, enum_obj)) from exc + + @staticmethod + def serialize_bytearray(attr, **kwargs): # pylint: disable=unused-argument + """Serialize bytearray into base-64 string. + + :param str attr: Object to be serialized. + :rtype: str + :return: serialized base64 + """ + return b64encode(attr).decode() + + @staticmethod + def serialize_base64(attr, **kwargs): # pylint: disable=unused-argument + """Serialize str into base-64 string. + + :param str attr: Object to be serialized. + :rtype: str + :return: serialized base64 + """ + encoded = b64encode(attr).decode("ascii") + return encoded.strip("=").replace("+", "-").replace("/", "_") + + @staticmethod + def serialize_decimal(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Decimal object to float. + + :param decimal attr: Object to be serialized. + :rtype: float + :return: serialized decimal + """ + return float(attr) + + @staticmethod + def serialize_long(attr, **kwargs): # pylint: disable=unused-argument + """Serialize long (Py2) or int (Py3). + + :param int attr: Object to be serialized. + :rtype: int/long + :return: serialized long + """ + return _long_type(attr) + + @staticmethod + def serialize_date(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Date object into ISO-8601 formatted string. + + :param Date attr: Object to be serialized. + :rtype: str + :return: serialized date + """ + if isinstance(attr, str): + attr = isodate.parse_date(attr) + t = "{:04}-{:02}-{:02}".format(attr.year, attr.month, attr.day) + return t + + @staticmethod + def serialize_time(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Time object into ISO-8601 formatted string. + + :param datetime.time attr: Object to be serialized. + :rtype: str + :return: serialized time + """ + if isinstance(attr, str): + attr = isodate.parse_time(attr) + t = "{:02}:{:02}:{:02}".format(attr.hour, attr.minute, attr.second) + if attr.microsecond: + t += ".{:02}".format(attr.microsecond) + return t + + @staticmethod + def serialize_duration(attr, **kwargs): # pylint: disable=unused-argument + """Serialize TimeDelta object into ISO-8601 formatted string. + + :param TimeDelta attr: Object to be serialized. + :rtype: str + :return: serialized duration + """ + if isinstance(attr, str): + attr = isodate.parse_duration(attr) + return isodate.duration_isoformat(attr) + + @staticmethod + def serialize_rfc(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Datetime object into RFC-1123 formatted string. + + :param Datetime attr: Object to be serialized. + :rtype: str + :raises TypeError: if format invalid. + :return: serialized rfc + """ + try: + if not attr.tzinfo: + _LOGGER.warning("Datetime with no tzinfo will be considered UTC.") + utc = attr.utctimetuple() + except AttributeError as exc: + raise TypeError("RFC1123 object must be valid Datetime object.") from exc + + return "{}, {:02} {} {:04} {:02}:{:02}:{:02} GMT".format( + Serializer.days[utc.tm_wday], + utc.tm_mday, + Serializer.months[utc.tm_mon], + utc.tm_year, + utc.tm_hour, + utc.tm_min, + utc.tm_sec, + ) + + @staticmethod + def serialize_iso(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Datetime object into ISO-8601 formatted string. + + :param Datetime attr: Object to be serialized. + :rtype: str + :raises SerializationError: if format invalid. + :return: serialized iso + """ + if isinstance(attr, str): + attr = isodate.parse_datetime(attr) + try: + if not attr.tzinfo: + _LOGGER.warning("Datetime with no tzinfo will be considered UTC.") + utc = attr.utctimetuple() + if utc.tm_year > 9999 or utc.tm_year < 1: + raise OverflowError("Hit max or min date") + + microseconds = str(attr.microsecond).rjust(6, "0").rstrip("0").ljust(3, "0") + if microseconds: + microseconds = "." + microseconds + date = "{:04}-{:02}-{:02}T{:02}:{:02}:{:02}".format( + utc.tm_year, utc.tm_mon, utc.tm_mday, utc.tm_hour, utc.tm_min, utc.tm_sec + ) + return date + microseconds + "Z" + except (ValueError, OverflowError) as err: + msg = "Unable to serialize datetime object." + raise SerializationError(msg) from err + except AttributeError as err: + msg = "ISO-8601 object must be valid Datetime object." + raise TypeError(msg) from err + + @staticmethod + def serialize_unix(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Datetime object into IntTime format. + This is represented as seconds. + + :param Datetime attr: Object to be serialized. + :rtype: int + :raises SerializationError: if format invalid + :return: serialied unix + """ + if isinstance(attr, int): + return attr + try: + if not attr.tzinfo: + _LOGGER.warning("Datetime with no tzinfo will be considered UTC.") + return int(calendar.timegm(attr.utctimetuple())) + except AttributeError as exc: + raise TypeError("Unix time object must be valid Datetime object.") from exc + + +def rest_key_extractor(attr, attr_desc, data): # pylint: disable=unused-argument + key = attr_desc["key"] + working_data = data + + while "." in key: + # Need the cast, as for some reasons "split" is typed as list[str | Any] + dict_keys = cast(List[str], _FLATTEN.split(key)) + if len(dict_keys) == 1: + key = _decode_attribute_map_key(dict_keys[0]) + break + working_key = _decode_attribute_map_key(dict_keys[0]) + working_data = working_data.get(working_key, data) + if working_data is None: + # If at any point while following flatten JSON path see None, it means + # that all properties under are None as well + return None + key = ".".join(dict_keys[1:]) + + return working_data.get(key) + + +def rest_key_case_insensitive_extractor( # pylint: disable=unused-argument, inconsistent-return-statements + attr, attr_desc, data +): + key = attr_desc["key"] + working_data = data + + while "." in key: + dict_keys = _FLATTEN.split(key) + if len(dict_keys) == 1: + key = _decode_attribute_map_key(dict_keys[0]) + break + working_key = _decode_attribute_map_key(dict_keys[0]) + working_data = attribute_key_case_insensitive_extractor(working_key, None, working_data) + if working_data is None: + # If at any point while following flatten JSON path see None, it means + # that all properties under are None as well + return None + key = ".".join(dict_keys[1:]) + + if working_data: + return attribute_key_case_insensitive_extractor(key, None, working_data) + + +def last_rest_key_extractor(attr, attr_desc, data): # pylint: disable=unused-argument + """Extract the attribute in "data" based on the last part of the JSON path key. + + :param str attr: The attribute to extract + :param dict attr_desc: The attribute description + :param dict data: The data to extract from + :rtype: object + :returns: The extracted attribute + """ + key = attr_desc["key"] + dict_keys = _FLATTEN.split(key) + return attribute_key_extractor(dict_keys[-1], None, data) + + +def last_rest_key_case_insensitive_extractor(attr, attr_desc, data): # pylint: disable=unused-argument + """Extract the attribute in "data" based on the last part of the JSON path key. + + This is the case insensitive version of "last_rest_key_extractor" + :param str attr: The attribute to extract + :param dict attr_desc: The attribute description + :param dict data: The data to extract from + :rtype: object + :returns: The extracted attribute + """ + key = attr_desc["key"] + dict_keys = _FLATTEN.split(key) + return attribute_key_case_insensitive_extractor(dict_keys[-1], None, data) + + +def attribute_key_extractor(attr, _, data): + return data.get(attr) + + +def attribute_key_case_insensitive_extractor(attr, _, data): + found_key = None + lower_attr = attr.lower() + for key in data: + if lower_attr == key.lower(): + found_key = key + break + + return data.get(found_key) + + +def _extract_name_from_internal_type(internal_type): + """Given an internal type XML description, extract correct XML name with namespace. + + :param dict internal_type: An model type + :rtype: tuple + :returns: A tuple XML name + namespace dict + """ + internal_type_xml_map = getattr(internal_type, "_xml_map", {}) + xml_name = internal_type_xml_map.get("name", internal_type.__name__) + xml_ns = internal_type_xml_map.get("ns", None) + if xml_ns: + xml_name = "{{{}}}{}".format(xml_ns, xml_name) + return xml_name + + +def xml_key_extractor(attr, attr_desc, data): # pylint: disable=unused-argument,too-many-return-statements + if isinstance(data, dict): + return None + + # Test if this model is XML ready first + if not isinstance(data, ET.Element): + return None + + xml_desc = attr_desc.get("xml", {}) + xml_name = xml_desc.get("name", attr_desc["key"]) + + # Look for a children + is_iter_type = attr_desc["type"].startswith("[") + is_wrapped = xml_desc.get("wrapped", False) + internal_type = attr_desc.get("internalType", None) + internal_type_xml_map = getattr(internal_type, "_xml_map", {}) + + # Integrate namespace if necessary + xml_ns = xml_desc.get("ns", internal_type_xml_map.get("ns", None)) + if xml_ns: + xml_name = "{{{}}}{}".format(xml_ns, xml_name) + + # If it's an attribute, that's simple + if xml_desc.get("attr", False): + return data.get(xml_name) + + # If it's x-ms-text, that's simple too + if xml_desc.get("text", False): + return data.text + + # Scenario where I take the local name: + # - Wrapped node + # - Internal type is an enum (considered basic types) + # - Internal type has no XML/Name node + if is_wrapped or (internal_type and (issubclass(internal_type, Enum) or "name" not in internal_type_xml_map)): + children = data.findall(xml_name) + # If internal type has a local name and it's not a list, I use that name + elif not is_iter_type and internal_type and "name" in internal_type_xml_map: + xml_name = _extract_name_from_internal_type(internal_type) + children = data.findall(xml_name) + # That's an array + else: + if internal_type: # Complex type, ignore itemsName and use the complex type name + items_name = _extract_name_from_internal_type(internal_type) + else: + items_name = xml_desc.get("itemsName", xml_name) + children = data.findall(items_name) + + if len(children) == 0: + if is_iter_type: + if is_wrapped: + return None # is_wrapped no node, we want None + return [] # not wrapped, assume empty list + return None # Assume it's not there, maybe an optional node. + + # If is_iter_type and not wrapped, return all found children + if is_iter_type: + if not is_wrapped: + return children + # Iter and wrapped, should have found one node only (the wrap one) + if len(children) != 1: + raise DeserializationError( + "Tried to deserialize an array not wrapped, and found several nodes '{}'. Maybe you should declare this array as wrapped?".format( + xml_name + ) + ) + return list(children[0]) # Might be empty list and that's ok. + + # Here it's not a itertype, we should have found one element only or empty + if len(children) > 1: + raise DeserializationError("Find several XML '{}' where it was not expected".format(xml_name)) + return children[0] + + +class Deserializer: + """Response object model deserializer. + + :param dict classes: Class type dictionary for deserializing complex types. + :ivar list key_extractors: Ordered list of extractors to be used by this deserializer. + """ + + basic_types = {str: "str", int: "int", bool: "bool", float: "float"} + + valid_date = re.compile(r"\d{4}[-]\d{2}[-]\d{2}T\d{2}:\d{2}:\d{2}\.?\d*Z?[-+]?[\d{2}]?:?[\d{2}]?") + + def __init__(self, classes: Optional[Mapping[str, type]] = None) -> None: + self.deserialize_type = { + "iso-8601": Deserializer.deserialize_iso, + "rfc-1123": Deserializer.deserialize_rfc, + "unix-time": Deserializer.deserialize_unix, + "duration": Deserializer.deserialize_duration, + "date": Deserializer.deserialize_date, + "time": Deserializer.deserialize_time, + "decimal": Deserializer.deserialize_decimal, + "long": Deserializer.deserialize_long, + "bytearray": Deserializer.deserialize_bytearray, + "base64": Deserializer.deserialize_base64, + "object": self.deserialize_object, + "[]": self.deserialize_iter, + "{}": self.deserialize_dict, + } + self.deserialize_expected_types = { + "duration": (isodate.Duration, datetime.timedelta), + "iso-8601": (datetime.datetime), + } + self.dependencies: Dict[str, type] = dict(classes) if classes else {} + self.key_extractors = [rest_key_extractor, xml_key_extractor] + # Additional properties only works if the "rest_key_extractor" is used to + # extract the keys. Making it to work whatever the key extractor is too much + # complicated, with no real scenario for now. + # So adding a flag to disable additional properties detection. This flag should be + # used if your expect the deserialization to NOT come from a JSON REST syntax. + # Otherwise, result are unexpected + self.additional_properties_detection = True + + def __call__(self, target_obj, response_data, content_type=None): + """Call the deserializer to process a REST response. + + :param str target_obj: Target data type to deserialize to. + :param requests.Response response_data: REST response object. + :param str content_type: Swagger "produces" if available. + :raises DeserializationError: if deserialization fails. + :return: Deserialized object. + :rtype: object + """ + data = self._unpack_content(response_data, content_type) + return self._deserialize(target_obj, data) + + def _deserialize(self, target_obj, data): # pylint: disable=inconsistent-return-statements + """Call the deserializer on a model. + + Data needs to be already deserialized as JSON or XML ElementTree + + :param str target_obj: Target data type to deserialize to. + :param object data: Object to deserialize. + :raises DeserializationError: if deserialization fails. + :return: Deserialized object. + :rtype: object + """ + # This is already a model, go recursive just in case + if hasattr(data, "_attribute_map"): + constants = [name for name, config in getattr(data, "_validation", {}).items() if config.get("constant")] + try: + for attr, mapconfig in data._attribute_map.items(): # pylint: disable=protected-access + if attr in constants: + continue + value = getattr(data, attr) + if value is None: + continue + local_type = mapconfig["type"] + internal_data_type = local_type.strip("[]{}") + if internal_data_type not in self.dependencies or isinstance(internal_data_type, Enum): + continue + setattr(data, attr, self._deserialize(local_type, value)) + return data + except AttributeError: + return + + response, class_name = self._classify_target(target_obj, data) + + if isinstance(response, str): + return self.deserialize_data(data, response) + if isinstance(response, type) and issubclass(response, Enum): + return self.deserialize_enum(data, response) + + if data is None or data is CoreNull: + return data + try: + attributes = response._attribute_map # type: ignore # pylint: disable=protected-access + d_attrs = {} + for attr, attr_desc in attributes.items(): + # Check empty string. If it's not empty, someone has a real "additionalProperties"... + if attr == "additional_properties" and attr_desc["key"] == "": + continue + raw_value = None + # Enhance attr_desc with some dynamic data + attr_desc = attr_desc.copy() # Do a copy, do not change the real one + internal_data_type = attr_desc["type"].strip("[]{}") + if internal_data_type in self.dependencies: + attr_desc["internalType"] = self.dependencies[internal_data_type] + + for key_extractor in self.key_extractors: + found_value = key_extractor(attr, attr_desc, data) + if found_value is not None: + if raw_value is not None and raw_value != found_value: + msg = ( + "Ignoring extracted value '%s' from %s for key '%s'" + " (duplicate extraction, follow extractors order)" + ) + _LOGGER.warning(msg, found_value, key_extractor, attr) + continue + raw_value = found_value + + value = self.deserialize_data(raw_value, attr_desc["type"]) + d_attrs[attr] = value + except (AttributeError, TypeError, KeyError) as err: + msg = "Unable to deserialize to object: " + class_name # type: ignore + raise DeserializationError(msg) from err + additional_properties = self._build_additional_properties(attributes, data) + return self._instantiate_model(response, d_attrs, additional_properties) + + def _build_additional_properties(self, attribute_map, data): + if not self.additional_properties_detection: + return None + if "additional_properties" in attribute_map and attribute_map.get("additional_properties", {}).get("key") != "": + # Check empty string. If it's not empty, someone has a real "additionalProperties" + return None + if isinstance(data, ET.Element): + data = {el.tag: el.text for el in data} + + known_keys = { + _decode_attribute_map_key(_FLATTEN.split(desc["key"])[0]) + for desc in attribute_map.values() + if desc["key"] != "" + } + present_keys = set(data.keys()) + missing_keys = present_keys - known_keys + return {key: data[key] for key in missing_keys} + + def _classify_target(self, target, data): + """Check to see whether the deserialization target object can + be classified into a subclass. + Once classification has been determined, initialize object. + + :param str target: The target object type to deserialize to. + :param str/dict data: The response data to deserialize. + :return: The classified target object and its class name. + :rtype: tuple + """ + if target is None: + return None, None + + if isinstance(target, str): + try: + target = self.dependencies[target] + except KeyError: + return target, target + + try: + target = target._classify(data, self.dependencies) # type: ignore # pylint: disable=protected-access + except AttributeError: + pass # Target is not a Model, no classify + return target, target.__class__.__name__ # type: ignore + + def failsafe_deserialize(self, target_obj, data, content_type=None): + """Ignores any errors encountered in deserialization, + and falls back to not deserializing the object. Recommended + for use in error deserialization, as we want to return the + HttpResponseError to users, and not have them deal with + a deserialization error. + + :param str target_obj: The target object type to deserialize to. + :param str/dict data: The response data to deserialize. + :param str content_type: Swagger "produces" if available. + :return: Deserialized object. + :rtype: object + """ + try: + return self(target_obj, data, content_type=content_type) + except: # pylint: disable=bare-except + _LOGGER.debug( + "Ran into a deserialization error. Ignoring since this is failsafe deserialization", exc_info=True + ) + return None + + @staticmethod + def _unpack_content(raw_data, content_type=None): + """Extract the correct structure for deserialization. + + If raw_data is a PipelineResponse, try to extract the result of RawDeserializer. + if we can't, raise. Your Pipeline should have a RawDeserializer. + + If not a pipeline response and raw_data is bytes or string, use content-type + to decode it. If no content-type, try JSON. + + If raw_data is something else, bypass all logic and return it directly. + + :param obj raw_data: Data to be processed. + :param str content_type: How to parse if raw_data is a string/bytes. + :raises JSONDecodeError: If JSON is requested and parsing is impossible. + :raises UnicodeDecodeError: If bytes is not UTF8 + :rtype: object + :return: Unpacked content. + """ + # Assume this is enough to detect a Pipeline Response without importing it + context = getattr(raw_data, "context", {}) + if context: + if RawDeserializer.CONTEXT_NAME in context: + return context[RawDeserializer.CONTEXT_NAME] + raise ValueError("This pipeline didn't have the RawDeserializer policy; can't deserialize") + + # Assume this is enough to recognize universal_http.ClientResponse without importing it + if hasattr(raw_data, "body"): + return RawDeserializer.deserialize_from_http_generics(raw_data.text(), raw_data.headers) + + # Assume this enough to recognize requests.Response without importing it. + if hasattr(raw_data, "_content_consumed"): + return RawDeserializer.deserialize_from_http_generics(raw_data.text, raw_data.headers) + + if isinstance(raw_data, (str, bytes)) or hasattr(raw_data, "read"): + return RawDeserializer.deserialize_from_text(raw_data, content_type) # type: ignore + return raw_data + + def _instantiate_model(self, response, attrs, additional_properties=None): + """Instantiate a response model passing in deserialized args. + + :param Response response: The response model class. + :param dict attrs: The deserialized response attributes. + :param dict additional_properties: Additional properties to be set. + :rtype: Response + :return: The instantiated response model. + """ + if callable(response): + subtype = getattr(response, "_subtype_map", {}) + try: + readonly = [ + k + for k, v in response._validation.items() # pylint: disable=protected-access # type: ignore + if v.get("readonly") + ] + const = [ + k + for k, v in response._validation.items() # pylint: disable=protected-access # type: ignore + if v.get("constant") + ] + kwargs = {k: v for k, v in attrs.items() if k not in subtype and k not in readonly + const} + response_obj = response(**kwargs) + for attr in readonly: + setattr(response_obj, attr, attrs.get(attr)) + if additional_properties: + response_obj.additional_properties = additional_properties # type: ignore + return response_obj + except TypeError as err: + msg = "Unable to deserialize {} into model {}. ".format(kwargs, response) # type: ignore + raise DeserializationError(msg + str(err)) from err + else: + try: + for attr, value in attrs.items(): + setattr(response, attr, value) + return response + except Exception as exp: + msg = "Unable to populate response model. " + msg += "Type: {}, Error: {}".format(type(response), exp) + raise DeserializationError(msg) from exp + + def deserialize_data(self, data, data_type): # pylint: disable=too-many-return-statements + """Process data for deserialization according to data type. + + :param str data: The response string to be deserialized. + :param str data_type: The type to deserialize to. + :raises DeserializationError: if deserialization fails. + :return: Deserialized object. + :rtype: object + """ + if data is None: + return data + + try: + if not data_type: + return data + if data_type in self.basic_types.values(): + return self.deserialize_basic(data, data_type) + if data_type in self.deserialize_type: + if isinstance(data, self.deserialize_expected_types.get(data_type, tuple())): + return data + + is_a_text_parsing_type = lambda x: x not in [ # pylint: disable=unnecessary-lambda-assignment + "object", + "[]", + r"{}", + ] + if isinstance(data, ET.Element) and is_a_text_parsing_type(data_type) and not data.text: + return None + data_val = self.deserialize_type[data_type](data) + return data_val + + iter_type = data_type[0] + data_type[-1] + if iter_type in self.deserialize_type: + return self.deserialize_type[iter_type](data, data_type[1:-1]) + + obj_type = self.dependencies[data_type] + if issubclass(obj_type, Enum): + if isinstance(data, ET.Element): + data = data.text + return self.deserialize_enum(data, obj_type) + + except (ValueError, TypeError, AttributeError) as err: + msg = "Unable to deserialize response data." + msg += " Data: {}, {}".format(data, data_type) + raise DeserializationError(msg) from err + return self._deserialize(obj_type, data) + + def deserialize_iter(self, attr, iter_type): + """Deserialize an iterable. + + :param list attr: Iterable to be deserialized. + :param str iter_type: The type of object in the iterable. + :return: Deserialized iterable. + :rtype: list + """ + if attr is None: + return None + if isinstance(attr, ET.Element): # If I receive an element here, get the children + attr = list(attr) + if not isinstance(attr, (list, set)): + raise DeserializationError("Cannot deserialize as [{}] an object of type {}".format(iter_type, type(attr))) + return [self.deserialize_data(a, iter_type) for a in attr] + + def deserialize_dict(self, attr, dict_type): + """Deserialize a dictionary. + + :param dict/list attr: Dictionary to be deserialized. Also accepts + a list of key, value pairs. + :param str dict_type: The object type of the items in the dictionary. + :return: Deserialized dictionary. + :rtype: dict + """ + if isinstance(attr, list): + return {x["key"]: self.deserialize_data(x["value"], dict_type) for x in attr} + + if isinstance(attr, ET.Element): + # Transform value into {"Key": "value"} + attr = {el.tag: el.text for el in attr} + return {k: self.deserialize_data(v, dict_type) for k, v in attr.items()} + + def deserialize_object(self, attr, **kwargs): # pylint: disable=too-many-return-statements + """Deserialize a generic object. + This will be handled as a dictionary. + + :param dict attr: Dictionary to be deserialized. + :return: Deserialized object. + :rtype: dict + :raises TypeError: if non-builtin datatype encountered. + """ + if attr is None: + return None + if isinstance(attr, ET.Element): + # Do no recurse on XML, just return the tree as-is + return attr + if isinstance(attr, str): + return self.deserialize_basic(attr, "str") + obj_type = type(attr) + if obj_type in self.basic_types: + return self.deserialize_basic(attr, self.basic_types[obj_type]) + if obj_type is _long_type: + return self.deserialize_long(attr) + + if obj_type == dict: + deserialized = {} + for key, value in attr.items(): + try: + deserialized[key] = self.deserialize_object(value, **kwargs) + except ValueError: + deserialized[key] = None + return deserialized + + if obj_type == list: + deserialized = [] + for obj in attr: + try: + deserialized.append(self.deserialize_object(obj, **kwargs)) + except ValueError: + pass + return deserialized + + error = "Cannot deserialize generic object with type: " + raise TypeError(error + str(obj_type)) + + def deserialize_basic(self, attr, data_type): # pylint: disable=too-many-return-statements + """Deserialize basic builtin data type from string. + Will attempt to convert to str, int, float and bool. + This function will also accept '1', '0', 'true' and 'false' as + valid bool values. + + :param str attr: response string to be deserialized. + :param str data_type: deserialization data type. + :return: Deserialized basic type. + :rtype: str, int, float or bool + :raises TypeError: if string format is not valid. + """ + # If we're here, data is supposed to be a basic type. + # If it's still an XML node, take the text + if isinstance(attr, ET.Element): + attr = attr.text + if not attr: + if data_type == "str": + # None or '', node is empty string. + return "" + # None or '', node with a strong type is None. + # Don't try to model "empty bool" or "empty int" + return None + + if data_type == "bool": + if attr in [True, False, 1, 0]: + return bool(attr) + if isinstance(attr, str): + if attr.lower() in ["true", "1"]: + return True + if attr.lower() in ["false", "0"]: + return False + raise TypeError("Invalid boolean value: {}".format(attr)) + + if data_type == "str": + return self.deserialize_unicode(attr) + return eval(data_type)(attr) # nosec # pylint: disable=eval-used + + @staticmethod + def deserialize_unicode(data): + """Preserve unicode objects in Python 2, otherwise return data + as a string. + + :param str data: response string to be deserialized. + :return: Deserialized string. + :rtype: str or unicode + """ + # We might be here because we have an enum modeled as string, + # and we try to deserialize a partial dict with enum inside + if isinstance(data, Enum): + return data + + # Consider this is real string + try: + if isinstance(data, unicode): # type: ignore + return data + except NameError: + return str(data) + return str(data) + + @staticmethod + def deserialize_enum(data, enum_obj): + """Deserialize string into enum object. + + If the string is not a valid enum value it will be returned as-is + and a warning will be logged. + + :param str data: Response string to be deserialized. If this value is + None or invalid it will be returned as-is. + :param Enum enum_obj: Enum object to deserialize to. + :return: Deserialized enum object. + :rtype: Enum + """ + if isinstance(data, enum_obj) or data is None: + return data + if isinstance(data, Enum): + data = data.value + if isinstance(data, int): + # Workaround. We might consider remove it in the future. + try: + return list(enum_obj.__members__.values())[data] + except IndexError as exc: + error = "{!r} is not a valid index for enum {!r}" + raise DeserializationError(error.format(data, enum_obj)) from exc + try: + return enum_obj(str(data)) + except ValueError: + for enum_value in enum_obj: + if enum_value.value.lower() == str(data).lower(): + return enum_value + # We don't fail anymore for unknown value, we deserialize as a string + _LOGGER.warning("Deserializer is not able to find %s as valid enum in %s", data, enum_obj) + return Deserializer.deserialize_unicode(data) + + @staticmethod + def deserialize_bytearray(attr): + """Deserialize string into bytearray. + + :param str attr: response string to be deserialized. + :return: Deserialized bytearray + :rtype: bytearray + :raises TypeError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + return bytearray(b64decode(attr)) # type: ignore + + @staticmethod + def deserialize_base64(attr): + """Deserialize base64 encoded string into string. + + :param str attr: response string to be deserialized. + :return: Deserialized base64 string + :rtype: bytearray + :raises TypeError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + padding = "=" * (3 - (len(attr) + 3) % 4) # type: ignore + attr = attr + padding # type: ignore + encoded = attr.replace("-", "+").replace("_", "/") + return b64decode(encoded) + + @staticmethod + def deserialize_decimal(attr): + """Deserialize string into Decimal object. + + :param str attr: response string to be deserialized. + :return: Deserialized decimal + :raises DeserializationError: if string format invalid. + :rtype: decimal + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + return decimal.Decimal(str(attr)) # type: ignore + except decimal.DecimalException as err: + msg = "Invalid decimal {}".format(attr) + raise DeserializationError(msg) from err + + @staticmethod + def deserialize_long(attr): + """Deserialize string into long (Py2) or int (Py3). + + :param str attr: response string to be deserialized. + :return: Deserialized int + :rtype: long or int + :raises ValueError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + return _long_type(attr) # type: ignore + + @staticmethod + def deserialize_duration(attr): + """Deserialize ISO-8601 formatted string into TimeDelta object. + + :param str attr: response string to be deserialized. + :return: Deserialized duration + :rtype: TimeDelta + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + duration = isodate.parse_duration(attr) + except (ValueError, OverflowError, AttributeError) as err: + msg = "Cannot deserialize duration object." + raise DeserializationError(msg) from err + return duration + + @staticmethod + def deserialize_date(attr): + """Deserialize ISO-8601 formatted string into Date object. + + :param str attr: response string to be deserialized. + :return: Deserialized date + :rtype: Date + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + if re.search(r"[^\W\d_]", attr, re.I + re.U): # type: ignore + raise DeserializationError("Date must have only digits and -. Received: %s" % attr) + # This must NOT use defaultmonth/defaultday. Using None ensure this raises an exception. + return isodate.parse_date(attr, defaultmonth=0, defaultday=0) + + @staticmethod + def deserialize_time(attr): + """Deserialize ISO-8601 formatted string into time object. + + :param str attr: response string to be deserialized. + :return: Deserialized time + :rtype: datetime.time + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + if re.search(r"[^\W\d_]", attr, re.I + re.U): # type: ignore + raise DeserializationError("Date must have only digits and -. Received: %s" % attr) + return isodate.parse_time(attr) + + @staticmethod + def deserialize_rfc(attr): + """Deserialize RFC-1123 formatted string into Datetime object. + + :param str attr: response string to be deserialized. + :return: Deserialized RFC datetime + :rtype: Datetime + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + parsed_date = email.utils.parsedate_tz(attr) # type: ignore + date_obj = datetime.datetime( + *parsed_date[:6], tzinfo=datetime.timezone(datetime.timedelta(minutes=(parsed_date[9] or 0) / 60)) + ) + if not date_obj.tzinfo: + date_obj = date_obj.astimezone(tz=TZ_UTC) + except ValueError as err: + msg = "Cannot deserialize to rfc datetime object." + raise DeserializationError(msg) from err + return date_obj + + @staticmethod + def deserialize_iso(attr): + """Deserialize ISO-8601 formatted string into Datetime object. + + :param str attr: response string to be deserialized. + :return: Deserialized ISO datetime + :rtype: Datetime + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + attr = attr.upper() # type: ignore + match = Deserializer.valid_date.match(attr) + if not match: + raise ValueError("Invalid datetime string: " + attr) + + check_decimal = attr.split(".") + if len(check_decimal) > 1: + decimal_str = "" + for digit in check_decimal[1]: + if digit.isdigit(): + decimal_str += digit + else: + break + if len(decimal_str) > 6: + attr = attr.replace(decimal_str, decimal_str[0:6]) + + date_obj = isodate.parse_datetime(attr) + test_utc = date_obj.utctimetuple() + if test_utc.tm_year > 9999 or test_utc.tm_year < 1: + raise OverflowError("Hit max or min date") + except (ValueError, OverflowError, AttributeError) as err: + msg = "Cannot deserialize datetime object." + raise DeserializationError(msg) from err + return date_obj + + @staticmethod + def deserialize_unix(attr): + """Serialize Datetime object into IntTime format. + This is represented as seconds. + + :param int attr: Object to be serialized. + :return: Deserialized datetime + :rtype: Datetime + :raises DeserializationError: if format invalid + """ + if isinstance(attr, ET.Element): + attr = int(attr.text) # type: ignore + try: + attr = int(attr) + date_obj = datetime.datetime.fromtimestamp(attr, TZ_UTC) + except ValueError as err: + msg = "Cannot deserialize to unix datetime object." + raise DeserializationError(msg) from err + return date_obj diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/XmlVersionTolerant/xmlserviceversiontolerant/aio/_client.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/XmlVersionTolerant/xmlserviceversiontolerant/aio/_client.py index 54c6d51998f..c68117bcc24 100644 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/XmlVersionTolerant/xmlserviceversiontolerant/aio/_client.py +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/XmlVersionTolerant/xmlserviceversiontolerant/aio/_client.py @@ -15,7 +15,7 @@ from azure.core.rest import AsyncHttpResponse, HttpRequest from .. import models as _models -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import AutoRestSwaggerBATXMLServiceConfiguration from .operations import XmlOperations diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/XmlVersionTolerant/xmlserviceversiontolerant/aio/operations/_operations.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/XmlVersionTolerant/xmlserviceversiontolerant/aio/operations/_operations.py index 700ac443627..3f3f8927b2e 100644 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/XmlVersionTolerant/xmlserviceversiontolerant/aio/operations/_operations.py +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/XmlVersionTolerant/xmlserviceversiontolerant/aio/operations/_operations.py @@ -25,7 +25,7 @@ from azure.core.utils import case_insensitive_dict from ... import models as _models -from ..._serialization import Deserializer, Serializer +from ..._utils.serialization import Deserializer, Serializer from ...operations._operations import ( build_xml_get_acls_request, build_xml_get_bytes_request, diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/XmlVersionTolerant/xmlserviceversiontolerant/models/_models.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/XmlVersionTolerant/xmlserviceversiontolerant/models/_models.py index 5ddfca1b641..bf5bf1d3dc1 100644 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/XmlVersionTolerant/xmlserviceversiontolerant/models/_models.py +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/XmlVersionTolerant/xmlserviceversiontolerant/models/_models.py @@ -10,7 +10,7 @@ import datetime from typing import Any, Dict, List, Optional, TYPE_CHECKING, Union -from .. import _serialization +from .._utils import serialization as _serialization if TYPE_CHECKING: from .. import models as _models diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/XmlVersionTolerant/xmlserviceversiontolerant/operations/_operations.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/XmlVersionTolerant/xmlserviceversiontolerant/operations/_operations.py index 895f52748dc..b2987d9b35a 100644 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/XmlVersionTolerant/xmlserviceversiontolerant/operations/_operations.py +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/XmlVersionTolerant/xmlserviceversiontolerant/operations/_operations.py @@ -26,7 +26,7 @@ from .. import models as _models from .._configuration import AutoRestSwaggerBATXMLServiceConfiguration -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/XmsErrorResponseVersionTolerant/xmserrorresponseversiontolerant/_client.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/XmsErrorResponseVersionTolerant/xmserrorresponseversiontolerant/_client.py index 33d7218a1b0..d129bff4b36 100644 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/XmsErrorResponseVersionTolerant/xmserrorresponseversiontolerant/_client.py +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/XmsErrorResponseVersionTolerant/xmserrorresponseversiontolerant/_client.py @@ -15,7 +15,7 @@ from azure.core.rest import HttpRequest, HttpResponse from ._configuration import XMSErrorResponseExtensionsConfiguration -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer from .operations import PetOperations diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/XmsErrorResponseVersionTolerant/xmserrorresponseversiontolerant/_utils/__init__.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/XmsErrorResponseVersionTolerant/xmserrorresponseversiontolerant/_utils/__init__.py new file mode 100644 index 00000000000..0af9b28f660 --- /dev/null +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/XmsErrorResponseVersionTolerant/xmserrorresponseversiontolerant/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/XmsErrorResponseVersionTolerant/xmserrorresponseversiontolerant/_utils/serialization.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/XmsErrorResponseVersionTolerant/xmserrorresponseversiontolerant/_utils/serialization.py new file mode 100644 index 00000000000..f5187701d7b --- /dev/null +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/XmsErrorResponseVersionTolerant/xmserrorresponseversiontolerant/_utils/serialization.py @@ -0,0 +1,2032 @@ +# pylint: disable=line-too-long,useless-suppression,too-many-lines +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +# pyright: reportUnnecessaryTypeIgnoreComment=false + +from base64 import b64decode, b64encode +import calendar +import datetime +import decimal +import email +from enum import Enum +import json +import logging +import re +import sys +import codecs +from typing import ( + Dict, + Any, + cast, + Optional, + Union, + AnyStr, + IO, + Mapping, + Callable, + MutableMapping, + List, +) + +try: + from urllib import quote # type: ignore +except ImportError: + from urllib.parse import quote +import xml.etree.ElementTree as ET + +import isodate # type: ignore +from typing_extensions import Self + +from azure.core.exceptions import DeserializationError, SerializationError +from azure.core.serialization import NULL as CoreNull + +_BOM = codecs.BOM_UTF8.decode(encoding="utf-8") + +JSON = MutableMapping[str, Any] + + +class RawDeserializer: + + # Accept "text" because we're open minded people... + JSON_REGEXP = re.compile(r"^(application|text)/([a-z+.]+\+)?json$") + + # Name used in context + CONTEXT_NAME = "deserialized_data" + + @classmethod + def deserialize_from_text(cls, data: Optional[Union[AnyStr, IO]], content_type: Optional[str] = None) -> Any: + """Decode data according to content-type. + + Accept a stream of data as well, but will be load at once in memory for now. + + If no content-type, will return the string version (not bytes, not stream) + + :param data: Input, could be bytes or stream (will be decoded with UTF8) or text + :type data: str or bytes or IO + :param str content_type: The content type. + :return: The deserialized data. + :rtype: object + """ + if hasattr(data, "read"): + # Assume a stream + data = cast(IO, data).read() + + if isinstance(data, bytes): + data_as_str = data.decode(encoding="utf-8-sig") + else: + # Explain to mypy the correct type. + data_as_str = cast(str, data) + + # Remove Byte Order Mark if present in string + data_as_str = data_as_str.lstrip(_BOM) + + if content_type is None: + return data + + if cls.JSON_REGEXP.match(content_type): + try: + return json.loads(data_as_str) + except ValueError as err: + raise DeserializationError("JSON is invalid: {}".format(err), err) from err + elif "xml" in (content_type or []): + try: + + try: + if isinstance(data, unicode): # type: ignore + # If I'm Python 2.7 and unicode XML will scream if I try a "fromstring" on unicode string + data_as_str = data_as_str.encode(encoding="utf-8") # type: ignore + except NameError: + pass + + return ET.fromstring(data_as_str) # nosec + except ET.ParseError as err: + # It might be because the server has an issue, and returned JSON with + # content-type XML.... + # So let's try a JSON load, and if it's still broken + # let's flow the initial exception + def _json_attemp(data): + try: + return True, json.loads(data) + except ValueError: + return False, None # Don't care about this one + + success, json_result = _json_attemp(data) + if success: + return json_result + # If i'm here, it's not JSON, it's not XML, let's scream + # and raise the last context in this block (the XML exception) + # The function hack is because Py2.7 messes up with exception + # context otherwise. + _LOGGER.critical("Wasn't XML not JSON, failing") + raise DeserializationError("XML is invalid") from err + elif content_type.startswith("text/"): + return data_as_str + raise DeserializationError("Cannot deserialize content-type: {}".format(content_type)) + + @classmethod + def deserialize_from_http_generics(cls, body_bytes: Optional[Union[AnyStr, IO]], headers: Mapping) -> Any: + """Deserialize from HTTP response. + + Use bytes and headers to NOT use any requests/aiohttp or whatever + specific implementation. + Headers will tested for "content-type" + + :param bytes body_bytes: The body of the response. + :param dict headers: The headers of the response. + :returns: The deserialized data. + :rtype: object + """ + # Try to use content-type from headers if available + content_type = None + if "content-type" in headers: + content_type = headers["content-type"].split(";")[0].strip().lower() + # Ouch, this server did not declare what it sent... + # Let's guess it's JSON... + # Also, since Autorest was considering that an empty body was a valid JSON, + # need that test as well.... + else: + content_type = "application/json" + + if body_bytes: + return cls.deserialize_from_text(body_bytes, content_type) + return None + + +_LOGGER = logging.getLogger(__name__) + +try: + _long_type = long # type: ignore +except NameError: + _long_type = int + +TZ_UTC = datetime.timezone.utc + +_FLATTEN = re.compile(r"(? None: + self.additional_properties: Optional[Dict[str, Any]] = {} + for k in kwargs: # pylint: disable=consider-using-dict-items + if k not in self._attribute_map: + _LOGGER.warning("%s is not a known attribute of class %s and will be ignored", k, self.__class__) + elif k in self._validation and self._validation[k].get("readonly", False): + _LOGGER.warning("Readonly attribute %s will be ignored in class %s", k, self.__class__) + else: + setattr(self, k, kwargs[k]) + + def __eq__(self, other: Any) -> bool: + """Compare objects by comparing all attributes. + + :param object other: The object to compare + :returns: True if objects are equal + :rtype: bool + """ + if isinstance(other, self.__class__): + return self.__dict__ == other.__dict__ + return False + + def __ne__(self, other: Any) -> bool: + """Compare objects by comparing all attributes. + + :param object other: The object to compare + :returns: True if objects are not equal + :rtype: bool + """ + return not self.__eq__(other) + + def __str__(self) -> str: + return str(self.__dict__) + + @classmethod + def enable_additional_properties_sending(cls) -> None: + cls._attribute_map["additional_properties"] = {"key": "", "type": "{object}"} + + @classmethod + def is_xml_model(cls) -> bool: + try: + cls._xml_map # type: ignore + except AttributeError: + return False + return True + + @classmethod + def _create_xml_node(cls): + """Create XML node. + + :returns: The XML node + :rtype: xml.etree.ElementTree.Element + """ + try: + xml_map = cls._xml_map # type: ignore + except AttributeError: + xml_map = {} + + return _create_xml_node(xml_map.get("name", cls.__name__), xml_map.get("prefix", None), xml_map.get("ns", None)) + + def serialize(self, keep_readonly: bool = False, **kwargs: Any) -> JSON: + """Return the JSON that would be sent to server from this model. + + This is an alias to `as_dict(full_restapi_key_transformer, keep_readonly=False)`. + + If you want XML serialization, you can pass the kwargs is_xml=True. + + :param bool keep_readonly: If you want to serialize the readonly attributes + :returns: A dict JSON compatible object + :rtype: dict + """ + serializer = Serializer(self._infer_class_models()) + return serializer._serialize( # type: ignore # pylint: disable=protected-access + self, keep_readonly=keep_readonly, **kwargs + ) + + def as_dict( + self, + keep_readonly: bool = True, + key_transformer: Callable[[str, Dict[str, Any], Any], Any] = attribute_transformer, + **kwargs: Any + ) -> JSON: + """Return a dict that can be serialized using json.dump. + + Advanced usage might optionally use a callback as parameter: + + .. code::python + + def my_key_transformer(key, attr_desc, value): + return key + + Key is the attribute name used in Python. Attr_desc + is a dict of metadata. Currently contains 'type' with the + msrest type and 'key' with the RestAPI encoded key. + Value is the current value in this object. + + The string returned will be used to serialize the key. + If the return type is a list, this is considered hierarchical + result dict. + + See the three examples in this file: + + - attribute_transformer + - full_restapi_key_transformer + - last_restapi_key_transformer + + If you want XML serialization, you can pass the kwargs is_xml=True. + + :param bool keep_readonly: If you want to serialize the readonly attributes + :param function key_transformer: A key transformer function. + :returns: A dict JSON compatible object + :rtype: dict + """ + serializer = Serializer(self._infer_class_models()) + return serializer._serialize( # type: ignore # pylint: disable=protected-access + self, key_transformer=key_transformer, keep_readonly=keep_readonly, **kwargs + ) + + @classmethod + def _infer_class_models(cls): + try: + str_models = cls.__module__.rsplit(".", 1)[0] + models = sys.modules[str_models] + client_models = {k: v for k, v in models.__dict__.items() if isinstance(v, type)} + if cls.__name__ not in client_models: + raise ValueError("Not Autorest generated code") + except Exception: # pylint: disable=broad-exception-caught + # Assume it's not Autorest generated (tests?). Add ourselves as dependencies. + client_models = {cls.__name__: cls} + return client_models + + @classmethod + def deserialize(cls, data: Any, content_type: Optional[str] = None) -> Self: + """Parse a str using the RestAPI syntax and return a model. + + :param str data: A str using RestAPI structure. JSON by default. + :param str content_type: JSON by default, set application/xml if XML. + :returns: An instance of this model + :raises DeserializationError: if something went wrong + :rtype: Self + """ + deserializer = Deserializer(cls._infer_class_models()) + return deserializer(cls.__name__, data, content_type=content_type) # type: ignore + + @classmethod + def from_dict( + cls, + data: Any, + key_extractors: Optional[Callable[[str, Dict[str, Any], Any], Any]] = None, + content_type: Optional[str] = None, + ) -> Self: + """Parse a dict using given key extractor return a model. + + By default consider key + extractors (rest_key_case_insensitive_extractor, attribute_key_case_insensitive_extractor + and last_rest_key_case_insensitive_extractor) + + :param dict data: A dict using RestAPI structure + :param function key_extractors: A key extractor function. + :param str content_type: JSON by default, set application/xml if XML. + :returns: An instance of this model + :raises DeserializationError: if something went wrong + :rtype: Self + """ + deserializer = Deserializer(cls._infer_class_models()) + deserializer.key_extractors = ( # type: ignore + [ # type: ignore + attribute_key_case_insensitive_extractor, + rest_key_case_insensitive_extractor, + last_rest_key_case_insensitive_extractor, + ] + if key_extractors is None + else key_extractors + ) + return deserializer(cls.__name__, data, content_type=content_type) # type: ignore + + @classmethod + def _flatten_subtype(cls, key, objects): + if "_subtype_map" not in cls.__dict__: + return {} + result = dict(cls._subtype_map[key]) + for valuetype in cls._subtype_map[key].values(): + result.update(objects[valuetype]._flatten_subtype(key, objects)) # pylint: disable=protected-access + return result + + @classmethod + def _classify(cls, response, objects): + """Check the class _subtype_map for any child classes. + We want to ignore any inherited _subtype_maps. + + :param dict response: The initial data + :param dict objects: The class objects + :returns: The class to be used + :rtype: class + """ + for subtype_key in cls.__dict__.get("_subtype_map", {}).keys(): + subtype_value = None + + if not isinstance(response, ET.Element): + rest_api_response_key = cls._get_rest_key_parts(subtype_key)[-1] + subtype_value = response.get(rest_api_response_key, None) or response.get(subtype_key, None) + else: + subtype_value = xml_key_extractor(subtype_key, cls._attribute_map[subtype_key], response) + if subtype_value: + # Try to match base class. Can be class name only + # (bug to fix in Autorest to support x-ms-discriminator-name) + if cls.__name__ == subtype_value: + return cls + flatten_mapping_type = cls._flatten_subtype(subtype_key, objects) + try: + return objects[flatten_mapping_type[subtype_value]] # type: ignore + except KeyError: + _LOGGER.warning( + "Subtype value %s has no mapping, use base class %s.", + subtype_value, + cls.__name__, + ) + break + else: + _LOGGER.warning("Discriminator %s is absent or null, use base class %s.", subtype_key, cls.__name__) + break + return cls + + @classmethod + def _get_rest_key_parts(cls, attr_key): + """Get the RestAPI key of this attr, split it and decode part + :param str attr_key: Attribute key must be in attribute_map. + :returns: A list of RestAPI part + :rtype: list + """ + rest_split_key = _FLATTEN.split(cls._attribute_map[attr_key]["key"]) + return [_decode_attribute_map_key(key_part) for key_part in rest_split_key] + + +def _decode_attribute_map_key(key): + """This decode a key in an _attribute_map to the actual key we want to look at + inside the received data. + + :param str key: A key string from the generated code + :returns: The decoded key + :rtype: str + """ + return key.replace("\\.", ".") + + +class Serializer: # pylint: disable=too-many-public-methods + """Request object model serializer.""" + + basic_types = {str: "str", int: "int", bool: "bool", float: "float"} + + _xml_basic_types_serializers = {"bool": lambda x: str(x).lower()} + days = {0: "Mon", 1: "Tue", 2: "Wed", 3: "Thu", 4: "Fri", 5: "Sat", 6: "Sun"} + months = { + 1: "Jan", + 2: "Feb", + 3: "Mar", + 4: "Apr", + 5: "May", + 6: "Jun", + 7: "Jul", + 8: "Aug", + 9: "Sep", + 10: "Oct", + 11: "Nov", + 12: "Dec", + } + validation = { + "min_length": lambda x, y: len(x) < y, + "max_length": lambda x, y: len(x) > y, + "minimum": lambda x, y: x < y, + "maximum": lambda x, y: x > y, + "minimum_ex": lambda x, y: x <= y, + "maximum_ex": lambda x, y: x >= y, + "min_items": lambda x, y: len(x) < y, + "max_items": lambda x, y: len(x) > y, + "pattern": lambda x, y: not re.match(y, x, re.UNICODE), + "unique": lambda x, y: len(x) != len(set(x)), + "multiple": lambda x, y: x % y != 0, + } + + def __init__(self, classes: Optional[Mapping[str, type]] = None) -> None: + self.serialize_type = { + "iso-8601": Serializer.serialize_iso, + "rfc-1123": Serializer.serialize_rfc, + "unix-time": Serializer.serialize_unix, + "duration": Serializer.serialize_duration, + "date": Serializer.serialize_date, + "time": Serializer.serialize_time, + "decimal": Serializer.serialize_decimal, + "long": Serializer.serialize_long, + "bytearray": Serializer.serialize_bytearray, + "base64": Serializer.serialize_base64, + "object": self.serialize_object, + "[]": self.serialize_iter, + "{}": self.serialize_dict, + } + self.dependencies: Dict[str, type] = dict(classes) if classes else {} + self.key_transformer = full_restapi_key_transformer + self.client_side_validation = True + + def _serialize( # pylint: disable=too-many-nested-blocks, too-many-branches, too-many-statements, too-many-locals + self, target_obj, data_type=None, **kwargs + ): + """Serialize data into a string according to type. + + :param object target_obj: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str, dict + :raises SerializationError: if serialization fails. + :returns: The serialized data. + """ + key_transformer = kwargs.get("key_transformer", self.key_transformer) + keep_readonly = kwargs.get("keep_readonly", False) + if target_obj is None: + return None + + attr_name = None + class_name = target_obj.__class__.__name__ + + if data_type: + return self.serialize_data(target_obj, data_type, **kwargs) + + if not hasattr(target_obj, "_attribute_map"): + data_type = type(target_obj).__name__ + if data_type in self.basic_types.values(): + return self.serialize_data(target_obj, data_type, **kwargs) + + # Force "is_xml" kwargs if we detect a XML model + try: + is_xml_model_serialization = kwargs["is_xml"] + except KeyError: + is_xml_model_serialization = kwargs.setdefault("is_xml", target_obj.is_xml_model()) + + serialized = {} + if is_xml_model_serialization: + serialized = target_obj._create_xml_node() # pylint: disable=protected-access + try: + attributes = target_obj._attribute_map # pylint: disable=protected-access + for attr, attr_desc in attributes.items(): + attr_name = attr + if not keep_readonly and target_obj._validation.get( # pylint: disable=protected-access + attr_name, {} + ).get("readonly", False): + continue + + if attr_name == "additional_properties" and attr_desc["key"] == "": + if target_obj.additional_properties is not None: + serialized.update(target_obj.additional_properties) + continue + try: + + orig_attr = getattr(target_obj, attr) + if is_xml_model_serialization: + pass # Don't provide "transformer" for XML for now. Keep "orig_attr" + else: # JSON + keys, orig_attr = key_transformer(attr, attr_desc.copy(), orig_attr) + keys = keys if isinstance(keys, list) else [keys] + + kwargs["serialization_ctxt"] = attr_desc + new_attr = self.serialize_data(orig_attr, attr_desc["type"], **kwargs) + + if is_xml_model_serialization: + xml_desc = attr_desc.get("xml", {}) + xml_name = xml_desc.get("name", attr_desc["key"]) + xml_prefix = xml_desc.get("prefix", None) + xml_ns = xml_desc.get("ns", None) + if xml_desc.get("attr", False): + if xml_ns: + ET.register_namespace(xml_prefix, xml_ns) + xml_name = "{{{}}}{}".format(xml_ns, xml_name) + serialized.set(xml_name, new_attr) # type: ignore + continue + if xml_desc.get("text", False): + serialized.text = new_attr # type: ignore + continue + if isinstance(new_attr, list): + serialized.extend(new_attr) # type: ignore + elif isinstance(new_attr, ET.Element): + # If the down XML has no XML/Name, + # we MUST replace the tag with the local tag. But keeping the namespaces. + if "name" not in getattr(orig_attr, "_xml_map", {}): + splitted_tag = new_attr.tag.split("}") + if len(splitted_tag) == 2: # Namespace + new_attr.tag = "}".join([splitted_tag[0], xml_name]) + else: + new_attr.tag = xml_name + serialized.append(new_attr) # type: ignore + else: # That's a basic type + # Integrate namespace if necessary + local_node = _create_xml_node(xml_name, xml_prefix, xml_ns) + local_node.text = str(new_attr) + serialized.append(local_node) # type: ignore + else: # JSON + for k in reversed(keys): # type: ignore + new_attr = {k: new_attr} + + _new_attr = new_attr + _serialized = serialized + for k in keys: # type: ignore + if k not in _serialized: + _serialized.update(_new_attr) # type: ignore + _new_attr = _new_attr[k] # type: ignore + _serialized = _serialized[k] + except ValueError as err: + if isinstance(err, SerializationError): + raise + + except (AttributeError, KeyError, TypeError) as err: + msg = "Attribute {} in object {} cannot be serialized.\n{}".format(attr_name, class_name, str(target_obj)) + raise SerializationError(msg) from err + return serialized + + def body(self, data, data_type, **kwargs): + """Serialize data intended for a request body. + + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: dict + :raises SerializationError: if serialization fails. + :raises ValueError: if data is None + :returns: The serialized request body + """ + + # Just in case this is a dict + internal_data_type_str = data_type.strip("[]{}") + internal_data_type = self.dependencies.get(internal_data_type_str, None) + try: + is_xml_model_serialization = kwargs["is_xml"] + except KeyError: + if internal_data_type and issubclass(internal_data_type, Model): + is_xml_model_serialization = kwargs.setdefault("is_xml", internal_data_type.is_xml_model()) + else: + is_xml_model_serialization = False + if internal_data_type and not isinstance(internal_data_type, Enum): + try: + deserializer = Deserializer(self.dependencies) + # Since it's on serialization, it's almost sure that format is not JSON REST + # We're not able to deal with additional properties for now. + deserializer.additional_properties_detection = False + if is_xml_model_serialization: + deserializer.key_extractors = [ # type: ignore + attribute_key_case_insensitive_extractor, + ] + else: + deserializer.key_extractors = [ + rest_key_case_insensitive_extractor, + attribute_key_case_insensitive_extractor, + last_rest_key_case_insensitive_extractor, + ] + data = deserializer._deserialize(data_type, data) # pylint: disable=protected-access + except DeserializationError as err: + raise SerializationError("Unable to build a model: " + str(err)) from err + + return self._serialize(data, data_type, **kwargs) + + def url(self, name, data, data_type, **kwargs): + """Serialize data intended for a URL path. + + :param str name: The name of the URL path parameter. + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str + :returns: The serialized URL path + :raises TypeError: if serialization fails. + :raises ValueError: if data is None + """ + try: + output = self.serialize_data(data, data_type, **kwargs) + if data_type == "bool": + output = json.dumps(output) + + if kwargs.get("skip_quote") is True: + output = str(output) + output = output.replace("{", quote("{")).replace("}", quote("}")) + else: + output = quote(str(output), safe="") + except SerializationError as exc: + raise TypeError("{} must be type {}.".format(name, data_type)) from exc + return output + + def query(self, name, data, data_type, **kwargs): + """Serialize data intended for a URL query. + + :param str name: The name of the query parameter. + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str, list + :raises TypeError: if serialization fails. + :raises ValueError: if data is None + :returns: The serialized query parameter + """ + try: + # Treat the list aside, since we don't want to encode the div separator + if data_type.startswith("["): + internal_data_type = data_type[1:-1] + do_quote = not kwargs.get("skip_quote", False) + return self.serialize_iter(data, internal_data_type, do_quote=do_quote, **kwargs) + + # Not a list, regular serialization + output = self.serialize_data(data, data_type, **kwargs) + if data_type == "bool": + output = json.dumps(output) + if kwargs.get("skip_quote") is True: + output = str(output) + else: + output = quote(str(output), safe="") + except SerializationError as exc: + raise TypeError("{} must be type {}.".format(name, data_type)) from exc + return str(output) + + def header(self, name, data, data_type, **kwargs): + """Serialize data intended for a request header. + + :param str name: The name of the header. + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str + :raises TypeError: if serialization fails. + :raises ValueError: if data is None + :returns: The serialized header + """ + try: + if data_type in ["[str]"]: + data = ["" if d is None else d for d in data] + + output = self.serialize_data(data, data_type, **kwargs) + if data_type == "bool": + output = json.dumps(output) + except SerializationError as exc: + raise TypeError("{} must be type {}.".format(name, data_type)) from exc + return str(output) + + def serialize_data(self, data, data_type, **kwargs): + """Serialize generic data according to supplied data type. + + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :raises AttributeError: if required data is None. + :raises ValueError: if data is None + :raises SerializationError: if serialization fails. + :returns: The serialized data. + :rtype: str, int, float, bool, dict, list + """ + if data is None: + raise ValueError("No value for given attribute") + + try: + if data is CoreNull: + return None + if data_type in self.basic_types.values(): + return self.serialize_basic(data, data_type, **kwargs) + + if data_type in self.serialize_type: + return self.serialize_type[data_type](data, **kwargs) + + # If dependencies is empty, try with current data class + # It has to be a subclass of Enum anyway + enum_type = self.dependencies.get(data_type, data.__class__) + if issubclass(enum_type, Enum): + return Serializer.serialize_enum(data, enum_obj=enum_type) + + iter_type = data_type[0] + data_type[-1] + if iter_type in self.serialize_type: + return self.serialize_type[iter_type](data, data_type[1:-1], **kwargs) + + except (ValueError, TypeError) as err: + msg = "Unable to serialize value: {!r} as type: {!r}." + raise SerializationError(msg.format(data, data_type)) from err + return self._serialize(data, **kwargs) + + @classmethod + def _get_custom_serializers(cls, data_type, **kwargs): # pylint: disable=inconsistent-return-statements + custom_serializer = kwargs.get("basic_types_serializers", {}).get(data_type) + if custom_serializer: + return custom_serializer + if kwargs.get("is_xml", False): + return cls._xml_basic_types_serializers.get(data_type) + + @classmethod + def serialize_basic(cls, data, data_type, **kwargs): + """Serialize basic builting data type. + Serializes objects to str, int, float or bool. + + Possible kwargs: + - basic_types_serializers dict[str, callable] : If set, use the callable as serializer + - is_xml bool : If set, use xml_basic_types_serializers + + :param obj data: Object to be serialized. + :param str data_type: Type of object in the iterable. + :rtype: str, int, float, bool + :return: serialized object + """ + custom_serializer = cls._get_custom_serializers(data_type, **kwargs) + if custom_serializer: + return custom_serializer(data) + if data_type == "str": + return cls.serialize_unicode(data) + return eval(data_type)(data) # nosec # pylint: disable=eval-used + + @classmethod + def serialize_unicode(cls, data): + """Special handling for serializing unicode strings in Py2. + Encode to UTF-8 if unicode, otherwise handle as a str. + + :param str data: Object to be serialized. + :rtype: str + :return: serialized object + """ + try: # If I received an enum, return its value + return data.value + except AttributeError: + pass + + try: + if isinstance(data, unicode): # type: ignore + # Don't change it, JSON and XML ElementTree are totally able + # to serialize correctly u'' strings + return data + except NameError: + return str(data) + return str(data) + + def serialize_iter(self, data, iter_type, div=None, **kwargs): + """Serialize iterable. + + Supported kwargs: + - serialization_ctxt dict : The current entry of _attribute_map, or same format. + serialization_ctxt['type'] should be same as data_type. + - is_xml bool : If set, serialize as XML + + :param list data: Object to be serialized. + :param str iter_type: Type of object in the iterable. + :param str div: If set, this str will be used to combine the elements + in the iterable into a combined string. Default is 'None'. + Defaults to False. + :rtype: list, str + :return: serialized iterable + """ + if isinstance(data, str): + raise SerializationError("Refuse str type as a valid iter type.") + + serialization_ctxt = kwargs.get("serialization_ctxt", {}) + is_xml = kwargs.get("is_xml", False) + + serialized = [] + for d in data: + try: + serialized.append(self.serialize_data(d, iter_type, **kwargs)) + except ValueError as err: + if isinstance(err, SerializationError): + raise + serialized.append(None) + + if kwargs.get("do_quote", False): + serialized = ["" if s is None else quote(str(s), safe="") for s in serialized] + + if div: + serialized = ["" if s is None else str(s) for s in serialized] + serialized = div.join(serialized) + + if "xml" in serialization_ctxt or is_xml: + # XML serialization is more complicated + xml_desc = serialization_ctxt.get("xml", {}) + xml_name = xml_desc.get("name") + if not xml_name: + xml_name = serialization_ctxt["key"] + + # Create a wrap node if necessary (use the fact that Element and list have "append") + is_wrapped = xml_desc.get("wrapped", False) + node_name = xml_desc.get("itemsName", xml_name) + if is_wrapped: + final_result = _create_xml_node(xml_name, xml_desc.get("prefix", None), xml_desc.get("ns", None)) + else: + final_result = [] + # All list elements to "local_node" + for el in serialized: + if isinstance(el, ET.Element): + el_node = el + else: + el_node = _create_xml_node(node_name, xml_desc.get("prefix", None), xml_desc.get("ns", None)) + if el is not None: # Otherwise it writes "None" :-p + el_node.text = str(el) + final_result.append(el_node) + return final_result + return serialized + + def serialize_dict(self, attr, dict_type, **kwargs): + """Serialize a dictionary of objects. + + :param dict attr: Object to be serialized. + :param str dict_type: Type of object in the dictionary. + :rtype: dict + :return: serialized dictionary + """ + serialization_ctxt = kwargs.get("serialization_ctxt", {}) + serialized = {} + for key, value in attr.items(): + try: + serialized[self.serialize_unicode(key)] = self.serialize_data(value, dict_type, **kwargs) + except ValueError as err: + if isinstance(err, SerializationError): + raise + serialized[self.serialize_unicode(key)] = None + + if "xml" in serialization_ctxt: + # XML serialization is more complicated + xml_desc = serialization_ctxt["xml"] + xml_name = xml_desc["name"] + + final_result = _create_xml_node(xml_name, xml_desc.get("prefix", None), xml_desc.get("ns", None)) + for key, value in serialized.items(): + ET.SubElement(final_result, key).text = value + return final_result + + return serialized + + def serialize_object(self, attr, **kwargs): # pylint: disable=too-many-return-statements + """Serialize a generic object. + This will be handled as a dictionary. If object passed in is not + a basic type (str, int, float, dict, list) it will simply be + cast to str. + + :param dict attr: Object to be serialized. + :rtype: dict or str + :return: serialized object + """ + if attr is None: + return None + if isinstance(attr, ET.Element): + return attr + obj_type = type(attr) + if obj_type in self.basic_types: + return self.serialize_basic(attr, self.basic_types[obj_type], **kwargs) + if obj_type is _long_type: + return self.serialize_long(attr) + if obj_type is str: + return self.serialize_unicode(attr) + if obj_type is datetime.datetime: + return self.serialize_iso(attr) + if obj_type is datetime.date: + return self.serialize_date(attr) + if obj_type is datetime.time: + return self.serialize_time(attr) + if obj_type is datetime.timedelta: + return self.serialize_duration(attr) + if obj_type is decimal.Decimal: + return self.serialize_decimal(attr) + + # If it's a model or I know this dependency, serialize as a Model + if obj_type in self.dependencies.values() or isinstance(attr, Model): + return self._serialize(attr) + + if obj_type == dict: + serialized = {} + for key, value in attr.items(): + try: + serialized[self.serialize_unicode(key)] = self.serialize_object(value, **kwargs) + except ValueError: + serialized[self.serialize_unicode(key)] = None + return serialized + + if obj_type == list: + serialized = [] + for obj in attr: + try: + serialized.append(self.serialize_object(obj, **kwargs)) + except ValueError: + pass + return serialized + return str(attr) + + @staticmethod + def serialize_enum(attr, enum_obj=None): + try: + result = attr.value + except AttributeError: + result = attr + try: + enum_obj(result) # type: ignore + return result + except ValueError as exc: + for enum_value in enum_obj: # type: ignore + if enum_value.value.lower() == str(attr).lower(): + return enum_value.value + error = "{!r} is not valid value for enum {!r}" + raise SerializationError(error.format(attr, enum_obj)) from exc + + @staticmethod + def serialize_bytearray(attr, **kwargs): # pylint: disable=unused-argument + """Serialize bytearray into base-64 string. + + :param str attr: Object to be serialized. + :rtype: str + :return: serialized base64 + """ + return b64encode(attr).decode() + + @staticmethod + def serialize_base64(attr, **kwargs): # pylint: disable=unused-argument + """Serialize str into base-64 string. + + :param str attr: Object to be serialized. + :rtype: str + :return: serialized base64 + """ + encoded = b64encode(attr).decode("ascii") + return encoded.strip("=").replace("+", "-").replace("/", "_") + + @staticmethod + def serialize_decimal(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Decimal object to float. + + :param decimal attr: Object to be serialized. + :rtype: float + :return: serialized decimal + """ + return float(attr) + + @staticmethod + def serialize_long(attr, **kwargs): # pylint: disable=unused-argument + """Serialize long (Py2) or int (Py3). + + :param int attr: Object to be serialized. + :rtype: int/long + :return: serialized long + """ + return _long_type(attr) + + @staticmethod + def serialize_date(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Date object into ISO-8601 formatted string. + + :param Date attr: Object to be serialized. + :rtype: str + :return: serialized date + """ + if isinstance(attr, str): + attr = isodate.parse_date(attr) + t = "{:04}-{:02}-{:02}".format(attr.year, attr.month, attr.day) + return t + + @staticmethod + def serialize_time(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Time object into ISO-8601 formatted string. + + :param datetime.time attr: Object to be serialized. + :rtype: str + :return: serialized time + """ + if isinstance(attr, str): + attr = isodate.parse_time(attr) + t = "{:02}:{:02}:{:02}".format(attr.hour, attr.minute, attr.second) + if attr.microsecond: + t += ".{:02}".format(attr.microsecond) + return t + + @staticmethod + def serialize_duration(attr, **kwargs): # pylint: disable=unused-argument + """Serialize TimeDelta object into ISO-8601 formatted string. + + :param TimeDelta attr: Object to be serialized. + :rtype: str + :return: serialized duration + """ + if isinstance(attr, str): + attr = isodate.parse_duration(attr) + return isodate.duration_isoformat(attr) + + @staticmethod + def serialize_rfc(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Datetime object into RFC-1123 formatted string. + + :param Datetime attr: Object to be serialized. + :rtype: str + :raises TypeError: if format invalid. + :return: serialized rfc + """ + try: + if not attr.tzinfo: + _LOGGER.warning("Datetime with no tzinfo will be considered UTC.") + utc = attr.utctimetuple() + except AttributeError as exc: + raise TypeError("RFC1123 object must be valid Datetime object.") from exc + + return "{}, {:02} {} {:04} {:02}:{:02}:{:02} GMT".format( + Serializer.days[utc.tm_wday], + utc.tm_mday, + Serializer.months[utc.tm_mon], + utc.tm_year, + utc.tm_hour, + utc.tm_min, + utc.tm_sec, + ) + + @staticmethod + def serialize_iso(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Datetime object into ISO-8601 formatted string. + + :param Datetime attr: Object to be serialized. + :rtype: str + :raises SerializationError: if format invalid. + :return: serialized iso + """ + if isinstance(attr, str): + attr = isodate.parse_datetime(attr) + try: + if not attr.tzinfo: + _LOGGER.warning("Datetime with no tzinfo will be considered UTC.") + utc = attr.utctimetuple() + if utc.tm_year > 9999 or utc.tm_year < 1: + raise OverflowError("Hit max or min date") + + microseconds = str(attr.microsecond).rjust(6, "0").rstrip("0").ljust(3, "0") + if microseconds: + microseconds = "." + microseconds + date = "{:04}-{:02}-{:02}T{:02}:{:02}:{:02}".format( + utc.tm_year, utc.tm_mon, utc.tm_mday, utc.tm_hour, utc.tm_min, utc.tm_sec + ) + return date + microseconds + "Z" + except (ValueError, OverflowError) as err: + msg = "Unable to serialize datetime object." + raise SerializationError(msg) from err + except AttributeError as err: + msg = "ISO-8601 object must be valid Datetime object." + raise TypeError(msg) from err + + @staticmethod + def serialize_unix(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Datetime object into IntTime format. + This is represented as seconds. + + :param Datetime attr: Object to be serialized. + :rtype: int + :raises SerializationError: if format invalid + :return: serialied unix + """ + if isinstance(attr, int): + return attr + try: + if not attr.tzinfo: + _LOGGER.warning("Datetime with no tzinfo will be considered UTC.") + return int(calendar.timegm(attr.utctimetuple())) + except AttributeError as exc: + raise TypeError("Unix time object must be valid Datetime object.") from exc + + +def rest_key_extractor(attr, attr_desc, data): # pylint: disable=unused-argument + key = attr_desc["key"] + working_data = data + + while "." in key: + # Need the cast, as for some reasons "split" is typed as list[str | Any] + dict_keys = cast(List[str], _FLATTEN.split(key)) + if len(dict_keys) == 1: + key = _decode_attribute_map_key(dict_keys[0]) + break + working_key = _decode_attribute_map_key(dict_keys[0]) + working_data = working_data.get(working_key, data) + if working_data is None: + # If at any point while following flatten JSON path see None, it means + # that all properties under are None as well + return None + key = ".".join(dict_keys[1:]) + + return working_data.get(key) + + +def rest_key_case_insensitive_extractor( # pylint: disable=unused-argument, inconsistent-return-statements + attr, attr_desc, data +): + key = attr_desc["key"] + working_data = data + + while "." in key: + dict_keys = _FLATTEN.split(key) + if len(dict_keys) == 1: + key = _decode_attribute_map_key(dict_keys[0]) + break + working_key = _decode_attribute_map_key(dict_keys[0]) + working_data = attribute_key_case_insensitive_extractor(working_key, None, working_data) + if working_data is None: + # If at any point while following flatten JSON path see None, it means + # that all properties under are None as well + return None + key = ".".join(dict_keys[1:]) + + if working_data: + return attribute_key_case_insensitive_extractor(key, None, working_data) + + +def last_rest_key_extractor(attr, attr_desc, data): # pylint: disable=unused-argument + """Extract the attribute in "data" based on the last part of the JSON path key. + + :param str attr: The attribute to extract + :param dict attr_desc: The attribute description + :param dict data: The data to extract from + :rtype: object + :returns: The extracted attribute + """ + key = attr_desc["key"] + dict_keys = _FLATTEN.split(key) + return attribute_key_extractor(dict_keys[-1], None, data) + + +def last_rest_key_case_insensitive_extractor(attr, attr_desc, data): # pylint: disable=unused-argument + """Extract the attribute in "data" based on the last part of the JSON path key. + + This is the case insensitive version of "last_rest_key_extractor" + :param str attr: The attribute to extract + :param dict attr_desc: The attribute description + :param dict data: The data to extract from + :rtype: object + :returns: The extracted attribute + """ + key = attr_desc["key"] + dict_keys = _FLATTEN.split(key) + return attribute_key_case_insensitive_extractor(dict_keys[-1], None, data) + + +def attribute_key_extractor(attr, _, data): + return data.get(attr) + + +def attribute_key_case_insensitive_extractor(attr, _, data): + found_key = None + lower_attr = attr.lower() + for key in data: + if lower_attr == key.lower(): + found_key = key + break + + return data.get(found_key) + + +def _extract_name_from_internal_type(internal_type): + """Given an internal type XML description, extract correct XML name with namespace. + + :param dict internal_type: An model type + :rtype: tuple + :returns: A tuple XML name + namespace dict + """ + internal_type_xml_map = getattr(internal_type, "_xml_map", {}) + xml_name = internal_type_xml_map.get("name", internal_type.__name__) + xml_ns = internal_type_xml_map.get("ns", None) + if xml_ns: + xml_name = "{{{}}}{}".format(xml_ns, xml_name) + return xml_name + + +def xml_key_extractor(attr, attr_desc, data): # pylint: disable=unused-argument,too-many-return-statements + if isinstance(data, dict): + return None + + # Test if this model is XML ready first + if not isinstance(data, ET.Element): + return None + + xml_desc = attr_desc.get("xml", {}) + xml_name = xml_desc.get("name", attr_desc["key"]) + + # Look for a children + is_iter_type = attr_desc["type"].startswith("[") + is_wrapped = xml_desc.get("wrapped", False) + internal_type = attr_desc.get("internalType", None) + internal_type_xml_map = getattr(internal_type, "_xml_map", {}) + + # Integrate namespace if necessary + xml_ns = xml_desc.get("ns", internal_type_xml_map.get("ns", None)) + if xml_ns: + xml_name = "{{{}}}{}".format(xml_ns, xml_name) + + # If it's an attribute, that's simple + if xml_desc.get("attr", False): + return data.get(xml_name) + + # If it's x-ms-text, that's simple too + if xml_desc.get("text", False): + return data.text + + # Scenario where I take the local name: + # - Wrapped node + # - Internal type is an enum (considered basic types) + # - Internal type has no XML/Name node + if is_wrapped or (internal_type and (issubclass(internal_type, Enum) or "name" not in internal_type_xml_map)): + children = data.findall(xml_name) + # If internal type has a local name and it's not a list, I use that name + elif not is_iter_type and internal_type and "name" in internal_type_xml_map: + xml_name = _extract_name_from_internal_type(internal_type) + children = data.findall(xml_name) + # That's an array + else: + if internal_type: # Complex type, ignore itemsName and use the complex type name + items_name = _extract_name_from_internal_type(internal_type) + else: + items_name = xml_desc.get("itemsName", xml_name) + children = data.findall(items_name) + + if len(children) == 0: + if is_iter_type: + if is_wrapped: + return None # is_wrapped no node, we want None + return [] # not wrapped, assume empty list + return None # Assume it's not there, maybe an optional node. + + # If is_iter_type and not wrapped, return all found children + if is_iter_type: + if not is_wrapped: + return children + # Iter and wrapped, should have found one node only (the wrap one) + if len(children) != 1: + raise DeserializationError( + "Tried to deserialize an array not wrapped, and found several nodes '{}'. Maybe you should declare this array as wrapped?".format( + xml_name + ) + ) + return list(children[0]) # Might be empty list and that's ok. + + # Here it's not a itertype, we should have found one element only or empty + if len(children) > 1: + raise DeserializationError("Find several XML '{}' where it was not expected".format(xml_name)) + return children[0] + + +class Deserializer: + """Response object model deserializer. + + :param dict classes: Class type dictionary for deserializing complex types. + :ivar list key_extractors: Ordered list of extractors to be used by this deserializer. + """ + + basic_types = {str: "str", int: "int", bool: "bool", float: "float"} + + valid_date = re.compile(r"\d{4}[-]\d{2}[-]\d{2}T\d{2}:\d{2}:\d{2}\.?\d*Z?[-+]?[\d{2}]?:?[\d{2}]?") + + def __init__(self, classes: Optional[Mapping[str, type]] = None) -> None: + self.deserialize_type = { + "iso-8601": Deserializer.deserialize_iso, + "rfc-1123": Deserializer.deserialize_rfc, + "unix-time": Deserializer.deserialize_unix, + "duration": Deserializer.deserialize_duration, + "date": Deserializer.deserialize_date, + "time": Deserializer.deserialize_time, + "decimal": Deserializer.deserialize_decimal, + "long": Deserializer.deserialize_long, + "bytearray": Deserializer.deserialize_bytearray, + "base64": Deserializer.deserialize_base64, + "object": self.deserialize_object, + "[]": self.deserialize_iter, + "{}": self.deserialize_dict, + } + self.deserialize_expected_types = { + "duration": (isodate.Duration, datetime.timedelta), + "iso-8601": (datetime.datetime), + } + self.dependencies: Dict[str, type] = dict(classes) if classes else {} + self.key_extractors = [rest_key_extractor, xml_key_extractor] + # Additional properties only works if the "rest_key_extractor" is used to + # extract the keys. Making it to work whatever the key extractor is too much + # complicated, with no real scenario for now. + # So adding a flag to disable additional properties detection. This flag should be + # used if your expect the deserialization to NOT come from a JSON REST syntax. + # Otherwise, result are unexpected + self.additional_properties_detection = True + + def __call__(self, target_obj, response_data, content_type=None): + """Call the deserializer to process a REST response. + + :param str target_obj: Target data type to deserialize to. + :param requests.Response response_data: REST response object. + :param str content_type: Swagger "produces" if available. + :raises DeserializationError: if deserialization fails. + :return: Deserialized object. + :rtype: object + """ + data = self._unpack_content(response_data, content_type) + return self._deserialize(target_obj, data) + + def _deserialize(self, target_obj, data): # pylint: disable=inconsistent-return-statements + """Call the deserializer on a model. + + Data needs to be already deserialized as JSON or XML ElementTree + + :param str target_obj: Target data type to deserialize to. + :param object data: Object to deserialize. + :raises DeserializationError: if deserialization fails. + :return: Deserialized object. + :rtype: object + """ + # This is already a model, go recursive just in case + if hasattr(data, "_attribute_map"): + constants = [name for name, config in getattr(data, "_validation", {}).items() if config.get("constant")] + try: + for attr, mapconfig in data._attribute_map.items(): # pylint: disable=protected-access + if attr in constants: + continue + value = getattr(data, attr) + if value is None: + continue + local_type = mapconfig["type"] + internal_data_type = local_type.strip("[]{}") + if internal_data_type not in self.dependencies or isinstance(internal_data_type, Enum): + continue + setattr(data, attr, self._deserialize(local_type, value)) + return data + except AttributeError: + return + + response, class_name = self._classify_target(target_obj, data) + + if isinstance(response, str): + return self.deserialize_data(data, response) + if isinstance(response, type) and issubclass(response, Enum): + return self.deserialize_enum(data, response) + + if data is None or data is CoreNull: + return data + try: + attributes = response._attribute_map # type: ignore # pylint: disable=protected-access + d_attrs = {} + for attr, attr_desc in attributes.items(): + # Check empty string. If it's not empty, someone has a real "additionalProperties"... + if attr == "additional_properties" and attr_desc["key"] == "": + continue + raw_value = None + # Enhance attr_desc with some dynamic data + attr_desc = attr_desc.copy() # Do a copy, do not change the real one + internal_data_type = attr_desc["type"].strip("[]{}") + if internal_data_type in self.dependencies: + attr_desc["internalType"] = self.dependencies[internal_data_type] + + for key_extractor in self.key_extractors: + found_value = key_extractor(attr, attr_desc, data) + if found_value is not None: + if raw_value is not None and raw_value != found_value: + msg = ( + "Ignoring extracted value '%s' from %s for key '%s'" + " (duplicate extraction, follow extractors order)" + ) + _LOGGER.warning(msg, found_value, key_extractor, attr) + continue + raw_value = found_value + + value = self.deserialize_data(raw_value, attr_desc["type"]) + d_attrs[attr] = value + except (AttributeError, TypeError, KeyError) as err: + msg = "Unable to deserialize to object: " + class_name # type: ignore + raise DeserializationError(msg) from err + additional_properties = self._build_additional_properties(attributes, data) + return self._instantiate_model(response, d_attrs, additional_properties) + + def _build_additional_properties(self, attribute_map, data): + if not self.additional_properties_detection: + return None + if "additional_properties" in attribute_map and attribute_map.get("additional_properties", {}).get("key") != "": + # Check empty string. If it's not empty, someone has a real "additionalProperties" + return None + if isinstance(data, ET.Element): + data = {el.tag: el.text for el in data} + + known_keys = { + _decode_attribute_map_key(_FLATTEN.split(desc["key"])[0]) + for desc in attribute_map.values() + if desc["key"] != "" + } + present_keys = set(data.keys()) + missing_keys = present_keys - known_keys + return {key: data[key] for key in missing_keys} + + def _classify_target(self, target, data): + """Check to see whether the deserialization target object can + be classified into a subclass. + Once classification has been determined, initialize object. + + :param str target: The target object type to deserialize to. + :param str/dict data: The response data to deserialize. + :return: The classified target object and its class name. + :rtype: tuple + """ + if target is None: + return None, None + + if isinstance(target, str): + try: + target = self.dependencies[target] + except KeyError: + return target, target + + try: + target = target._classify(data, self.dependencies) # type: ignore # pylint: disable=protected-access + except AttributeError: + pass # Target is not a Model, no classify + return target, target.__class__.__name__ # type: ignore + + def failsafe_deserialize(self, target_obj, data, content_type=None): + """Ignores any errors encountered in deserialization, + and falls back to not deserializing the object. Recommended + for use in error deserialization, as we want to return the + HttpResponseError to users, and not have them deal with + a deserialization error. + + :param str target_obj: The target object type to deserialize to. + :param str/dict data: The response data to deserialize. + :param str content_type: Swagger "produces" if available. + :return: Deserialized object. + :rtype: object + """ + try: + return self(target_obj, data, content_type=content_type) + except: # pylint: disable=bare-except + _LOGGER.debug( + "Ran into a deserialization error. Ignoring since this is failsafe deserialization", exc_info=True + ) + return None + + @staticmethod + def _unpack_content(raw_data, content_type=None): + """Extract the correct structure for deserialization. + + If raw_data is a PipelineResponse, try to extract the result of RawDeserializer. + if we can't, raise. Your Pipeline should have a RawDeserializer. + + If not a pipeline response and raw_data is bytes or string, use content-type + to decode it. If no content-type, try JSON. + + If raw_data is something else, bypass all logic and return it directly. + + :param obj raw_data: Data to be processed. + :param str content_type: How to parse if raw_data is a string/bytes. + :raises JSONDecodeError: If JSON is requested and parsing is impossible. + :raises UnicodeDecodeError: If bytes is not UTF8 + :rtype: object + :return: Unpacked content. + """ + # Assume this is enough to detect a Pipeline Response without importing it + context = getattr(raw_data, "context", {}) + if context: + if RawDeserializer.CONTEXT_NAME in context: + return context[RawDeserializer.CONTEXT_NAME] + raise ValueError("This pipeline didn't have the RawDeserializer policy; can't deserialize") + + # Assume this is enough to recognize universal_http.ClientResponse without importing it + if hasattr(raw_data, "body"): + return RawDeserializer.deserialize_from_http_generics(raw_data.text(), raw_data.headers) + + # Assume this enough to recognize requests.Response without importing it. + if hasattr(raw_data, "_content_consumed"): + return RawDeserializer.deserialize_from_http_generics(raw_data.text, raw_data.headers) + + if isinstance(raw_data, (str, bytes)) or hasattr(raw_data, "read"): + return RawDeserializer.deserialize_from_text(raw_data, content_type) # type: ignore + return raw_data + + def _instantiate_model(self, response, attrs, additional_properties=None): + """Instantiate a response model passing in deserialized args. + + :param Response response: The response model class. + :param dict attrs: The deserialized response attributes. + :param dict additional_properties: Additional properties to be set. + :rtype: Response + :return: The instantiated response model. + """ + if callable(response): + subtype = getattr(response, "_subtype_map", {}) + try: + readonly = [ + k + for k, v in response._validation.items() # pylint: disable=protected-access # type: ignore + if v.get("readonly") + ] + const = [ + k + for k, v in response._validation.items() # pylint: disable=protected-access # type: ignore + if v.get("constant") + ] + kwargs = {k: v for k, v in attrs.items() if k not in subtype and k not in readonly + const} + response_obj = response(**kwargs) + for attr in readonly: + setattr(response_obj, attr, attrs.get(attr)) + if additional_properties: + response_obj.additional_properties = additional_properties # type: ignore + return response_obj + except TypeError as err: + msg = "Unable to deserialize {} into model {}. ".format(kwargs, response) # type: ignore + raise DeserializationError(msg + str(err)) from err + else: + try: + for attr, value in attrs.items(): + setattr(response, attr, value) + return response + except Exception as exp: + msg = "Unable to populate response model. " + msg += "Type: {}, Error: {}".format(type(response), exp) + raise DeserializationError(msg) from exp + + def deserialize_data(self, data, data_type): # pylint: disable=too-many-return-statements + """Process data for deserialization according to data type. + + :param str data: The response string to be deserialized. + :param str data_type: The type to deserialize to. + :raises DeserializationError: if deserialization fails. + :return: Deserialized object. + :rtype: object + """ + if data is None: + return data + + try: + if not data_type: + return data + if data_type in self.basic_types.values(): + return self.deserialize_basic(data, data_type) + if data_type in self.deserialize_type: + if isinstance(data, self.deserialize_expected_types.get(data_type, tuple())): + return data + + is_a_text_parsing_type = lambda x: x not in [ # pylint: disable=unnecessary-lambda-assignment + "object", + "[]", + r"{}", + ] + if isinstance(data, ET.Element) and is_a_text_parsing_type(data_type) and not data.text: + return None + data_val = self.deserialize_type[data_type](data) + return data_val + + iter_type = data_type[0] + data_type[-1] + if iter_type in self.deserialize_type: + return self.deserialize_type[iter_type](data, data_type[1:-1]) + + obj_type = self.dependencies[data_type] + if issubclass(obj_type, Enum): + if isinstance(data, ET.Element): + data = data.text + return self.deserialize_enum(data, obj_type) + + except (ValueError, TypeError, AttributeError) as err: + msg = "Unable to deserialize response data." + msg += " Data: {}, {}".format(data, data_type) + raise DeserializationError(msg) from err + return self._deserialize(obj_type, data) + + def deserialize_iter(self, attr, iter_type): + """Deserialize an iterable. + + :param list attr: Iterable to be deserialized. + :param str iter_type: The type of object in the iterable. + :return: Deserialized iterable. + :rtype: list + """ + if attr is None: + return None + if isinstance(attr, ET.Element): # If I receive an element here, get the children + attr = list(attr) + if not isinstance(attr, (list, set)): + raise DeserializationError("Cannot deserialize as [{}] an object of type {}".format(iter_type, type(attr))) + return [self.deserialize_data(a, iter_type) for a in attr] + + def deserialize_dict(self, attr, dict_type): + """Deserialize a dictionary. + + :param dict/list attr: Dictionary to be deserialized. Also accepts + a list of key, value pairs. + :param str dict_type: The object type of the items in the dictionary. + :return: Deserialized dictionary. + :rtype: dict + """ + if isinstance(attr, list): + return {x["key"]: self.deserialize_data(x["value"], dict_type) for x in attr} + + if isinstance(attr, ET.Element): + # Transform value into {"Key": "value"} + attr = {el.tag: el.text for el in attr} + return {k: self.deserialize_data(v, dict_type) for k, v in attr.items()} + + def deserialize_object(self, attr, **kwargs): # pylint: disable=too-many-return-statements + """Deserialize a generic object. + This will be handled as a dictionary. + + :param dict attr: Dictionary to be deserialized. + :return: Deserialized object. + :rtype: dict + :raises TypeError: if non-builtin datatype encountered. + """ + if attr is None: + return None + if isinstance(attr, ET.Element): + # Do no recurse on XML, just return the tree as-is + return attr + if isinstance(attr, str): + return self.deserialize_basic(attr, "str") + obj_type = type(attr) + if obj_type in self.basic_types: + return self.deserialize_basic(attr, self.basic_types[obj_type]) + if obj_type is _long_type: + return self.deserialize_long(attr) + + if obj_type == dict: + deserialized = {} + for key, value in attr.items(): + try: + deserialized[key] = self.deserialize_object(value, **kwargs) + except ValueError: + deserialized[key] = None + return deserialized + + if obj_type == list: + deserialized = [] + for obj in attr: + try: + deserialized.append(self.deserialize_object(obj, **kwargs)) + except ValueError: + pass + return deserialized + + error = "Cannot deserialize generic object with type: " + raise TypeError(error + str(obj_type)) + + def deserialize_basic(self, attr, data_type): # pylint: disable=too-many-return-statements + """Deserialize basic builtin data type from string. + Will attempt to convert to str, int, float and bool. + This function will also accept '1', '0', 'true' and 'false' as + valid bool values. + + :param str attr: response string to be deserialized. + :param str data_type: deserialization data type. + :return: Deserialized basic type. + :rtype: str, int, float or bool + :raises TypeError: if string format is not valid. + """ + # If we're here, data is supposed to be a basic type. + # If it's still an XML node, take the text + if isinstance(attr, ET.Element): + attr = attr.text + if not attr: + if data_type == "str": + # None or '', node is empty string. + return "" + # None or '', node with a strong type is None. + # Don't try to model "empty bool" or "empty int" + return None + + if data_type == "bool": + if attr in [True, False, 1, 0]: + return bool(attr) + if isinstance(attr, str): + if attr.lower() in ["true", "1"]: + return True + if attr.lower() in ["false", "0"]: + return False + raise TypeError("Invalid boolean value: {}".format(attr)) + + if data_type == "str": + return self.deserialize_unicode(attr) + return eval(data_type)(attr) # nosec # pylint: disable=eval-used + + @staticmethod + def deserialize_unicode(data): + """Preserve unicode objects in Python 2, otherwise return data + as a string. + + :param str data: response string to be deserialized. + :return: Deserialized string. + :rtype: str or unicode + """ + # We might be here because we have an enum modeled as string, + # and we try to deserialize a partial dict with enum inside + if isinstance(data, Enum): + return data + + # Consider this is real string + try: + if isinstance(data, unicode): # type: ignore + return data + except NameError: + return str(data) + return str(data) + + @staticmethod + def deserialize_enum(data, enum_obj): + """Deserialize string into enum object. + + If the string is not a valid enum value it will be returned as-is + and a warning will be logged. + + :param str data: Response string to be deserialized. If this value is + None or invalid it will be returned as-is. + :param Enum enum_obj: Enum object to deserialize to. + :return: Deserialized enum object. + :rtype: Enum + """ + if isinstance(data, enum_obj) or data is None: + return data + if isinstance(data, Enum): + data = data.value + if isinstance(data, int): + # Workaround. We might consider remove it in the future. + try: + return list(enum_obj.__members__.values())[data] + except IndexError as exc: + error = "{!r} is not a valid index for enum {!r}" + raise DeserializationError(error.format(data, enum_obj)) from exc + try: + return enum_obj(str(data)) + except ValueError: + for enum_value in enum_obj: + if enum_value.value.lower() == str(data).lower(): + return enum_value + # We don't fail anymore for unknown value, we deserialize as a string + _LOGGER.warning("Deserializer is not able to find %s as valid enum in %s", data, enum_obj) + return Deserializer.deserialize_unicode(data) + + @staticmethod + def deserialize_bytearray(attr): + """Deserialize string into bytearray. + + :param str attr: response string to be deserialized. + :return: Deserialized bytearray + :rtype: bytearray + :raises TypeError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + return bytearray(b64decode(attr)) # type: ignore + + @staticmethod + def deserialize_base64(attr): + """Deserialize base64 encoded string into string. + + :param str attr: response string to be deserialized. + :return: Deserialized base64 string + :rtype: bytearray + :raises TypeError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + padding = "=" * (3 - (len(attr) + 3) % 4) # type: ignore + attr = attr + padding # type: ignore + encoded = attr.replace("-", "+").replace("_", "/") + return b64decode(encoded) + + @staticmethod + def deserialize_decimal(attr): + """Deserialize string into Decimal object. + + :param str attr: response string to be deserialized. + :return: Deserialized decimal + :raises DeserializationError: if string format invalid. + :rtype: decimal + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + return decimal.Decimal(str(attr)) # type: ignore + except decimal.DecimalException as err: + msg = "Invalid decimal {}".format(attr) + raise DeserializationError(msg) from err + + @staticmethod + def deserialize_long(attr): + """Deserialize string into long (Py2) or int (Py3). + + :param str attr: response string to be deserialized. + :return: Deserialized int + :rtype: long or int + :raises ValueError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + return _long_type(attr) # type: ignore + + @staticmethod + def deserialize_duration(attr): + """Deserialize ISO-8601 formatted string into TimeDelta object. + + :param str attr: response string to be deserialized. + :return: Deserialized duration + :rtype: TimeDelta + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + duration = isodate.parse_duration(attr) + except (ValueError, OverflowError, AttributeError) as err: + msg = "Cannot deserialize duration object." + raise DeserializationError(msg) from err + return duration + + @staticmethod + def deserialize_date(attr): + """Deserialize ISO-8601 formatted string into Date object. + + :param str attr: response string to be deserialized. + :return: Deserialized date + :rtype: Date + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + if re.search(r"[^\W\d_]", attr, re.I + re.U): # type: ignore + raise DeserializationError("Date must have only digits and -. Received: %s" % attr) + # This must NOT use defaultmonth/defaultday. Using None ensure this raises an exception. + return isodate.parse_date(attr, defaultmonth=0, defaultday=0) + + @staticmethod + def deserialize_time(attr): + """Deserialize ISO-8601 formatted string into time object. + + :param str attr: response string to be deserialized. + :return: Deserialized time + :rtype: datetime.time + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + if re.search(r"[^\W\d_]", attr, re.I + re.U): # type: ignore + raise DeserializationError("Date must have only digits and -. Received: %s" % attr) + return isodate.parse_time(attr) + + @staticmethod + def deserialize_rfc(attr): + """Deserialize RFC-1123 formatted string into Datetime object. + + :param str attr: response string to be deserialized. + :return: Deserialized RFC datetime + :rtype: Datetime + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + parsed_date = email.utils.parsedate_tz(attr) # type: ignore + date_obj = datetime.datetime( + *parsed_date[:6], tzinfo=datetime.timezone(datetime.timedelta(minutes=(parsed_date[9] or 0) / 60)) + ) + if not date_obj.tzinfo: + date_obj = date_obj.astimezone(tz=TZ_UTC) + except ValueError as err: + msg = "Cannot deserialize to rfc datetime object." + raise DeserializationError(msg) from err + return date_obj + + @staticmethod + def deserialize_iso(attr): + """Deserialize ISO-8601 formatted string into Datetime object. + + :param str attr: response string to be deserialized. + :return: Deserialized ISO datetime + :rtype: Datetime + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + attr = attr.upper() # type: ignore + match = Deserializer.valid_date.match(attr) + if not match: + raise ValueError("Invalid datetime string: " + attr) + + check_decimal = attr.split(".") + if len(check_decimal) > 1: + decimal_str = "" + for digit in check_decimal[1]: + if digit.isdigit(): + decimal_str += digit + else: + break + if len(decimal_str) > 6: + attr = attr.replace(decimal_str, decimal_str[0:6]) + + date_obj = isodate.parse_datetime(attr) + test_utc = date_obj.utctimetuple() + if test_utc.tm_year > 9999 or test_utc.tm_year < 1: + raise OverflowError("Hit max or min date") + except (ValueError, OverflowError, AttributeError) as err: + msg = "Cannot deserialize datetime object." + raise DeserializationError(msg) from err + return date_obj + + @staticmethod + def deserialize_unix(attr): + """Serialize Datetime object into IntTime format. + This is represented as seconds. + + :param int attr: Object to be serialized. + :return: Deserialized datetime + :rtype: Datetime + :raises DeserializationError: if format invalid + """ + if isinstance(attr, ET.Element): + attr = int(attr.text) # type: ignore + try: + attr = int(attr) + date_obj = datetime.datetime.fromtimestamp(attr, TZ_UTC) + except ValueError as err: + msg = "Cannot deserialize to unix datetime object." + raise DeserializationError(msg) from err + return date_obj diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/XmsErrorResponseVersionTolerant/xmserrorresponseversiontolerant/aio/_client.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/XmsErrorResponseVersionTolerant/xmserrorresponseversiontolerant/aio/_client.py index 38e6f003747..6439a621e8c 100644 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/XmsErrorResponseVersionTolerant/xmserrorresponseversiontolerant/aio/_client.py +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/XmsErrorResponseVersionTolerant/xmserrorresponseversiontolerant/aio/_client.py @@ -14,7 +14,7 @@ from azure.core.pipeline import policies from azure.core.rest import AsyncHttpResponse, HttpRequest -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import XMSErrorResponseExtensionsConfiguration from .operations import PetOperations diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/XmsErrorResponseVersionTolerant/xmserrorresponseversiontolerant/aio/operations/_operations.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/XmsErrorResponseVersionTolerant/xmserrorresponseversiontolerant/aio/operations/_operations.py index a730123be82..a66676c2824 100644 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/XmsErrorResponseVersionTolerant/xmserrorresponseversiontolerant/aio/operations/_operations.py +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/XmsErrorResponseVersionTolerant/xmserrorresponseversiontolerant/aio/operations/_operations.py @@ -21,7 +21,7 @@ from azure.core.rest import AsyncHttpResponse, HttpRequest from azure.core.tracing.decorator_async import distributed_trace_async -from ..._serialization import Deserializer, Serializer +from ..._utils.serialization import Deserializer, Serializer from ...operations._operations import ( build_pet_do_something_request, build_pet_get_pet_by_id_request, diff --git a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/XmsErrorResponseVersionTolerant/xmserrorresponseversiontolerant/operations/_operations.py b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/XmsErrorResponseVersionTolerant/xmserrorresponseversiontolerant/operations/_operations.py index 83a1e28a3fd..00a1d5f2ede 100644 --- a/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/XmsErrorResponseVersionTolerant/xmserrorresponseversiontolerant/operations/_operations.py +++ b/packages/autorest.python/test/vanilla/version-tolerant/Expected/AcceptanceTests/XmsErrorResponseVersionTolerant/xmserrorresponseversiontolerant/operations/_operations.py @@ -23,7 +23,7 @@ from azure.core.utils import case_insensitive_dict from .._configuration import XMSErrorResponseExtensionsConfiguration -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer JSON = MutableMapping[str, Any] T = TypeVar("T") diff --git a/packages/autorest.python/test/vanilla/version-tolerant/tox.ini b/packages/autorest.python/test/vanilla/version-tolerant/tox.ini index 19af4d2abbc..39601b040e9 100644 --- a/packages/autorest.python/test/vanilla/version-tolerant/tox.ini +++ b/packages/autorest.python/test/vanilla/version-tolerant/tox.ini @@ -8,7 +8,7 @@ deps= -r requirements.txt -r ../../../../../eng/dev_requirements.txt commands= - pytest --cov=Expected + pytest [testenv:lint] deps= @@ -28,7 +28,7 @@ commands = [testenv:ci] commands = - pytest --cov=Expected AcceptanceTests + pytest AcceptanceTests [testenv:apiview] commands = diff --git a/packages/typespec-python/package.json b/packages/typespec-python/package.json index 613ef45ccad..2cf1ffc8914 100644 --- a/packages/typespec-python/package.json +++ b/packages/typespec-python/package.json @@ -64,7 +64,7 @@ "js-yaml": "~4.1.0", "semver": "~7.6.2", "tsx": "~4.19.1", - "@typespec/http-client-python": "~0.11.0", + "@typespec/http-client-python": "~0.11.1", "fs-extra": "~11.2.0" }, "devDependencies": { diff --git a/packages/typespec-python/test/azure/generated/authentication-api-key/authentication/apikey/_client.py b/packages/typespec-python/test/azure/generated/authentication-api-key/authentication/apikey/_client.py index 3620dab0989..f17fdc3a1fe 100644 --- a/packages/typespec-python/test/azure/generated/authentication-api-key/authentication/apikey/_client.py +++ b/packages/typespec-python/test/azure/generated/authentication-api-key/authentication/apikey/_client.py @@ -17,7 +17,7 @@ from ._configuration import ApiKeyClientConfiguration from ._operations import ApiKeyClientOperationsMixin -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer class ApiKeyClient(ApiKeyClientOperationsMixin): # pylint: disable=client-accepts-api-version-keyword diff --git a/packages/typespec-python/test/azure/generated/authentication-api-key/authentication/apikey/_operations/_operations.py b/packages/typespec-python/test/azure/generated/authentication-api-key/authentication/apikey/_operations/_operations.py index 356bf602ae2..204f90b071d 100644 --- a/packages/typespec-python/test/azure/generated/authentication-api-key/authentication/apikey/_operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/authentication-api-key/authentication/apikey/_operations/_operations.py @@ -8,6 +8,7 @@ from collections.abc import MutableMapping from typing import Any, Callable, Dict, Optional, TypeVar +from azure.core import PipelineClient from azure.core.exceptions import ( ClientAuthenticationError, HttpResponseError, @@ -22,9 +23,10 @@ from azure.core.utils import case_insensitive_dict from .. import models as _models -from .._model_base import _failsafe_deserialize -from .._serialization import Serializer -from .._vendor import ApiKeyClientMixinABC +from .._configuration import ApiKeyClientConfiguration +from .._utils.model_base import _failsafe_deserialize +from .._utils.serialization import Serializer +from .._utils.utils import ClientMixinABC T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] @@ -54,7 +56,7 @@ def build_api_key_invalid_request(**kwargs: Any) -> HttpRequest: return HttpRequest(method="GET", url=_url, headers=_headers, **kwargs) -class ApiKeyClientOperationsMixin(ApiKeyClientMixinABC): +class ApiKeyClientOperationsMixin(ClientMixinABC[PipelineClient, ApiKeyClientConfiguration]): @distributed_trace def valid(self, **kwargs: Any) -> None: # pylint: disable=inconsistent-return-statements diff --git a/packages/typespec-python/test/azure/generated/authentication-api-key/authentication/apikey/_utils/__init__.py b/packages/typespec-python/test/azure/generated/authentication-api-key/authentication/apikey/_utils/__init__.py new file mode 100644 index 00000000000..8026245c2ab --- /dev/null +++ b/packages/typespec-python/test/azure/generated/authentication-api-key/authentication/apikey/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) Python Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/typespec-python/test/azure/generated/authentication-api-key/authentication/apikey/_model_base.py b/packages/typespec-python/test/azure/generated/authentication-api-key/authentication/apikey/_utils/model_base.py similarity index 100% rename from packages/typespec-python/test/azure/generated/authentication-api-key/authentication/apikey/_model_base.py rename to packages/typespec-python/test/azure/generated/authentication-api-key/authentication/apikey/_utils/model_base.py diff --git a/packages/typespec-python/test/azure/generated/authentication-api-key/authentication/apikey/_serialization.py b/packages/typespec-python/test/azure/generated/authentication-api-key/authentication/apikey/_utils/serialization.py similarity index 100% rename from packages/typespec-python/test/azure/generated/authentication-api-key/authentication/apikey/_serialization.py rename to packages/typespec-python/test/azure/generated/authentication-api-key/authentication/apikey/_utils/serialization.py diff --git a/packages/typespec-python/test/azure/generated/authentication-api-key/authentication/apikey/_utils/utils.py b/packages/typespec-python/test/azure/generated/authentication-api-key/authentication/apikey/_utils/utils.py new file mode 100644 index 00000000000..35c9c836f85 --- /dev/null +++ b/packages/typespec-python/test/azure/generated/authentication-api-key/authentication/apikey/_utils/utils.py @@ -0,0 +1,25 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) Python Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from abc import ABC +from typing import Generic, TYPE_CHECKING, TypeVar + +if TYPE_CHECKING: + from .serialization import Deserializer, Serializer + + +TClient = TypeVar("TClient") +TConfig = TypeVar("TConfig") + + +class ClientMixinABC(ABC, Generic[TClient, TConfig]): + """DO NOT use this class. It is for internal typing use only.""" + + _client: TClient + _config: TConfig + _serialize: "Serializer" + _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/azure/generated/authentication-api-key/authentication/apikey/_vendor.py b/packages/typespec-python/test/azure/generated/authentication-api-key/authentication/apikey/_vendor.py deleted file mode 100644 index b99f7ccffbc..00000000000 --- a/packages/typespec-python/test/azure/generated/authentication-api-key/authentication/apikey/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) Python Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import ApiKeyClientConfiguration - -if TYPE_CHECKING: - from azure.core import PipelineClient - - from ._serialization import Deserializer, Serializer - - -class ApiKeyClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "PipelineClient" - _config: ApiKeyClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/azure/generated/authentication-api-key/authentication/apikey/aio/_client.py b/packages/typespec-python/test/azure/generated/authentication-api-key/authentication/apikey/aio/_client.py index 9bcb3550412..c2f27568d35 100644 --- a/packages/typespec-python/test/azure/generated/authentication-api-key/authentication/apikey/aio/_client.py +++ b/packages/typespec-python/test/azure/generated/authentication-api-key/authentication/apikey/aio/_client.py @@ -15,7 +15,7 @@ from azure.core.pipeline import policies from azure.core.rest import AsyncHttpResponse, HttpRequest -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import ApiKeyClientConfiguration from ._operations import ApiKeyClientOperationsMixin diff --git a/packages/typespec-python/test/azure/generated/authentication-api-key/authentication/apikey/aio/_operations/_operations.py b/packages/typespec-python/test/azure/generated/authentication-api-key/authentication/apikey/aio/_operations/_operations.py index 3d3afa4089c..1f005c666aa 100644 --- a/packages/typespec-python/test/azure/generated/authentication-api-key/authentication/apikey/aio/_operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/authentication-api-key/authentication/apikey/aio/_operations/_operations.py @@ -9,6 +9,7 @@ from collections.abc import MutableMapping from typing import Any, Callable, Dict, Optional, TypeVar +from azure.core import AsyncPipelineClient from azure.core.exceptions import ( ClientAuthenticationError, HttpResponseError, @@ -22,15 +23,16 @@ from azure.core.tracing.decorator_async import distributed_trace_async from ... import models as _models -from ..._model_base import _failsafe_deserialize from ..._operations._operations import build_api_key_invalid_request, build_api_key_valid_request -from .._vendor import ApiKeyClientMixinABC +from ..._utils.model_base import _failsafe_deserialize +from ..._utils.utils import ClientMixinABC +from .._configuration import ApiKeyClientConfiguration T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, AsyncHttpResponse], T, Dict[str, Any]], Any]] -class ApiKeyClientOperationsMixin(ApiKeyClientMixinABC): +class ApiKeyClientOperationsMixin(ClientMixinABC[AsyncPipelineClient, ApiKeyClientConfiguration]): @distributed_trace_async async def valid(self, **kwargs: Any) -> None: diff --git a/packages/typespec-python/test/azure/generated/authentication-api-key/authentication/apikey/aio/_vendor.py b/packages/typespec-python/test/azure/generated/authentication-api-key/authentication/apikey/aio/_vendor.py deleted file mode 100644 index 4340164b26b..00000000000 --- a/packages/typespec-python/test/azure/generated/authentication-api-key/authentication/apikey/aio/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) Python Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import ApiKeyClientConfiguration - -if TYPE_CHECKING: - from azure.core import AsyncPipelineClient - - from .._serialization import Deserializer, Serializer - - -class ApiKeyClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "AsyncPipelineClient" - _config: ApiKeyClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/azure/generated/authentication-api-key/authentication/apikey/models/_models.py b/packages/typespec-python/test/azure/generated/authentication-api-key/authentication/apikey/models/_models.py index 724a4800fa7..b695706d2dd 100644 --- a/packages/typespec-python/test/azure/generated/authentication-api-key/authentication/apikey/models/_models.py +++ b/packages/typespec-python/test/azure/generated/authentication-api-key/authentication/apikey/models/_models.py @@ -9,11 +9,10 @@ from typing import Any, Mapping, overload -from .. import _model_base -from .._model_base import rest_field +from .._utils.model_base import Model as _Model, rest_field -class InvalidAuth(_model_base.Model): +class InvalidAuth(_Model): """InvalidAuth. :ivar error: Required. diff --git a/packages/typespec-python/test/azure/generated/authentication-http-custom/authentication/http/custom/_client.py b/packages/typespec-python/test/azure/generated/authentication-http-custom/authentication/http/custom/_client.py index dd5e2eb2448..e245d57e48b 100644 --- a/packages/typespec-python/test/azure/generated/authentication-http-custom/authentication/http/custom/_client.py +++ b/packages/typespec-python/test/azure/generated/authentication-http-custom/authentication/http/custom/_client.py @@ -17,7 +17,7 @@ from ._configuration import CustomClientConfiguration from ._operations import CustomClientOperationsMixin -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer class CustomClient(CustomClientOperationsMixin): # pylint: disable=client-accepts-api-version-keyword diff --git a/packages/typespec-python/test/azure/generated/authentication-http-custom/authentication/http/custom/_operations/_operations.py b/packages/typespec-python/test/azure/generated/authentication-http-custom/authentication/http/custom/_operations/_operations.py index cf2b1f36cf3..b0f4a82b28f 100644 --- a/packages/typespec-python/test/azure/generated/authentication-http-custom/authentication/http/custom/_operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/authentication-http-custom/authentication/http/custom/_operations/_operations.py @@ -8,6 +8,7 @@ from collections.abc import MutableMapping from typing import Any, Callable, Dict, Optional, TypeVar +from azure.core import PipelineClient from azure.core.exceptions import ( ClientAuthenticationError, HttpResponseError, @@ -22,9 +23,10 @@ from azure.core.utils import case_insensitive_dict from .. import models as _models -from .._model_base import _failsafe_deserialize -from .._serialization import Serializer -from .._vendor import CustomClientMixinABC +from .._configuration import CustomClientConfiguration +from .._utils.model_base import _failsafe_deserialize +from .._utils.serialization import Serializer +from .._utils.utils import ClientMixinABC T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] @@ -54,7 +56,7 @@ def build_custom_invalid_request(**kwargs: Any) -> HttpRequest: return HttpRequest(method="GET", url=_url, headers=_headers, **kwargs) -class CustomClientOperationsMixin(CustomClientMixinABC): +class CustomClientOperationsMixin(ClientMixinABC[PipelineClient, CustomClientConfiguration]): @distributed_trace def valid(self, **kwargs: Any) -> None: # pylint: disable=inconsistent-return-statements diff --git a/packages/typespec-python/test/azure/generated/authentication-http-custom/authentication/http/custom/_utils/__init__.py b/packages/typespec-python/test/azure/generated/authentication-http-custom/authentication/http/custom/_utils/__init__.py new file mode 100644 index 00000000000..8026245c2ab --- /dev/null +++ b/packages/typespec-python/test/azure/generated/authentication-http-custom/authentication/http/custom/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) Python Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/typespec-python/test/azure/generated/authentication-http-custom/authentication/http/custom/_model_base.py b/packages/typespec-python/test/azure/generated/authentication-http-custom/authentication/http/custom/_utils/model_base.py similarity index 100% rename from packages/typespec-python/test/azure/generated/authentication-http-custom/authentication/http/custom/_model_base.py rename to packages/typespec-python/test/azure/generated/authentication-http-custom/authentication/http/custom/_utils/model_base.py diff --git a/packages/typespec-python/test/azure/generated/authentication-http-custom/authentication/http/custom/_serialization.py b/packages/typespec-python/test/azure/generated/authentication-http-custom/authentication/http/custom/_utils/serialization.py similarity index 100% rename from packages/typespec-python/test/azure/generated/authentication-http-custom/authentication/http/custom/_serialization.py rename to packages/typespec-python/test/azure/generated/authentication-http-custom/authentication/http/custom/_utils/serialization.py diff --git a/packages/typespec-python/test/azure/generated/authentication-http-custom/authentication/http/custom/_utils/utils.py b/packages/typespec-python/test/azure/generated/authentication-http-custom/authentication/http/custom/_utils/utils.py new file mode 100644 index 00000000000..35c9c836f85 --- /dev/null +++ b/packages/typespec-python/test/azure/generated/authentication-http-custom/authentication/http/custom/_utils/utils.py @@ -0,0 +1,25 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) Python Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from abc import ABC +from typing import Generic, TYPE_CHECKING, TypeVar + +if TYPE_CHECKING: + from .serialization import Deserializer, Serializer + + +TClient = TypeVar("TClient") +TConfig = TypeVar("TConfig") + + +class ClientMixinABC(ABC, Generic[TClient, TConfig]): + """DO NOT use this class. It is for internal typing use only.""" + + _client: TClient + _config: TConfig + _serialize: "Serializer" + _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/azure/generated/authentication-http-custom/authentication/http/custom/_vendor.py b/packages/typespec-python/test/azure/generated/authentication-http-custom/authentication/http/custom/_vendor.py deleted file mode 100644 index ca3074f75b4..00000000000 --- a/packages/typespec-python/test/azure/generated/authentication-http-custom/authentication/http/custom/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) Python Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import CustomClientConfiguration - -if TYPE_CHECKING: - from azure.core import PipelineClient - - from ._serialization import Deserializer, Serializer - - -class CustomClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "PipelineClient" - _config: CustomClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/azure/generated/authentication-http-custom/authentication/http/custom/aio/_client.py b/packages/typespec-python/test/azure/generated/authentication-http-custom/authentication/http/custom/aio/_client.py index d7bb66cc353..1b8498f1ae4 100644 --- a/packages/typespec-python/test/azure/generated/authentication-http-custom/authentication/http/custom/aio/_client.py +++ b/packages/typespec-python/test/azure/generated/authentication-http-custom/authentication/http/custom/aio/_client.py @@ -15,7 +15,7 @@ from azure.core.pipeline import policies from azure.core.rest import AsyncHttpResponse, HttpRequest -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import CustomClientConfiguration from ._operations import CustomClientOperationsMixin diff --git a/packages/typespec-python/test/azure/generated/authentication-http-custom/authentication/http/custom/aio/_operations/_operations.py b/packages/typespec-python/test/azure/generated/authentication-http-custom/authentication/http/custom/aio/_operations/_operations.py index e52c442ac76..6caf04a8e44 100644 --- a/packages/typespec-python/test/azure/generated/authentication-http-custom/authentication/http/custom/aio/_operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/authentication-http-custom/authentication/http/custom/aio/_operations/_operations.py @@ -9,6 +9,7 @@ from collections.abc import MutableMapping from typing import Any, Callable, Dict, Optional, TypeVar +from azure.core import AsyncPipelineClient from azure.core.exceptions import ( ClientAuthenticationError, HttpResponseError, @@ -22,15 +23,16 @@ from azure.core.tracing.decorator_async import distributed_trace_async from ... import models as _models -from ..._model_base import _failsafe_deserialize from ..._operations._operations import build_custom_invalid_request, build_custom_valid_request -from .._vendor import CustomClientMixinABC +from ..._utils.model_base import _failsafe_deserialize +from ..._utils.utils import ClientMixinABC +from .._configuration import CustomClientConfiguration T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, AsyncHttpResponse], T, Dict[str, Any]], Any]] -class CustomClientOperationsMixin(CustomClientMixinABC): +class CustomClientOperationsMixin(ClientMixinABC[AsyncPipelineClient, CustomClientConfiguration]): @distributed_trace_async async def valid(self, **kwargs: Any) -> None: diff --git a/packages/typespec-python/test/azure/generated/authentication-http-custom/authentication/http/custom/aio/_vendor.py b/packages/typespec-python/test/azure/generated/authentication-http-custom/authentication/http/custom/aio/_vendor.py deleted file mode 100644 index c795fc22c5a..00000000000 --- a/packages/typespec-python/test/azure/generated/authentication-http-custom/authentication/http/custom/aio/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) Python Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import CustomClientConfiguration - -if TYPE_CHECKING: - from azure.core import AsyncPipelineClient - - from .._serialization import Deserializer, Serializer - - -class CustomClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "AsyncPipelineClient" - _config: CustomClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/azure/generated/authentication-http-custom/authentication/http/custom/models/_models.py b/packages/typespec-python/test/azure/generated/authentication-http-custom/authentication/http/custom/models/_models.py index 724a4800fa7..b695706d2dd 100644 --- a/packages/typespec-python/test/azure/generated/authentication-http-custom/authentication/http/custom/models/_models.py +++ b/packages/typespec-python/test/azure/generated/authentication-http-custom/authentication/http/custom/models/_models.py @@ -9,11 +9,10 @@ from typing import Any, Mapping, overload -from .. import _model_base -from .._model_base import rest_field +from .._utils.model_base import Model as _Model, rest_field -class InvalidAuth(_model_base.Model): +class InvalidAuth(_Model): """InvalidAuth. :ivar error: Required. diff --git a/packages/typespec-python/test/azure/generated/authentication-oauth2/authentication/oauth2/_client.py b/packages/typespec-python/test/azure/generated/authentication-oauth2/authentication/oauth2/_client.py index 8959a17b11b..a85661a5f2a 100644 --- a/packages/typespec-python/test/azure/generated/authentication-oauth2/authentication/oauth2/_client.py +++ b/packages/typespec-python/test/azure/generated/authentication-oauth2/authentication/oauth2/_client.py @@ -16,7 +16,7 @@ from ._configuration import OAuth2ClientConfiguration from ._operations import OAuth2ClientOperationsMixin -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer if TYPE_CHECKING: from azure.core.credentials import TokenCredential diff --git a/packages/typespec-python/test/azure/generated/authentication-oauth2/authentication/oauth2/_operations/_operations.py b/packages/typespec-python/test/azure/generated/authentication-oauth2/authentication/oauth2/_operations/_operations.py index fa3cbdf8f38..2f27e25232b 100644 --- a/packages/typespec-python/test/azure/generated/authentication-oauth2/authentication/oauth2/_operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/authentication-oauth2/authentication/oauth2/_operations/_operations.py @@ -8,6 +8,7 @@ from collections.abc import MutableMapping from typing import Any, Callable, Dict, Optional, TypeVar +from azure.core import PipelineClient from azure.core.exceptions import ( ClientAuthenticationError, HttpResponseError, @@ -22,9 +23,10 @@ from azure.core.utils import case_insensitive_dict from .. import models as _models -from .._model_base import _failsafe_deserialize -from .._serialization import Serializer -from .._vendor import OAuth2ClientMixinABC +from .._configuration import OAuth2ClientConfiguration +from .._utils.model_base import _failsafe_deserialize +from .._utils.serialization import Serializer +from .._utils.utils import ClientMixinABC T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] @@ -54,7 +56,7 @@ def build_oauth2_invalid_request(**kwargs: Any) -> HttpRequest: return HttpRequest(method="GET", url=_url, headers=_headers, **kwargs) -class OAuth2ClientOperationsMixin(OAuth2ClientMixinABC): +class OAuth2ClientOperationsMixin(ClientMixinABC[PipelineClient, OAuth2ClientConfiguration]): @distributed_trace def valid(self, **kwargs: Any) -> None: # pylint: disable=inconsistent-return-statements diff --git a/packages/typespec-python/test/azure/generated/authentication-oauth2/authentication/oauth2/_utils/__init__.py b/packages/typespec-python/test/azure/generated/authentication-oauth2/authentication/oauth2/_utils/__init__.py new file mode 100644 index 00000000000..8026245c2ab --- /dev/null +++ b/packages/typespec-python/test/azure/generated/authentication-oauth2/authentication/oauth2/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) Python Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/typespec-python/test/azure/generated/authentication-oauth2/authentication/oauth2/_model_base.py b/packages/typespec-python/test/azure/generated/authentication-oauth2/authentication/oauth2/_utils/model_base.py similarity index 100% rename from packages/typespec-python/test/azure/generated/authentication-oauth2/authentication/oauth2/_model_base.py rename to packages/typespec-python/test/azure/generated/authentication-oauth2/authentication/oauth2/_utils/model_base.py diff --git a/packages/typespec-python/test/azure/generated/authentication-oauth2/authentication/oauth2/_serialization.py b/packages/typespec-python/test/azure/generated/authentication-oauth2/authentication/oauth2/_utils/serialization.py similarity index 100% rename from packages/typespec-python/test/azure/generated/authentication-oauth2/authentication/oauth2/_serialization.py rename to packages/typespec-python/test/azure/generated/authentication-oauth2/authentication/oauth2/_utils/serialization.py diff --git a/packages/typespec-python/test/azure/generated/authentication-oauth2/authentication/oauth2/_utils/utils.py b/packages/typespec-python/test/azure/generated/authentication-oauth2/authentication/oauth2/_utils/utils.py new file mode 100644 index 00000000000..35c9c836f85 --- /dev/null +++ b/packages/typespec-python/test/azure/generated/authentication-oauth2/authentication/oauth2/_utils/utils.py @@ -0,0 +1,25 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) Python Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from abc import ABC +from typing import Generic, TYPE_CHECKING, TypeVar + +if TYPE_CHECKING: + from .serialization import Deserializer, Serializer + + +TClient = TypeVar("TClient") +TConfig = TypeVar("TConfig") + + +class ClientMixinABC(ABC, Generic[TClient, TConfig]): + """DO NOT use this class. It is for internal typing use only.""" + + _client: TClient + _config: TConfig + _serialize: "Serializer" + _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/azure/generated/authentication-oauth2/authentication/oauth2/_vendor.py b/packages/typespec-python/test/azure/generated/authentication-oauth2/authentication/oauth2/_vendor.py deleted file mode 100644 index 18bfe1600c2..00000000000 --- a/packages/typespec-python/test/azure/generated/authentication-oauth2/authentication/oauth2/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) Python Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import OAuth2ClientConfiguration - -if TYPE_CHECKING: - from azure.core import PipelineClient - - from ._serialization import Deserializer, Serializer - - -class OAuth2ClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "PipelineClient" - _config: OAuth2ClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/azure/generated/authentication-oauth2/authentication/oauth2/aio/_client.py b/packages/typespec-python/test/azure/generated/authentication-oauth2/authentication/oauth2/aio/_client.py index 2cf7633abaa..b83ebed8a29 100644 --- a/packages/typespec-python/test/azure/generated/authentication-oauth2/authentication/oauth2/aio/_client.py +++ b/packages/typespec-python/test/azure/generated/authentication-oauth2/authentication/oauth2/aio/_client.py @@ -14,7 +14,7 @@ from azure.core.pipeline import policies from azure.core.rest import AsyncHttpResponse, HttpRequest -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import OAuth2ClientConfiguration from ._operations import OAuth2ClientOperationsMixin diff --git a/packages/typespec-python/test/azure/generated/authentication-oauth2/authentication/oauth2/aio/_operations/_operations.py b/packages/typespec-python/test/azure/generated/authentication-oauth2/authentication/oauth2/aio/_operations/_operations.py index 3dd9886797d..149f9a0ac20 100644 --- a/packages/typespec-python/test/azure/generated/authentication-oauth2/authentication/oauth2/aio/_operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/authentication-oauth2/authentication/oauth2/aio/_operations/_operations.py @@ -9,6 +9,7 @@ from collections.abc import MutableMapping from typing import Any, Callable, Dict, Optional, TypeVar +from azure.core import AsyncPipelineClient from azure.core.exceptions import ( ClientAuthenticationError, HttpResponseError, @@ -22,15 +23,16 @@ from azure.core.tracing.decorator_async import distributed_trace_async from ... import models as _models -from ..._model_base import _failsafe_deserialize from ..._operations._operations import build_oauth2_invalid_request, build_oauth2_valid_request -from .._vendor import OAuth2ClientMixinABC +from ..._utils.model_base import _failsafe_deserialize +from ..._utils.utils import ClientMixinABC +from .._configuration import OAuth2ClientConfiguration T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, AsyncHttpResponse], T, Dict[str, Any]], Any]] -class OAuth2ClientOperationsMixin(OAuth2ClientMixinABC): +class OAuth2ClientOperationsMixin(ClientMixinABC[AsyncPipelineClient, OAuth2ClientConfiguration]): @distributed_trace_async async def valid(self, **kwargs: Any) -> None: diff --git a/packages/typespec-python/test/azure/generated/authentication-oauth2/authentication/oauth2/aio/_vendor.py b/packages/typespec-python/test/azure/generated/authentication-oauth2/authentication/oauth2/aio/_vendor.py deleted file mode 100644 index b07a94fefba..00000000000 --- a/packages/typespec-python/test/azure/generated/authentication-oauth2/authentication/oauth2/aio/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) Python Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import OAuth2ClientConfiguration - -if TYPE_CHECKING: - from azure.core import AsyncPipelineClient - - from .._serialization import Deserializer, Serializer - - -class OAuth2ClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "AsyncPipelineClient" - _config: OAuth2ClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/azure/generated/authentication-oauth2/authentication/oauth2/models/_models.py b/packages/typespec-python/test/azure/generated/authentication-oauth2/authentication/oauth2/models/_models.py index 724a4800fa7..b695706d2dd 100644 --- a/packages/typespec-python/test/azure/generated/authentication-oauth2/authentication/oauth2/models/_models.py +++ b/packages/typespec-python/test/azure/generated/authentication-oauth2/authentication/oauth2/models/_models.py @@ -9,11 +9,10 @@ from typing import Any, Mapping, overload -from .. import _model_base -from .._model_base import rest_field +from .._utils.model_base import Model as _Model, rest_field -class InvalidAuth(_model_base.Model): +class InvalidAuth(_Model): """InvalidAuth. :ivar error: Required. diff --git a/packages/typespec-python/test/azure/generated/authentication-union/authentication/union/_client.py b/packages/typespec-python/test/azure/generated/authentication-union/authentication/union/_client.py index d87f104cf4c..016731ce5c8 100644 --- a/packages/typespec-python/test/azure/generated/authentication-union/authentication/union/_client.py +++ b/packages/typespec-python/test/azure/generated/authentication-union/authentication/union/_client.py @@ -17,7 +17,7 @@ from ._configuration import UnionClientConfiguration from ._operations import UnionClientOperationsMixin -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer if TYPE_CHECKING: from azure.core.credentials import TokenCredential diff --git a/packages/typespec-python/test/azure/generated/authentication-union/authentication/union/_operations/_operations.py b/packages/typespec-python/test/azure/generated/authentication-union/authentication/union/_operations/_operations.py index 0de6df74913..8f7a350daec 100644 --- a/packages/typespec-python/test/azure/generated/authentication-union/authentication/union/_operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/authentication-union/authentication/union/_operations/_operations.py @@ -8,6 +8,7 @@ from collections.abc import MutableMapping from typing import Any, Callable, Dict, Optional, TypeVar +from azure.core import PipelineClient from azure.core.exceptions import ( ClientAuthenticationError, HttpResponseError, @@ -20,8 +21,9 @@ from azure.core.rest import HttpRequest, HttpResponse from azure.core.tracing.decorator import distributed_trace -from .._serialization import Serializer -from .._vendor import UnionClientMixinABC +from .._configuration import UnionClientConfiguration +from .._utils.serialization import Serializer +from .._utils.utils import ClientMixinABC T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] @@ -44,7 +46,7 @@ def build_union_valid_token_request(**kwargs: Any) -> HttpRequest: return HttpRequest(method="GET", url=_url, **kwargs) -class UnionClientOperationsMixin(UnionClientMixinABC): +class UnionClientOperationsMixin(ClientMixinABC[PipelineClient, UnionClientConfiguration]): @distributed_trace def valid_key(self, **kwargs: Any) -> None: # pylint: disable=inconsistent-return-statements diff --git a/packages/typespec-python/test/azure/generated/authentication-union/authentication/union/_utils/__init__.py b/packages/typespec-python/test/azure/generated/authentication-union/authentication/union/_utils/__init__.py new file mode 100644 index 00000000000..8026245c2ab --- /dev/null +++ b/packages/typespec-python/test/azure/generated/authentication-union/authentication/union/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) Python Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/typespec-python/test/azure/generated/authentication-union/authentication/union/_model_base.py b/packages/typespec-python/test/azure/generated/authentication-union/authentication/union/_utils/model_base.py similarity index 100% rename from packages/typespec-python/test/azure/generated/authentication-union/authentication/union/_model_base.py rename to packages/typespec-python/test/azure/generated/authentication-union/authentication/union/_utils/model_base.py diff --git a/packages/typespec-python/test/azure/generated/authentication-union/authentication/union/_serialization.py b/packages/typespec-python/test/azure/generated/authentication-union/authentication/union/_utils/serialization.py similarity index 100% rename from packages/typespec-python/test/azure/generated/authentication-union/authentication/union/_serialization.py rename to packages/typespec-python/test/azure/generated/authentication-union/authentication/union/_utils/serialization.py diff --git a/packages/typespec-python/test/azure/generated/authentication-union/authentication/union/_utils/utils.py b/packages/typespec-python/test/azure/generated/authentication-union/authentication/union/_utils/utils.py new file mode 100644 index 00000000000..35c9c836f85 --- /dev/null +++ b/packages/typespec-python/test/azure/generated/authentication-union/authentication/union/_utils/utils.py @@ -0,0 +1,25 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) Python Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from abc import ABC +from typing import Generic, TYPE_CHECKING, TypeVar + +if TYPE_CHECKING: + from .serialization import Deserializer, Serializer + + +TClient = TypeVar("TClient") +TConfig = TypeVar("TConfig") + + +class ClientMixinABC(ABC, Generic[TClient, TConfig]): + """DO NOT use this class. It is for internal typing use only.""" + + _client: TClient + _config: TConfig + _serialize: "Serializer" + _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/azure/generated/authentication-union/authentication/union/_vendor.py b/packages/typespec-python/test/azure/generated/authentication-union/authentication/union/_vendor.py deleted file mode 100644 index b4a86bb9e91..00000000000 --- a/packages/typespec-python/test/azure/generated/authentication-union/authentication/union/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) Python Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import UnionClientConfiguration - -if TYPE_CHECKING: - from azure.core import PipelineClient - - from ._serialization import Deserializer, Serializer - - -class UnionClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "PipelineClient" - _config: UnionClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/azure/generated/authentication-union/authentication/union/aio/_client.py b/packages/typespec-python/test/azure/generated/authentication-union/authentication/union/aio/_client.py index 7550be98cf4..89a85fa7f4c 100644 --- a/packages/typespec-python/test/azure/generated/authentication-union/authentication/union/aio/_client.py +++ b/packages/typespec-python/test/azure/generated/authentication-union/authentication/union/aio/_client.py @@ -15,7 +15,7 @@ from azure.core.pipeline import policies from azure.core.rest import AsyncHttpResponse, HttpRequest -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import UnionClientConfiguration from ._operations import UnionClientOperationsMixin diff --git a/packages/typespec-python/test/azure/generated/authentication-union/authentication/union/aio/_operations/_operations.py b/packages/typespec-python/test/azure/generated/authentication-union/authentication/union/aio/_operations/_operations.py index 8de6db287d0..126e9105f65 100644 --- a/packages/typespec-python/test/azure/generated/authentication-union/authentication/union/aio/_operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/authentication-union/authentication/union/aio/_operations/_operations.py @@ -9,6 +9,7 @@ from collections.abc import MutableMapping from typing import Any, Callable, Dict, Optional, TypeVar +from azure.core import AsyncPipelineClient from azure.core.exceptions import ( ClientAuthenticationError, HttpResponseError, @@ -22,13 +23,14 @@ from azure.core.tracing.decorator_async import distributed_trace_async from ..._operations._operations import build_union_valid_key_request, build_union_valid_token_request -from .._vendor import UnionClientMixinABC +from ..._utils.utils import ClientMixinABC +from .._configuration import UnionClientConfiguration T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, AsyncHttpResponse], T, Dict[str, Any]], Any]] -class UnionClientOperationsMixin(UnionClientMixinABC): +class UnionClientOperationsMixin(ClientMixinABC[AsyncPipelineClient, UnionClientConfiguration]): @distributed_trace_async async def valid_key(self, **kwargs: Any) -> None: diff --git a/packages/typespec-python/test/azure/generated/authentication-union/authentication/union/aio/_vendor.py b/packages/typespec-python/test/azure/generated/authentication-union/authentication/union/aio/_vendor.py deleted file mode 100644 index 0e4af421704..00000000000 --- a/packages/typespec-python/test/azure/generated/authentication-union/authentication/union/aio/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) Python Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import UnionClientConfiguration - -if TYPE_CHECKING: - from azure.core import AsyncPipelineClient - - from .._serialization import Deserializer, Serializer - - -class UnionClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "AsyncPipelineClient" - _config: UnionClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/azure/generated/azure-client-generator-core-access/specs/azure/clientgenerator/core/access/_client.py b/packages/typespec-python/test/azure/generated/azure-client-generator-core-access/specs/azure/clientgenerator/core/access/_client.py index 21efc90ff9c..d9c94e451c6 100644 --- a/packages/typespec-python/test/azure/generated/azure-client-generator-core-access/specs/azure/clientgenerator/core/access/_client.py +++ b/packages/typespec-python/test/azure/generated/azure-client-generator-core-access/specs/azure/clientgenerator/core/access/_client.py @@ -15,7 +15,7 @@ from azure.core.rest import HttpRequest, HttpResponse from ._configuration import AccessClientConfiguration -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer from .operations import ( InternalOperationOperations, PublicOperationOperations, diff --git a/packages/typespec-python/test/azure/generated/azure-client-generator-core-access/specs/azure/clientgenerator/core/access/_utils/__init__.py b/packages/typespec-python/test/azure/generated/azure-client-generator-core-access/specs/azure/clientgenerator/core/access/_utils/__init__.py new file mode 100644 index 00000000000..8026245c2ab --- /dev/null +++ b/packages/typespec-python/test/azure/generated/azure-client-generator-core-access/specs/azure/clientgenerator/core/access/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) Python Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/typespec-python/test/azure/generated/azure-client-generator-core-access/specs/azure/clientgenerator/core/access/_model_base.py b/packages/typespec-python/test/azure/generated/azure-client-generator-core-access/specs/azure/clientgenerator/core/access/_utils/model_base.py similarity index 100% rename from packages/typespec-python/test/azure/generated/azure-client-generator-core-access/specs/azure/clientgenerator/core/access/_model_base.py rename to packages/typespec-python/test/azure/generated/azure-client-generator-core-access/specs/azure/clientgenerator/core/access/_utils/model_base.py diff --git a/packages/typespec-python/test/azure/generated/azure-client-generator-core-access/specs/azure/clientgenerator/core/access/_serialization.py b/packages/typespec-python/test/azure/generated/azure-client-generator-core-access/specs/azure/clientgenerator/core/access/_utils/serialization.py similarity index 100% rename from packages/typespec-python/test/azure/generated/azure-client-generator-core-access/specs/azure/clientgenerator/core/access/_serialization.py rename to packages/typespec-python/test/azure/generated/azure-client-generator-core-access/specs/azure/clientgenerator/core/access/_utils/serialization.py diff --git a/packages/typespec-python/test/azure/generated/azure-client-generator-core-access/specs/azure/clientgenerator/core/access/aio/_client.py b/packages/typespec-python/test/azure/generated/azure-client-generator-core-access/specs/azure/clientgenerator/core/access/aio/_client.py index 8132ba1b50b..e731ef7b56e 100644 --- a/packages/typespec-python/test/azure/generated/azure-client-generator-core-access/specs/azure/clientgenerator/core/access/aio/_client.py +++ b/packages/typespec-python/test/azure/generated/azure-client-generator-core-access/specs/azure/clientgenerator/core/access/aio/_client.py @@ -14,7 +14,7 @@ from azure.core.pipeline import policies from azure.core.rest import AsyncHttpResponse, HttpRequest -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import AccessClientConfiguration from .operations import ( InternalOperationOperations, diff --git a/packages/typespec-python/test/azure/generated/azure-client-generator-core-access/specs/azure/clientgenerator/core/access/aio/operations/_operations.py b/packages/typespec-python/test/azure/generated/azure-client-generator-core-access/specs/azure/clientgenerator/core/access/aio/operations/_operations.py index 31c2c108db4..04eb6cce7dd 100644 --- a/packages/typespec-python/test/azure/generated/azure-client-generator-core-access/specs/azure/clientgenerator/core/access/aio/operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/azure-client-generator-core-access/specs/azure/clientgenerator/core/access/aio/operations/_operations.py @@ -24,8 +24,8 @@ from azure.core.tracing.decorator_async import distributed_trace_async from ... import models as _models -from ..._model_base import _deserialize -from ..._serialization import Deserializer, Serializer +from ..._utils.model_base import _deserialize +from ..._utils.serialization import Deserializer, Serializer from ...operations._operations import ( build_internal_operation_internal_decorator_in_internal_request, build_internal_operation_no_decorator_in_internal_request, diff --git a/packages/typespec-python/test/azure/generated/azure-client-generator-core-access/specs/azure/clientgenerator/core/access/models/_models.py b/packages/typespec-python/test/azure/generated/azure-client-generator-core-access/specs/azure/clientgenerator/core/access/models/_models.py index 73740de086a..0d18fba5477 100644 --- a/packages/typespec-python/test/azure/generated/azure-client-generator-core-access/specs/azure/clientgenerator/core/access/models/_models.py +++ b/packages/typespec-python/test/azure/generated/azure-client-generator-core-access/specs/azure/clientgenerator/core/access/models/_models.py @@ -10,14 +10,13 @@ from typing import Any, Dict, Literal, Mapping, TYPE_CHECKING, overload -from .. import _model_base -from .._model_base import rest_discriminator, rest_field +from .._utils.model_base import Model as _Model, rest_discriminator, rest_field if TYPE_CHECKING: from .. import models as _models -class AbstractModel(_model_base.Model): +class AbstractModel(_Model): """Used in internal operations, should be generated but not exported. You probably want to use the sub-classes and not this class directly. Known sub-classes are: @@ -29,7 +28,7 @@ class AbstractModel(_model_base.Model): :vartype name: str """ - __mapping__: Dict[str, _model_base.Model] = {} + __mapping__: Dict[str, _Model] = {} kind: str = rest_discriminator(name="kind") """Discriminator property for AbstractModel. Required. Default value is None.""" name: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) @@ -54,7 +53,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class BaseModel(_model_base.Model): +class BaseModel(_Model): """Used in internal operations, should be generated but not exported. :ivar name: Required. @@ -82,7 +81,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class InnerModel(_model_base.Model): +class InnerModel(_Model): """Used in internal operations, should be generated but not exported. :ivar name: Required. @@ -110,7 +109,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class InternalDecoratorModelInInternal(_model_base.Model): +class InternalDecoratorModelInInternal(_Model): """Used in an internal operation, should be generated but not exported. :ivar name: Required. @@ -138,7 +137,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class NoDecoratorModelInInternal(_model_base.Model): +class NoDecoratorModelInInternal(_Model): """Used in an internal operation, should be generated but not exported. :ivar name: Required. @@ -166,7 +165,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class NoDecoratorModelInPublic(_model_base.Model): +class NoDecoratorModelInPublic(_Model): """Used in a public operation, should be generated and exported. :ivar name: Required. @@ -225,7 +224,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class PublicDecoratorModelInInternal(_model_base.Model): +class PublicDecoratorModelInInternal(_Model): """Used in an internal operation but with public decorator, should be generated and exported. :ivar name: Required. @@ -253,7 +252,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class PublicDecoratorModelInPublic(_model_base.Model): +class PublicDecoratorModelInPublic(_Model): """Used in a public operation, should be generated and exported. :ivar name: Required. @@ -311,7 +310,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, kind="real", **kwargs) -class SharedModel(_model_base.Model): +class SharedModel(_Model): """Used by both public and internal operation. It should be generated and exported. :ivar name: Required. diff --git a/packages/typespec-python/test/azure/generated/azure-client-generator-core-access/specs/azure/clientgenerator/core/access/operations/_operations.py b/packages/typespec-python/test/azure/generated/azure-client-generator-core-access/specs/azure/clientgenerator/core/access/operations/_operations.py index 91cd735702b..267b7bcaef5 100644 --- a/packages/typespec-python/test/azure/generated/azure-client-generator-core-access/specs/azure/clientgenerator/core/access/operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/azure-client-generator-core-access/specs/azure/clientgenerator/core/access/operations/_operations.py @@ -26,8 +26,8 @@ from .. import models as _models from .._configuration import AccessClientConfiguration -from .._model_base import _deserialize -from .._serialization import Deserializer, Serializer +from .._utils.model_base import _deserialize +from .._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/typespec-python/test/azure/generated/azure-client-generator-core-client-initialization/specs/azure/clientgenerator/core/clientinitialization/_client.py b/packages/typespec-python/test/azure/generated/azure-client-generator-core-client-initialization/specs/azure/clientgenerator/core/clientinitialization/_client.py index 38434b9eb61..24ee3cb87f3 100644 --- a/packages/typespec-python/test/azure/generated/azure-client-generator-core-client-initialization/specs/azure/clientgenerator/core/clientinitialization/_client.py +++ b/packages/typespec-python/test/azure/generated/azure-client-generator-core-client-initialization/specs/azure/clientgenerator/core/clientinitialization/_client.py @@ -28,7 +28,7 @@ ParamAliasClientOperationsMixin, PathParamClientOperationsMixin, ) -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer class HeaderParamClient(HeaderParamClientOperationsMixin): # pylint: disable=client-accepts-api-version-keyword diff --git a/packages/typespec-python/test/azure/generated/azure-client-generator-core-client-initialization/specs/azure/clientgenerator/core/clientinitialization/_operations/_operations.py b/packages/typespec-python/test/azure/generated/azure-client-generator-core-client-initialization/specs/azure/clientgenerator/core/clientinitialization/_operations/_operations.py index 26afe2e243c..eaa5c1adb50 100644 --- a/packages/typespec-python/test/azure/generated/azure-client-generator-core-client-initialization/specs/azure/clientgenerator/core/clientinitialization/_operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/azure-client-generator-core-client-initialization/specs/azure/clientgenerator/core/clientinitialization/_operations/_operations.py @@ -10,6 +10,7 @@ import json from typing import Any, Callable, Dict, IO, Optional, TypeVar, Union, overload +from azure.core import PipelineClient from azure.core.exceptions import ( ClientAuthenticationError, HttpResponseError, @@ -26,15 +27,16 @@ from azure.core.utils import case_insensitive_dict from .. import models as _models -from .._model_base import SdkJSONEncoder, _deserialize -from .._serialization import Serializer -from .._vendor import ( - HeaderParamClientMixinABC, - MixedParamsClientMixinABC, - MultipleParamsClientMixinABC, - ParamAliasClientMixinABC, - PathParamClientMixinABC, +from .._configuration import ( + HeaderParamClientConfiguration, + MixedParamsClientConfiguration, + MultipleParamsClientConfiguration, + ParamAliasClientConfiguration, + PathParamClientConfiguration, ) +from .._utils.model_base import SdkJSONEncoder, _deserialize +from .._utils.serialization import Serializer +from .._utils.utils import ClientMixinABC JSON = MutableMapping[str, Any] T = TypeVar("T") @@ -226,7 +228,7 @@ def build_param_alias_with_original_name_request( # pylint: disable=name-too-lo return HttpRequest(method="GET", url=_url, **kwargs) -class HeaderParamClientOperationsMixin(HeaderParamClientMixinABC): +class HeaderParamClientOperationsMixin(ClientMixinABC[PipelineClient, HeaderParamClientConfiguration]): @distributed_trace def with_query(self, *, id: str, **kwargs: Any) -> None: # pylint: disable=inconsistent-return-statements @@ -379,7 +381,7 @@ def with_body( # pylint: disable=inconsistent-return-statements return cls(pipeline_response, None, {}) # type: ignore -class MultipleParamsClientOperationsMixin(MultipleParamsClientMixinABC): +class MultipleParamsClientOperationsMixin(ClientMixinABC[PipelineClient, MultipleParamsClientConfiguration]): @distributed_trace def with_query(self, *, id: str, **kwargs: Any) -> None: # pylint: disable=inconsistent-return-statements @@ -534,7 +536,7 @@ def with_body( # pylint: disable=inconsistent-return-statements return cls(pipeline_response, None, {}) # type: ignore -class MixedParamsClientOperationsMixin(MixedParamsClientMixinABC): +class MixedParamsClientOperationsMixin(ClientMixinABC[PipelineClient, MixedParamsClientConfiguration]): @distributed_trace def with_query( # pylint: disable=inconsistent-return-statements @@ -703,7 +705,7 @@ def with_body( # pylint: disable=inconsistent-return-statements return cls(pipeline_response, None, {}) # type: ignore -class PathParamClientOperationsMixin(PathParamClientMixinABC): +class PathParamClientOperationsMixin(ClientMixinABC[PipelineClient, PathParamClientConfiguration]): @distributed_trace def with_query( # pylint: disable=inconsistent-return-statements @@ -858,7 +860,7 @@ def delete_standalone(self, **kwargs: Any) -> None: # pylint: disable=inconsist return cls(pipeline_response, None, {}) # type: ignore -class ParamAliasClientOperationsMixin(ParamAliasClientMixinABC): +class ParamAliasClientOperationsMixin(ClientMixinABC[PipelineClient, ParamAliasClientConfiguration]): @distributed_trace def with_aliased_name(self, **kwargs: Any) -> None: # pylint: disable=inconsistent-return-statements diff --git a/packages/typespec-python/test/azure/generated/azure-client-generator-core-client-initialization/specs/azure/clientgenerator/core/clientinitialization/_utils/__init__.py b/packages/typespec-python/test/azure/generated/azure-client-generator-core-client-initialization/specs/azure/clientgenerator/core/clientinitialization/_utils/__init__.py new file mode 100644 index 00000000000..8026245c2ab --- /dev/null +++ b/packages/typespec-python/test/azure/generated/azure-client-generator-core-client-initialization/specs/azure/clientgenerator/core/clientinitialization/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) Python Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/typespec-python/test/azure/generated/azure-client-generator-core-client-initialization/specs/azure/clientgenerator/core/clientinitialization/_model_base.py b/packages/typespec-python/test/azure/generated/azure-client-generator-core-client-initialization/specs/azure/clientgenerator/core/clientinitialization/_utils/model_base.py similarity index 100% rename from packages/typespec-python/test/azure/generated/azure-client-generator-core-client-initialization/specs/azure/clientgenerator/core/clientinitialization/_model_base.py rename to packages/typespec-python/test/azure/generated/azure-client-generator-core-client-initialization/specs/azure/clientgenerator/core/clientinitialization/_utils/model_base.py diff --git a/packages/typespec-python/test/azure/generated/azure-client-generator-core-client-initialization/specs/azure/clientgenerator/core/clientinitialization/_serialization.py b/packages/typespec-python/test/azure/generated/azure-client-generator-core-client-initialization/specs/azure/clientgenerator/core/clientinitialization/_utils/serialization.py similarity index 100% rename from packages/typespec-python/test/azure/generated/azure-client-generator-core-client-initialization/specs/azure/clientgenerator/core/clientinitialization/_serialization.py rename to packages/typespec-python/test/azure/generated/azure-client-generator-core-client-initialization/specs/azure/clientgenerator/core/clientinitialization/_utils/serialization.py diff --git a/packages/typespec-python/test/azure/generated/azure-client-generator-core-client-initialization/specs/azure/clientgenerator/core/clientinitialization/_utils/utils.py b/packages/typespec-python/test/azure/generated/azure-client-generator-core-client-initialization/specs/azure/clientgenerator/core/clientinitialization/_utils/utils.py new file mode 100644 index 00000000000..35c9c836f85 --- /dev/null +++ b/packages/typespec-python/test/azure/generated/azure-client-generator-core-client-initialization/specs/azure/clientgenerator/core/clientinitialization/_utils/utils.py @@ -0,0 +1,25 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) Python Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from abc import ABC +from typing import Generic, TYPE_CHECKING, TypeVar + +if TYPE_CHECKING: + from .serialization import Deserializer, Serializer + + +TClient = TypeVar("TClient") +TConfig = TypeVar("TConfig") + + +class ClientMixinABC(ABC, Generic[TClient, TConfig]): + """DO NOT use this class. It is for internal typing use only.""" + + _client: TClient + _config: TConfig + _serialize: "Serializer" + _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/azure/generated/azure-client-generator-core-client-initialization/specs/azure/clientgenerator/core/clientinitialization/_vendor.py b/packages/typespec-python/test/azure/generated/azure-client-generator-core-client-initialization/specs/azure/clientgenerator/core/clientinitialization/_vendor.py deleted file mode 100644 index 0bf891fe013..00000000000 --- a/packages/typespec-python/test/azure/generated/azure-client-generator-core-client-initialization/specs/azure/clientgenerator/core/clientinitialization/_vendor.py +++ /dev/null @@ -1,67 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) Python Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import ( - HeaderParamClientConfiguration, - MixedParamsClientConfiguration, - MultipleParamsClientConfiguration, - ParamAliasClientConfiguration, - PathParamClientConfiguration, -) - -if TYPE_CHECKING: - from azure.core import PipelineClient - - from ._serialization import Deserializer, Serializer - - -class HeaderParamClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "PipelineClient" - _config: HeaderParamClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" - - -class MultipleParamsClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "PipelineClient" - _config: MultipleParamsClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" - - -class MixedParamsClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "PipelineClient" - _config: MixedParamsClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" - - -class PathParamClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "PipelineClient" - _config: PathParamClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" - - -class ParamAliasClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "PipelineClient" - _config: ParamAliasClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/azure/generated/azure-client-generator-core-client-initialization/specs/azure/clientgenerator/core/clientinitialization/aio/_client.py b/packages/typespec-python/test/azure/generated/azure-client-generator-core-client-initialization/specs/azure/clientgenerator/core/clientinitialization/aio/_client.py index e088980e696..1fda68f0245 100644 --- a/packages/typespec-python/test/azure/generated/azure-client-generator-core-client-initialization/specs/azure/clientgenerator/core/clientinitialization/aio/_client.py +++ b/packages/typespec-python/test/azure/generated/azure-client-generator-core-client-initialization/specs/azure/clientgenerator/core/clientinitialization/aio/_client.py @@ -14,7 +14,7 @@ from azure.core.pipeline import policies from azure.core.rest import AsyncHttpResponse, HttpRequest -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import ( HeaderParamClientConfiguration, MixedParamsClientConfiguration, diff --git a/packages/typespec-python/test/azure/generated/azure-client-generator-core-client-initialization/specs/azure/clientgenerator/core/clientinitialization/aio/_operations/_operations.py b/packages/typespec-python/test/azure/generated/azure-client-generator-core-client-initialization/specs/azure/clientgenerator/core/clientinitialization/aio/_operations/_operations.py index f102063d7e7..8488ffba70f 100644 --- a/packages/typespec-python/test/azure/generated/azure-client-generator-core-client-initialization/specs/azure/clientgenerator/core/clientinitialization/aio/_operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/azure-client-generator-core-client-initialization/specs/azure/clientgenerator/core/clientinitialization/aio/_operations/_operations.py @@ -11,6 +11,7 @@ import json from typing import Any, Callable, Dict, IO, Optional, TypeVar, Union, overload +from azure.core import AsyncPipelineClient from azure.core.exceptions import ( ClientAuthenticationError, HttpResponseError, @@ -27,7 +28,6 @@ from azure.core.utils import case_insensitive_dict from ... import models as _models -from ..._model_base import SdkJSONEncoder, _deserialize from ..._operations._operations import ( build_header_param_with_body_request, build_header_param_with_query_request, @@ -41,12 +41,14 @@ build_path_param_get_standalone_request, build_path_param_with_query_request, ) -from .._vendor import ( - HeaderParamClientMixinABC, - MixedParamsClientMixinABC, - MultipleParamsClientMixinABC, - ParamAliasClientMixinABC, - PathParamClientMixinABC, +from ..._utils.model_base import SdkJSONEncoder, _deserialize +from ..._utils.utils import ClientMixinABC +from .._configuration import ( + HeaderParamClientConfiguration, + MixedParamsClientConfiguration, + MultipleParamsClientConfiguration, + ParamAliasClientConfiguration, + PathParamClientConfiguration, ) JSON = MutableMapping[str, Any] @@ -54,7 +56,7 @@ ClsType = Optional[Callable[[PipelineResponse[HttpRequest, AsyncHttpResponse], T, Dict[str, Any]], Any]] -class HeaderParamClientOperationsMixin(HeaderParamClientMixinABC): +class HeaderParamClientOperationsMixin(ClientMixinABC[AsyncPipelineClient, HeaderParamClientConfiguration]): @distributed_trace_async async def with_query(self, *, id: str, **kwargs: Any) -> None: @@ -205,7 +207,7 @@ async def with_body(self, body: Union[_models.Input, JSON, IO[bytes]], **kwargs: return cls(pipeline_response, None, {}) # type: ignore -class MultipleParamsClientOperationsMixin(MultipleParamsClientMixinABC): +class MultipleParamsClientOperationsMixin(ClientMixinABC[AsyncPipelineClient, MultipleParamsClientConfiguration]): @distributed_trace_async async def with_query(self, *, id: str, **kwargs: Any) -> None: @@ -358,7 +360,7 @@ async def with_body(self, body: Union[_models.Input, JSON, IO[bytes]], **kwargs: return cls(pipeline_response, None, {}) # type: ignore -class MixedParamsClientOperationsMixin(MixedParamsClientMixinABC): +class MixedParamsClientOperationsMixin(ClientMixinABC[AsyncPipelineClient, MixedParamsClientConfiguration]): @distributed_trace_async async def with_query(self, *, region: str, id: str, **kwargs: Any) -> None: @@ -529,7 +531,7 @@ async def with_body( return cls(pipeline_response, None, {}) # type: ignore -class PathParamClientOperationsMixin(PathParamClientMixinABC): +class PathParamClientOperationsMixin(ClientMixinABC[AsyncPipelineClient, PathParamClientConfiguration]): @distributed_trace_async async def with_query(self, *, format: Optional[str] = None, **kwargs: Any) -> None: @@ -682,7 +684,7 @@ async def delete_standalone(self, **kwargs: Any) -> None: return cls(pipeline_response, None, {}) # type: ignore -class ParamAliasClientOperationsMixin(ParamAliasClientMixinABC): +class ParamAliasClientOperationsMixin(ClientMixinABC[AsyncPipelineClient, ParamAliasClientConfiguration]): @distributed_trace_async async def with_aliased_name(self, **kwargs: Any) -> None: diff --git a/packages/typespec-python/test/azure/generated/azure-client-generator-core-client-initialization/specs/azure/clientgenerator/core/clientinitialization/aio/_vendor.py b/packages/typespec-python/test/azure/generated/azure-client-generator-core-client-initialization/specs/azure/clientgenerator/core/clientinitialization/aio/_vendor.py deleted file mode 100644 index 8eb2c6bd696..00000000000 --- a/packages/typespec-python/test/azure/generated/azure-client-generator-core-client-initialization/specs/azure/clientgenerator/core/clientinitialization/aio/_vendor.py +++ /dev/null @@ -1,67 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) Python Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import ( - HeaderParamClientConfiguration, - MixedParamsClientConfiguration, - MultipleParamsClientConfiguration, - ParamAliasClientConfiguration, - PathParamClientConfiguration, -) - -if TYPE_CHECKING: - from azure.core import AsyncPipelineClient - - from .._serialization import Deserializer, Serializer - - -class HeaderParamClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "AsyncPipelineClient" - _config: HeaderParamClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" - - -class MultipleParamsClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "AsyncPipelineClient" - _config: MultipleParamsClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" - - -class MixedParamsClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "AsyncPipelineClient" - _config: MixedParamsClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" - - -class PathParamClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "AsyncPipelineClient" - _config: PathParamClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" - - -class ParamAliasClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "AsyncPipelineClient" - _config: ParamAliasClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/azure/generated/azure-client-generator-core-client-initialization/specs/azure/clientgenerator/core/clientinitialization/models/_models.py b/packages/typespec-python/test/azure/generated/azure-client-generator-core-client-initialization/specs/azure/clientgenerator/core/clientinitialization/models/_models.py index dc2e5935ad1..5a973dd3c65 100644 --- a/packages/typespec-python/test/azure/generated/azure-client-generator-core-client-initialization/specs/azure/clientgenerator/core/clientinitialization/models/_models.py +++ b/packages/typespec-python/test/azure/generated/azure-client-generator-core-client-initialization/specs/azure/clientgenerator/core/clientinitialization/models/_models.py @@ -10,11 +10,10 @@ import datetime from typing import Any, Mapping, overload -from .. import _model_base -from .._model_base import rest_field +from .._utils.model_base import Model as _Model, rest_field -class BlobProperties(_model_base.Model): +class BlobProperties(_Model): """Properties of a blob. :ivar name: Required. @@ -59,7 +58,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class Input(_model_base.Model): +class Input(_Model): """Input. :ivar name: Required. @@ -87,7 +86,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class WithBodyRequest(_model_base.Model): +class WithBodyRequest(_Model): """WithBodyRequest. :ivar name: Required. diff --git a/packages/typespec-python/test/azure/generated/azure-client-generator-core-flatten-property/specs/azure/clientgenerator/core/flattenproperty/_client.py b/packages/typespec-python/test/azure/generated/azure-client-generator-core-flatten-property/specs/azure/clientgenerator/core/flattenproperty/_client.py index af14a03d503..08683b15615 100644 --- a/packages/typespec-python/test/azure/generated/azure-client-generator-core-flatten-property/specs/azure/clientgenerator/core/flattenproperty/_client.py +++ b/packages/typespec-python/test/azure/generated/azure-client-generator-core-flatten-property/specs/azure/clientgenerator/core/flattenproperty/_client.py @@ -16,7 +16,7 @@ from ._configuration import FlattenPropertyClientConfiguration from ._operations import FlattenPropertyClientOperationsMixin -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer class FlattenPropertyClient(FlattenPropertyClientOperationsMixin): # pylint: disable=client-accepts-api-version-keyword diff --git a/packages/typespec-python/test/azure/generated/azure-client-generator-core-flatten-property/specs/azure/clientgenerator/core/flattenproperty/_operations/_operations.py b/packages/typespec-python/test/azure/generated/azure-client-generator-core-flatten-property/specs/azure/clientgenerator/core/flattenproperty/_operations/_operations.py index 9c8ec6c5e7f..5d7d8d5fb3e 100644 --- a/packages/typespec-python/test/azure/generated/azure-client-generator-core-flatten-property/specs/azure/clientgenerator/core/flattenproperty/_operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/azure-client-generator-core-flatten-property/specs/azure/clientgenerator/core/flattenproperty/_operations/_operations.py @@ -10,6 +10,7 @@ import json from typing import Any, Callable, Dict, IO, Optional, TypeVar, Union, overload +from azure.core import PipelineClient from azure.core.exceptions import ( ClientAuthenticationError, HttpResponseError, @@ -26,9 +27,10 @@ from azure.core.utils import case_insensitive_dict from .. import models as _models -from .._model_base import SdkJSONEncoder, _deserialize -from .._serialization import Serializer -from .._vendor import FlattenPropertyClientMixinABC +from .._configuration import FlattenPropertyClientConfiguration +from .._utils.model_base import SdkJSONEncoder, _deserialize +from .._utils.serialization import Serializer +from .._utils.utils import ClientMixinABC JSON = MutableMapping[str, Any] T = TypeVar("T") @@ -74,7 +76,7 @@ def build_flatten_property_put_nested_flatten_model_request( # pylint: disable= return HttpRequest(method="PUT", url=_url, headers=_headers, **kwargs) -class FlattenPropertyClientOperationsMixin(FlattenPropertyClientMixinABC): +class FlattenPropertyClientOperationsMixin(ClientMixinABC[PipelineClient, FlattenPropertyClientConfiguration]): @overload def put_flatten_model( diff --git a/packages/typespec-python/test/azure/generated/azure-client-generator-core-flatten-property/specs/azure/clientgenerator/core/flattenproperty/_utils/__init__.py b/packages/typespec-python/test/azure/generated/azure-client-generator-core-flatten-property/specs/azure/clientgenerator/core/flattenproperty/_utils/__init__.py new file mode 100644 index 00000000000..8026245c2ab --- /dev/null +++ b/packages/typespec-python/test/azure/generated/azure-client-generator-core-flatten-property/specs/azure/clientgenerator/core/flattenproperty/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) Python Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/typespec-python/test/azure/generated/azure-client-generator-core-flatten-property/specs/azure/clientgenerator/core/flattenproperty/_model_base.py b/packages/typespec-python/test/azure/generated/azure-client-generator-core-flatten-property/specs/azure/clientgenerator/core/flattenproperty/_utils/model_base.py similarity index 100% rename from packages/typespec-python/test/azure/generated/azure-client-generator-core-flatten-property/specs/azure/clientgenerator/core/flattenproperty/_model_base.py rename to packages/typespec-python/test/azure/generated/azure-client-generator-core-flatten-property/specs/azure/clientgenerator/core/flattenproperty/_utils/model_base.py diff --git a/packages/typespec-python/test/azure/generated/azure-client-generator-core-flatten-property/specs/azure/clientgenerator/core/flattenproperty/_serialization.py b/packages/typespec-python/test/azure/generated/azure-client-generator-core-flatten-property/specs/azure/clientgenerator/core/flattenproperty/_utils/serialization.py similarity index 100% rename from packages/typespec-python/test/azure/generated/azure-client-generator-core-flatten-property/specs/azure/clientgenerator/core/flattenproperty/_serialization.py rename to packages/typespec-python/test/azure/generated/azure-client-generator-core-flatten-property/specs/azure/clientgenerator/core/flattenproperty/_utils/serialization.py diff --git a/packages/typespec-python/test/azure/generated/azure-client-generator-core-flatten-property/specs/azure/clientgenerator/core/flattenproperty/_utils/utils.py b/packages/typespec-python/test/azure/generated/azure-client-generator-core-flatten-property/specs/azure/clientgenerator/core/flattenproperty/_utils/utils.py new file mode 100644 index 00000000000..35c9c836f85 --- /dev/null +++ b/packages/typespec-python/test/azure/generated/azure-client-generator-core-flatten-property/specs/azure/clientgenerator/core/flattenproperty/_utils/utils.py @@ -0,0 +1,25 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) Python Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from abc import ABC +from typing import Generic, TYPE_CHECKING, TypeVar + +if TYPE_CHECKING: + from .serialization import Deserializer, Serializer + + +TClient = TypeVar("TClient") +TConfig = TypeVar("TConfig") + + +class ClientMixinABC(ABC, Generic[TClient, TConfig]): + """DO NOT use this class. It is for internal typing use only.""" + + _client: TClient + _config: TConfig + _serialize: "Serializer" + _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/azure/generated/azure-client-generator-core-flatten-property/specs/azure/clientgenerator/core/flattenproperty/_vendor.py b/packages/typespec-python/test/azure/generated/azure-client-generator-core-flatten-property/specs/azure/clientgenerator/core/flattenproperty/_vendor.py deleted file mode 100644 index bc0657eb4e5..00000000000 --- a/packages/typespec-python/test/azure/generated/azure-client-generator-core-flatten-property/specs/azure/clientgenerator/core/flattenproperty/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) Python Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import FlattenPropertyClientConfiguration - -if TYPE_CHECKING: - from azure.core import PipelineClient - - from ._serialization import Deserializer, Serializer - - -class FlattenPropertyClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "PipelineClient" - _config: FlattenPropertyClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/azure/generated/azure-client-generator-core-flatten-property/specs/azure/clientgenerator/core/flattenproperty/aio/_client.py b/packages/typespec-python/test/azure/generated/azure-client-generator-core-flatten-property/specs/azure/clientgenerator/core/flattenproperty/aio/_client.py index cc62d7b8598..d6d5e6a62a4 100644 --- a/packages/typespec-python/test/azure/generated/azure-client-generator-core-flatten-property/specs/azure/clientgenerator/core/flattenproperty/aio/_client.py +++ b/packages/typespec-python/test/azure/generated/azure-client-generator-core-flatten-property/specs/azure/clientgenerator/core/flattenproperty/aio/_client.py @@ -14,7 +14,7 @@ from azure.core.pipeline import policies from azure.core.rest import AsyncHttpResponse, HttpRequest -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import FlattenPropertyClientConfiguration from ._operations import FlattenPropertyClientOperationsMixin diff --git a/packages/typespec-python/test/azure/generated/azure-client-generator-core-flatten-property/specs/azure/clientgenerator/core/flattenproperty/aio/_operations/_operations.py b/packages/typespec-python/test/azure/generated/azure-client-generator-core-flatten-property/specs/azure/clientgenerator/core/flattenproperty/aio/_operations/_operations.py index 22145246654..fffaa7c4c1d 100644 --- a/packages/typespec-python/test/azure/generated/azure-client-generator-core-flatten-property/specs/azure/clientgenerator/core/flattenproperty/aio/_operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/azure-client-generator-core-flatten-property/specs/azure/clientgenerator/core/flattenproperty/aio/_operations/_operations.py @@ -11,6 +11,7 @@ import json from typing import Any, Callable, Dict, IO, Optional, TypeVar, Union, overload +from azure.core import AsyncPipelineClient from azure.core.exceptions import ( ClientAuthenticationError, HttpResponseError, @@ -27,19 +28,20 @@ from azure.core.utils import case_insensitive_dict from ... import models as _models -from ..._model_base import SdkJSONEncoder, _deserialize from ..._operations._operations import ( build_flatten_property_put_flatten_model_request, build_flatten_property_put_nested_flatten_model_request, ) -from .._vendor import FlattenPropertyClientMixinABC +from ..._utils.model_base import SdkJSONEncoder, _deserialize +from ..._utils.utils import ClientMixinABC +from .._configuration import FlattenPropertyClientConfiguration JSON = MutableMapping[str, Any] T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, AsyncHttpResponse], T, Dict[str, Any]], Any]] -class FlattenPropertyClientOperationsMixin(FlattenPropertyClientMixinABC): +class FlattenPropertyClientOperationsMixin(ClientMixinABC[AsyncPipelineClient, FlattenPropertyClientConfiguration]): @overload async def put_flatten_model( diff --git a/packages/typespec-python/test/azure/generated/azure-client-generator-core-flatten-property/specs/azure/clientgenerator/core/flattenproperty/aio/_vendor.py b/packages/typespec-python/test/azure/generated/azure-client-generator-core-flatten-property/specs/azure/clientgenerator/core/flattenproperty/aio/_vendor.py deleted file mode 100644 index 56b763366fe..00000000000 --- a/packages/typespec-python/test/azure/generated/azure-client-generator-core-flatten-property/specs/azure/clientgenerator/core/flattenproperty/aio/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) Python Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import FlattenPropertyClientConfiguration - -if TYPE_CHECKING: - from azure.core import AsyncPipelineClient - - from .._serialization import Deserializer, Serializer - - -class FlattenPropertyClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "AsyncPipelineClient" - _config: FlattenPropertyClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/azure/generated/azure-client-generator-core-flatten-property/specs/azure/clientgenerator/core/flattenproperty/models/_models.py b/packages/typespec-python/test/azure/generated/azure-client-generator-core-flatten-property/specs/azure/clientgenerator/core/flattenproperty/models/_models.py index c1cd8057f71..ee3f100ca2d 100644 --- a/packages/typespec-python/test/azure/generated/azure-client-generator-core-flatten-property/specs/azure/clientgenerator/core/flattenproperty/models/_models.py +++ b/packages/typespec-python/test/azure/generated/azure-client-generator-core-flatten-property/specs/azure/clientgenerator/core/flattenproperty/models/_models.py @@ -9,14 +9,13 @@ from typing import Any, Mapping, TYPE_CHECKING, overload -from .. import _model_base -from .._model_base import rest_field +from .._utils.model_base import Model as _Model, rest_field if TYPE_CHECKING: from .. import models as _models -class ChildFlattenModel(_model_base.Model): +class ChildFlattenModel(_Model): """This is the child model to be flattened. And it has flattened property as well. :ivar summary: Required. @@ -69,7 +68,7 @@ def __setattr__(self, key: str, value: Any) -> None: super().__setattr__(key, value) -class ChildModel(_model_base.Model): +class ChildModel(_Model): """This is the child model to be flattened. :ivar description: Required. @@ -102,7 +101,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class FlattenModel(_model_base.Model): +class FlattenModel(_Model): """This is the model with one level of flattening. :ivar name: Required. @@ -155,7 +154,7 @@ def __setattr__(self, key: str, value: Any) -> None: super().__setattr__(key, value) -class NestedFlattenModel(_model_base.Model): +class NestedFlattenModel(_Model): """This is the model with two levels of flattening. :ivar name: Required. diff --git a/packages/typespec-python/test/azure/generated/azure-client-generator-core-usage/specs/azure/clientgenerator/core/usage/_client.py b/packages/typespec-python/test/azure/generated/azure-client-generator-core-usage/specs/azure/clientgenerator/core/usage/_client.py index 488f9f14afc..e46fc7d382d 100644 --- a/packages/typespec-python/test/azure/generated/azure-client-generator-core-usage/specs/azure/clientgenerator/core/usage/_client.py +++ b/packages/typespec-python/test/azure/generated/azure-client-generator-core-usage/specs/azure/clientgenerator/core/usage/_client.py @@ -15,7 +15,7 @@ from azure.core.rest import HttpRequest, HttpResponse from ._configuration import UsageClientConfiguration -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer from .operations import ModelInOperationOperations diff --git a/packages/typespec-python/test/azure/generated/azure-client-generator-core-usage/specs/azure/clientgenerator/core/usage/_utils/__init__.py b/packages/typespec-python/test/azure/generated/azure-client-generator-core-usage/specs/azure/clientgenerator/core/usage/_utils/__init__.py new file mode 100644 index 00000000000..8026245c2ab --- /dev/null +++ b/packages/typespec-python/test/azure/generated/azure-client-generator-core-usage/specs/azure/clientgenerator/core/usage/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) Python Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/typespec-python/test/azure/generated/azure-client-generator-core-usage/specs/azure/clientgenerator/core/usage/_model_base.py b/packages/typespec-python/test/azure/generated/azure-client-generator-core-usage/specs/azure/clientgenerator/core/usage/_utils/model_base.py similarity index 100% rename from packages/typespec-python/test/azure/generated/azure-client-generator-core-usage/specs/azure/clientgenerator/core/usage/_model_base.py rename to packages/typespec-python/test/azure/generated/azure-client-generator-core-usage/specs/azure/clientgenerator/core/usage/_utils/model_base.py diff --git a/packages/typespec-python/test/azure/generated/azure-client-generator-core-usage/specs/azure/clientgenerator/core/usage/_serialization.py b/packages/typespec-python/test/azure/generated/azure-client-generator-core-usage/specs/azure/clientgenerator/core/usage/_utils/serialization.py similarity index 100% rename from packages/typespec-python/test/azure/generated/azure-client-generator-core-usage/specs/azure/clientgenerator/core/usage/_serialization.py rename to packages/typespec-python/test/azure/generated/azure-client-generator-core-usage/specs/azure/clientgenerator/core/usage/_utils/serialization.py diff --git a/packages/typespec-python/test/azure/generated/azure-client-generator-core-usage/specs/azure/clientgenerator/core/usage/aio/_client.py b/packages/typespec-python/test/azure/generated/azure-client-generator-core-usage/specs/azure/clientgenerator/core/usage/aio/_client.py index d4044081637..e613aa05e51 100644 --- a/packages/typespec-python/test/azure/generated/azure-client-generator-core-usage/specs/azure/clientgenerator/core/usage/aio/_client.py +++ b/packages/typespec-python/test/azure/generated/azure-client-generator-core-usage/specs/azure/clientgenerator/core/usage/aio/_client.py @@ -14,7 +14,7 @@ from azure.core.pipeline import policies from azure.core.rest import AsyncHttpResponse, HttpRequest -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import UsageClientConfiguration from .operations import ModelInOperationOperations diff --git a/packages/typespec-python/test/azure/generated/azure-client-generator-core-usage/specs/azure/clientgenerator/core/usage/aio/operations/_operations.py b/packages/typespec-python/test/azure/generated/azure-client-generator-core-usage/specs/azure/clientgenerator/core/usage/aio/operations/_operations.py index 0beed326762..944ad5938bb 100644 --- a/packages/typespec-python/test/azure/generated/azure-client-generator-core-usage/specs/azure/clientgenerator/core/usage/aio/operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/azure-client-generator-core-usage/specs/azure/clientgenerator/core/usage/aio/operations/_operations.py @@ -27,8 +27,8 @@ from azure.core.utils import case_insensitive_dict from ... import models as _models -from ..._model_base import SdkJSONEncoder, _deserialize -from ..._serialization import Deserializer, Serializer +from ..._utils.model_base import SdkJSONEncoder, _deserialize +from ..._utils.serialization import Deserializer, Serializer from ...operations._operations import ( build_model_in_operation_input_to_input_output_request, build_model_in_operation_model_in_read_only_property_request, diff --git a/packages/typespec-python/test/azure/generated/azure-client-generator-core-usage/specs/azure/clientgenerator/core/usage/models/_models.py b/packages/typespec-python/test/azure/generated/azure-client-generator-core-usage/specs/azure/clientgenerator/core/usage/models/_models.py index 9126293a8fc..a894f7bbcf8 100644 --- a/packages/typespec-python/test/azure/generated/azure-client-generator-core-usage/specs/azure/clientgenerator/core/usage/models/_models.py +++ b/packages/typespec-python/test/azure/generated/azure-client-generator-core-usage/specs/azure/clientgenerator/core/usage/models/_models.py @@ -9,14 +9,13 @@ from typing import Any, Mapping, TYPE_CHECKING, overload -from .. import _model_base -from .._model_base import rest_field +from .._utils.model_base import Model as _Model, rest_field if TYPE_CHECKING: from .. import models as _models -class InputModel(_model_base.Model): +class InputModel(_Model): """Usage override to roundtrip. :ivar name: Required. @@ -44,7 +43,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class OrphanModel(_model_base.Model): +class OrphanModel(_Model): """Not used anywhere, but access is override to public so still need to be generated and exported with serialization. @@ -78,7 +77,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class OutputModel(_model_base.Model): +class OutputModel(_Model): """Usage override to roundtrip. :ivar name: Required. @@ -106,7 +105,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class ResultModel(_model_base.Model): +class ResultModel(_Model): """ResultModel. :ivar name: Required. @@ -134,7 +133,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class RoundTripModel(_model_base.Model): +class RoundTripModel(_Model): """RoundTripModel. :ivar result: Required. diff --git a/packages/typespec-python/test/azure/generated/azure-client-generator-core-usage/specs/azure/clientgenerator/core/usage/operations/_operations.py b/packages/typespec-python/test/azure/generated/azure-client-generator-core-usage/specs/azure/clientgenerator/core/usage/operations/_operations.py index 1b322b231fc..ef607bb5ff8 100644 --- a/packages/typespec-python/test/azure/generated/azure-client-generator-core-usage/specs/azure/clientgenerator/core/usage/operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/azure-client-generator-core-usage/specs/azure/clientgenerator/core/usage/operations/_operations.py @@ -28,8 +28,8 @@ from .. import models as _models from .._configuration import UsageClientConfiguration -from .._model_base import SdkJSONEncoder, _deserialize -from .._serialization import Deserializer, Serializer +from .._utils.model_base import SdkJSONEncoder, _deserialize +from .._utils.serialization import Deserializer, Serializer JSON = MutableMapping[str, Any] T = TypeVar("T") diff --git a/packages/typespec-python/test/azure/generated/azure-core-basic/specs/azure/core/basic/_client.py b/packages/typespec-python/test/azure/generated/azure-core-basic/specs/azure/core/basic/_client.py index e2e0b1a46f5..a2b73b77e3d 100644 --- a/packages/typespec-python/test/azure/generated/azure-core-basic/specs/azure/core/basic/_client.py +++ b/packages/typespec-python/test/azure/generated/azure-core-basic/specs/azure/core/basic/_client.py @@ -16,7 +16,7 @@ from ._configuration import BasicClientConfiguration from ._operations import BasicClientOperationsMixin -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer class BasicClient(BasicClientOperationsMixin): diff --git a/packages/typespec-python/test/azure/generated/azure-core-basic/specs/azure/core/basic/_operations/_operations.py b/packages/typespec-python/test/azure/generated/azure-core-basic/specs/azure/core/basic/_operations/_operations.py index 39e96c46f9c..6bbe4192085 100644 --- a/packages/typespec-python/test/azure/generated/azure-core-basic/specs/azure/core/basic/_operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/azure-core-basic/specs/azure/core/basic/_operations/_operations.py @@ -11,6 +11,7 @@ from typing import Any, Callable, Dict, IO, Iterable, List, Optional, TypeVar, Union, overload import urllib.parse +from azure.core import PipelineClient from azure.core.exceptions import ( ClientAuthenticationError, HttpResponseError, @@ -28,9 +29,10 @@ from azure.core.utils import case_insensitive_dict from .. import models as _models -from .._model_base import SdkJSONEncoder, _deserialize -from .._serialization import Serializer -from .._vendor import BasicClientMixinABC +from .._configuration import BasicClientConfiguration +from .._utils.model_base import SdkJSONEncoder, _deserialize +from .._utils.serialization import Serializer +from .._utils.utils import ClientMixinABC JSON = MutableMapping[str, Any] T = TypeVar("T") @@ -230,7 +232,7 @@ def build_basic_export_all_users_request(*, format: str, **kwargs: Any) -> HttpR return HttpRequest(method="POST", url=_url, params=_params, headers=_headers, **kwargs) -class BasicClientOperationsMixin(BasicClientMixinABC): +class BasicClientOperationsMixin(ClientMixinABC[PipelineClient, BasicClientConfiguration]): @overload def create_or_update( diff --git a/packages/typespec-python/test/azure/generated/azure-core-basic/specs/azure/core/basic/_utils/__init__.py b/packages/typespec-python/test/azure/generated/azure-core-basic/specs/azure/core/basic/_utils/__init__.py new file mode 100644 index 00000000000..8026245c2ab --- /dev/null +++ b/packages/typespec-python/test/azure/generated/azure-core-basic/specs/azure/core/basic/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) Python Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/typespec-python/test/azure/generated/azure-core-basic/specs/azure/core/basic/_model_base.py b/packages/typespec-python/test/azure/generated/azure-core-basic/specs/azure/core/basic/_utils/model_base.py similarity index 100% rename from packages/typespec-python/test/azure/generated/azure-core-basic/specs/azure/core/basic/_model_base.py rename to packages/typespec-python/test/azure/generated/azure-core-basic/specs/azure/core/basic/_utils/model_base.py diff --git a/packages/typespec-python/test/azure/generated/azure-core-basic/specs/azure/core/basic/_serialization.py b/packages/typespec-python/test/azure/generated/azure-core-basic/specs/azure/core/basic/_utils/serialization.py similarity index 100% rename from packages/typespec-python/test/azure/generated/azure-core-basic/specs/azure/core/basic/_serialization.py rename to packages/typespec-python/test/azure/generated/azure-core-basic/specs/azure/core/basic/_utils/serialization.py diff --git a/packages/typespec-python/test/azure/generated/azure-core-basic/specs/azure/core/basic/_utils/utils.py b/packages/typespec-python/test/azure/generated/azure-core-basic/specs/azure/core/basic/_utils/utils.py new file mode 100644 index 00000000000..35c9c836f85 --- /dev/null +++ b/packages/typespec-python/test/azure/generated/azure-core-basic/specs/azure/core/basic/_utils/utils.py @@ -0,0 +1,25 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) Python Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from abc import ABC +from typing import Generic, TYPE_CHECKING, TypeVar + +if TYPE_CHECKING: + from .serialization import Deserializer, Serializer + + +TClient = TypeVar("TClient") +TConfig = TypeVar("TConfig") + + +class ClientMixinABC(ABC, Generic[TClient, TConfig]): + """DO NOT use this class. It is for internal typing use only.""" + + _client: TClient + _config: TConfig + _serialize: "Serializer" + _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/azure/generated/azure-core-basic/specs/azure/core/basic/_vendor.py b/packages/typespec-python/test/azure/generated/azure-core-basic/specs/azure/core/basic/_vendor.py deleted file mode 100644 index a9646cc0a20..00000000000 --- a/packages/typespec-python/test/azure/generated/azure-core-basic/specs/azure/core/basic/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) Python Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import BasicClientConfiguration - -if TYPE_CHECKING: - from azure.core import PipelineClient - - from ._serialization import Deserializer, Serializer - - -class BasicClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "PipelineClient" - _config: BasicClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/azure/generated/azure-core-basic/specs/azure/core/basic/aio/_client.py b/packages/typespec-python/test/azure/generated/azure-core-basic/specs/azure/core/basic/aio/_client.py index 7b6fe116f38..4b1915f1edd 100644 --- a/packages/typespec-python/test/azure/generated/azure-core-basic/specs/azure/core/basic/aio/_client.py +++ b/packages/typespec-python/test/azure/generated/azure-core-basic/specs/azure/core/basic/aio/_client.py @@ -14,7 +14,7 @@ from azure.core.pipeline import policies from azure.core.rest import AsyncHttpResponse, HttpRequest -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import BasicClientConfiguration from ._operations import BasicClientOperationsMixin diff --git a/packages/typespec-python/test/azure/generated/azure-core-basic/specs/azure/core/basic/aio/_operations/_operations.py b/packages/typespec-python/test/azure/generated/azure-core-basic/specs/azure/core/basic/aio/_operations/_operations.py index 037d6df80f2..b95d5756f4c 100644 --- a/packages/typespec-python/test/azure/generated/azure-core-basic/specs/azure/core/basic/aio/_operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/azure-core-basic/specs/azure/core/basic/aio/_operations/_operations.py @@ -12,6 +12,7 @@ from typing import Any, AsyncIterable, Callable, Dict, IO, List, Optional, TypeVar, Union, overload import urllib.parse +from azure.core import AsyncPipelineClient from azure.core.async_paging import AsyncItemPaged, AsyncList from azure.core.exceptions import ( ClientAuthenticationError, @@ -30,7 +31,6 @@ from azure.core.utils import case_insensitive_dict from ... import models as _models -from ..._model_base import SdkJSONEncoder, _deserialize from ..._operations._operations import ( build_basic_create_or_replace_request, build_basic_create_or_update_request, @@ -40,14 +40,16 @@ build_basic_get_request, build_basic_list_request, ) -from .._vendor import BasicClientMixinABC +from ..._utils.model_base import SdkJSONEncoder, _deserialize +from ..._utils.utils import ClientMixinABC +from .._configuration import BasicClientConfiguration JSON = MutableMapping[str, Any] T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, AsyncHttpResponse], T, Dict[str, Any]], Any]] -class BasicClientOperationsMixin(BasicClientMixinABC): +class BasicClientOperationsMixin(ClientMixinABC[AsyncPipelineClient, BasicClientConfiguration]): @overload async def create_or_update( diff --git a/packages/typespec-python/test/azure/generated/azure-core-basic/specs/azure/core/basic/aio/_vendor.py b/packages/typespec-python/test/azure/generated/azure-core-basic/specs/azure/core/basic/aio/_vendor.py deleted file mode 100644 index 1adc29db48d..00000000000 --- a/packages/typespec-python/test/azure/generated/azure-core-basic/specs/azure/core/basic/aio/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) Python Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import BasicClientConfiguration - -if TYPE_CHECKING: - from azure.core import AsyncPipelineClient - - from .._serialization import Deserializer, Serializer - - -class BasicClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "AsyncPipelineClient" - _config: BasicClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/azure/generated/azure-core-basic/specs/azure/core/basic/models/_models.py b/packages/typespec-python/test/azure/generated/azure-core-basic/specs/azure/core/basic/models/_models.py index d0765992b9e..aa5658cb411 100644 --- a/packages/typespec-python/test/azure/generated/azure-core-basic/specs/azure/core/basic/models/_models.py +++ b/packages/typespec-python/test/azure/generated/azure-core-basic/specs/azure/core/basic/models/_models.py @@ -9,14 +9,13 @@ from typing import Any, List, Mapping, Optional, TYPE_CHECKING, overload -from .. import _model_base -from .._model_base import rest_field +from .._utils.model_base import Model as _Model, rest_field if TYPE_CHECKING: from .. import models as _models -class User(_model_base.Model): +class User(_Model): """Details about a user. :ivar id: The user's id. Required. @@ -57,7 +56,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class UserList(_model_base.Model): +class UserList(_Model): """UserList. :ivar users: Required. @@ -85,7 +84,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class UserOrder(_model_base.Model): +class UserOrder(_Model): """UserOrder for testing list with expand. :ivar id: The user's id. Required. diff --git a/packages/typespec-python/test/azure/generated/azure-core-lro-rpc/specs/azure/core/lro/rpc/_client.py b/packages/typespec-python/test/azure/generated/azure-core-lro-rpc/specs/azure/core/lro/rpc/_client.py index 5406ce3de2b..7afdf2069bb 100644 --- a/packages/typespec-python/test/azure/generated/azure-core-lro-rpc/specs/azure/core/lro/rpc/_client.py +++ b/packages/typespec-python/test/azure/generated/azure-core-lro-rpc/specs/azure/core/lro/rpc/_client.py @@ -16,7 +16,7 @@ from ._configuration import RpcClientConfiguration from ._operations import RpcClientOperationsMixin -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer class RpcClient(RpcClientOperationsMixin): diff --git a/packages/typespec-python/test/azure/generated/azure-core-lro-rpc/specs/azure/core/lro/rpc/_operations/_operations.py b/packages/typespec-python/test/azure/generated/azure-core-lro-rpc/specs/azure/core/lro/rpc/_operations/_operations.py index 556fc03668a..ab01f4666e6 100644 --- a/packages/typespec-python/test/azure/generated/azure-core-lro-rpc/specs/azure/core/lro/rpc/_operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/azure-core-lro-rpc/specs/azure/core/lro/rpc/_operations/_operations.py @@ -10,6 +10,7 @@ import json from typing import Any, Callable, Dict, IO, Iterator, Optional, TypeVar, Union, cast, overload +from azure.core import PipelineClient from azure.core.exceptions import ( ClientAuthenticationError, HttpResponseError, @@ -28,9 +29,10 @@ from azure.core.utils import case_insensitive_dict from .. import models as _models -from .._model_base import SdkJSONEncoder, _deserialize -from .._serialization import Serializer -from .._vendor import RpcClientMixinABC +from .._configuration import RpcClientConfiguration +from .._utils.model_base import SdkJSONEncoder, _deserialize +from .._utils.serialization import Serializer +from .._utils.utils import ClientMixinABC JSON = MutableMapping[str, Any] T = TypeVar("T") @@ -62,7 +64,7 @@ def build_rpc_long_running_rpc_request(**kwargs: Any) -> HttpRequest: return HttpRequest(method="POST", url=_url, params=_params, headers=_headers, **kwargs) -class RpcClientOperationsMixin(RpcClientMixinABC): +class RpcClientOperationsMixin(ClientMixinABC[PipelineClient, RpcClientConfiguration]): def _long_running_rpc_initial( self, body: Union[_models.GenerationOptions, JSON, IO[bytes]], **kwargs: Any diff --git a/packages/typespec-python/test/azure/generated/azure-core-lro-rpc/specs/azure/core/lro/rpc/_utils/__init__.py b/packages/typespec-python/test/azure/generated/azure-core-lro-rpc/specs/azure/core/lro/rpc/_utils/__init__.py new file mode 100644 index 00000000000..8026245c2ab --- /dev/null +++ b/packages/typespec-python/test/azure/generated/azure-core-lro-rpc/specs/azure/core/lro/rpc/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) Python Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/typespec-python/test/azure/generated/azure-core-lro-rpc/specs/azure/core/lro/rpc/_model_base.py b/packages/typespec-python/test/azure/generated/azure-core-lro-rpc/specs/azure/core/lro/rpc/_utils/model_base.py similarity index 100% rename from packages/typespec-python/test/azure/generated/azure-core-lro-rpc/specs/azure/core/lro/rpc/_model_base.py rename to packages/typespec-python/test/azure/generated/azure-core-lro-rpc/specs/azure/core/lro/rpc/_utils/model_base.py diff --git a/packages/typespec-python/test/azure/generated/azure-core-lro-rpc/specs/azure/core/lro/rpc/_serialization.py b/packages/typespec-python/test/azure/generated/azure-core-lro-rpc/specs/azure/core/lro/rpc/_utils/serialization.py similarity index 100% rename from packages/typespec-python/test/azure/generated/azure-core-lro-rpc/specs/azure/core/lro/rpc/_serialization.py rename to packages/typespec-python/test/azure/generated/azure-core-lro-rpc/specs/azure/core/lro/rpc/_utils/serialization.py diff --git a/packages/typespec-python/test/azure/generated/azure-core-lro-rpc/specs/azure/core/lro/rpc/_utils/utils.py b/packages/typespec-python/test/azure/generated/azure-core-lro-rpc/specs/azure/core/lro/rpc/_utils/utils.py new file mode 100644 index 00000000000..35c9c836f85 --- /dev/null +++ b/packages/typespec-python/test/azure/generated/azure-core-lro-rpc/specs/azure/core/lro/rpc/_utils/utils.py @@ -0,0 +1,25 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) Python Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from abc import ABC +from typing import Generic, TYPE_CHECKING, TypeVar + +if TYPE_CHECKING: + from .serialization import Deserializer, Serializer + + +TClient = TypeVar("TClient") +TConfig = TypeVar("TConfig") + + +class ClientMixinABC(ABC, Generic[TClient, TConfig]): + """DO NOT use this class. It is for internal typing use only.""" + + _client: TClient + _config: TConfig + _serialize: "Serializer" + _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/azure/generated/azure-core-lro-rpc/specs/azure/core/lro/rpc/_vendor.py b/packages/typespec-python/test/azure/generated/azure-core-lro-rpc/specs/azure/core/lro/rpc/_vendor.py deleted file mode 100644 index 15a90450617..00000000000 --- a/packages/typespec-python/test/azure/generated/azure-core-lro-rpc/specs/azure/core/lro/rpc/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) Python Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import RpcClientConfiguration - -if TYPE_CHECKING: - from azure.core import PipelineClient - - from ._serialization import Deserializer, Serializer - - -class RpcClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "PipelineClient" - _config: RpcClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/azure/generated/azure-core-lro-rpc/specs/azure/core/lro/rpc/aio/_client.py b/packages/typespec-python/test/azure/generated/azure-core-lro-rpc/specs/azure/core/lro/rpc/aio/_client.py index d5143bb3040..e8c1ff14f39 100644 --- a/packages/typespec-python/test/azure/generated/azure-core-lro-rpc/specs/azure/core/lro/rpc/aio/_client.py +++ b/packages/typespec-python/test/azure/generated/azure-core-lro-rpc/specs/azure/core/lro/rpc/aio/_client.py @@ -14,7 +14,7 @@ from azure.core.pipeline import policies from azure.core.rest import AsyncHttpResponse, HttpRequest -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import RpcClientConfiguration from ._operations import RpcClientOperationsMixin diff --git a/packages/typespec-python/test/azure/generated/azure-core-lro-rpc/specs/azure/core/lro/rpc/aio/_operations/_operations.py b/packages/typespec-python/test/azure/generated/azure-core-lro-rpc/specs/azure/core/lro/rpc/aio/_operations/_operations.py index 31b506b6cda..6f555d53957 100644 --- a/packages/typespec-python/test/azure/generated/azure-core-lro-rpc/specs/azure/core/lro/rpc/aio/_operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/azure-core-lro-rpc/specs/azure/core/lro/rpc/aio/_operations/_operations.py @@ -11,6 +11,7 @@ import json from typing import Any, AsyncIterator, Callable, Dict, IO, Optional, TypeVar, Union, cast, overload +from azure.core import AsyncPipelineClient from azure.core.exceptions import ( ClientAuthenticationError, HttpResponseError, @@ -29,16 +30,17 @@ from azure.core.utils import case_insensitive_dict from ... import models as _models -from ..._model_base import SdkJSONEncoder, _deserialize from ..._operations._operations import build_rpc_long_running_rpc_request -from .._vendor import RpcClientMixinABC +from ..._utils.model_base import SdkJSONEncoder, _deserialize +from ..._utils.utils import ClientMixinABC +from .._configuration import RpcClientConfiguration JSON = MutableMapping[str, Any] T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, AsyncHttpResponse], T, Dict[str, Any]], Any]] -class RpcClientOperationsMixin(RpcClientMixinABC): +class RpcClientOperationsMixin(ClientMixinABC[AsyncPipelineClient, RpcClientConfiguration]): async def _long_running_rpc_initial( self, body: Union[_models.GenerationOptions, JSON, IO[bytes]], **kwargs: Any diff --git a/packages/typespec-python/test/azure/generated/azure-core-lro-rpc/specs/azure/core/lro/rpc/aio/_vendor.py b/packages/typespec-python/test/azure/generated/azure-core-lro-rpc/specs/azure/core/lro/rpc/aio/_vendor.py deleted file mode 100644 index 9e0cd032e1d..00000000000 --- a/packages/typespec-python/test/azure/generated/azure-core-lro-rpc/specs/azure/core/lro/rpc/aio/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) Python Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import RpcClientConfiguration - -if TYPE_CHECKING: - from azure.core import AsyncPipelineClient - - from .._serialization import Deserializer, Serializer - - -class RpcClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "AsyncPipelineClient" - _config: RpcClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/azure/generated/azure-core-lro-rpc/specs/azure/core/lro/rpc/models/_models.py b/packages/typespec-python/test/azure/generated/azure-core-lro-rpc/specs/azure/core/lro/rpc/models/_models.py index 27c76591a96..be0900af492 100644 --- a/packages/typespec-python/test/azure/generated/azure-core-lro-rpc/specs/azure/core/lro/rpc/models/_models.py +++ b/packages/typespec-python/test/azure/generated/azure-core-lro-rpc/specs/azure/core/lro/rpc/models/_models.py @@ -9,11 +9,10 @@ from typing import Any, Mapping, overload -from .. import _model_base -from .._model_base import rest_field +from .._utils.model_base import Model as _Model, rest_field -class GenerationOptions(_model_base.Model): +class GenerationOptions(_Model): """Options for the generation. :ivar prompt: Prompt. Required. @@ -41,7 +40,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class GenerationResult(_model_base.Model): +class GenerationResult(_Model): """Result of the generation. :ivar data: The data. Required. diff --git a/packages/typespec-python/test/azure/generated/azure-core-lro-standard/specs/azure/core/lro/standard/_client.py b/packages/typespec-python/test/azure/generated/azure-core-lro-standard/specs/azure/core/lro/standard/_client.py index aa8957f4afe..94247511a2f 100644 --- a/packages/typespec-python/test/azure/generated/azure-core-lro-standard/specs/azure/core/lro/standard/_client.py +++ b/packages/typespec-python/test/azure/generated/azure-core-lro-standard/specs/azure/core/lro/standard/_client.py @@ -16,7 +16,7 @@ from ._configuration import StandardClientConfiguration from ._operations import StandardClientOperationsMixin -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer class StandardClient(StandardClientOperationsMixin): diff --git a/packages/typespec-python/test/azure/generated/azure-core-lro-standard/specs/azure/core/lro/standard/_operations/_operations.py b/packages/typespec-python/test/azure/generated/azure-core-lro-standard/specs/azure/core/lro/standard/_operations/_operations.py index 43936f86c48..1635c6ab94d 100644 --- a/packages/typespec-python/test/azure/generated/azure-core-lro-standard/specs/azure/core/lro/standard/_operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/azure-core-lro-standard/specs/azure/core/lro/standard/_operations/_operations.py @@ -10,6 +10,7 @@ import json from typing import Any, Callable, Dict, IO, Iterator, Optional, TypeVar, Union, cast, overload +from azure.core import PipelineClient from azure.core.exceptions import ( ClientAuthenticationError, HttpResponseError, @@ -28,9 +29,10 @@ from azure.core.utils import case_insensitive_dict from .. import models as _models -from .._model_base import SdkJSONEncoder, _deserialize -from .._serialization import Serializer -from .._vendor import StandardClientMixinABC +from .._configuration import StandardClientConfiguration +from .._utils.model_base import SdkJSONEncoder, _deserialize +from .._utils.serialization import Serializer +from .._utils.utils import ClientMixinABC JSON = MutableMapping[str, Any] T = TypeVar("T") @@ -116,7 +118,7 @@ def build_standard_export_request(name: str, *, format: str, **kwargs: Any) -> H return HttpRequest(method="POST", url=_url, params=_params, headers=_headers, **kwargs) -class StandardClientOperationsMixin(StandardClientMixinABC): +class StandardClientOperationsMixin(ClientMixinABC[PipelineClient, StandardClientConfiguration]): def _create_or_replace_initial( self, name: str, resource: Union[_models.User, JSON, IO[bytes]], **kwargs: Any diff --git a/packages/typespec-python/test/azure/generated/azure-core-lro-standard/specs/azure/core/lro/standard/_utils/__init__.py b/packages/typespec-python/test/azure/generated/azure-core-lro-standard/specs/azure/core/lro/standard/_utils/__init__.py new file mode 100644 index 00000000000..8026245c2ab --- /dev/null +++ b/packages/typespec-python/test/azure/generated/azure-core-lro-standard/specs/azure/core/lro/standard/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) Python Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/typespec-python/test/azure/generated/azure-core-lro-standard/specs/azure/core/lro/standard/_model_base.py b/packages/typespec-python/test/azure/generated/azure-core-lro-standard/specs/azure/core/lro/standard/_utils/model_base.py similarity index 100% rename from packages/typespec-python/test/azure/generated/azure-core-lro-standard/specs/azure/core/lro/standard/_model_base.py rename to packages/typespec-python/test/azure/generated/azure-core-lro-standard/specs/azure/core/lro/standard/_utils/model_base.py diff --git a/packages/typespec-python/test/azure/generated/azure-core-lro-standard/specs/azure/core/lro/standard/_serialization.py b/packages/typespec-python/test/azure/generated/azure-core-lro-standard/specs/azure/core/lro/standard/_utils/serialization.py similarity index 100% rename from packages/typespec-python/test/azure/generated/azure-core-lro-standard/specs/azure/core/lro/standard/_serialization.py rename to packages/typespec-python/test/azure/generated/azure-core-lro-standard/specs/azure/core/lro/standard/_utils/serialization.py diff --git a/packages/typespec-python/test/azure/generated/azure-core-lro-standard/specs/azure/core/lro/standard/_utils/utils.py b/packages/typespec-python/test/azure/generated/azure-core-lro-standard/specs/azure/core/lro/standard/_utils/utils.py new file mode 100644 index 00000000000..35c9c836f85 --- /dev/null +++ b/packages/typespec-python/test/azure/generated/azure-core-lro-standard/specs/azure/core/lro/standard/_utils/utils.py @@ -0,0 +1,25 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) Python Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from abc import ABC +from typing import Generic, TYPE_CHECKING, TypeVar + +if TYPE_CHECKING: + from .serialization import Deserializer, Serializer + + +TClient = TypeVar("TClient") +TConfig = TypeVar("TConfig") + + +class ClientMixinABC(ABC, Generic[TClient, TConfig]): + """DO NOT use this class. It is for internal typing use only.""" + + _client: TClient + _config: TConfig + _serialize: "Serializer" + _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/azure/generated/azure-core-lro-standard/specs/azure/core/lro/standard/_vendor.py b/packages/typespec-python/test/azure/generated/azure-core-lro-standard/specs/azure/core/lro/standard/_vendor.py deleted file mode 100644 index 89c21215746..00000000000 --- a/packages/typespec-python/test/azure/generated/azure-core-lro-standard/specs/azure/core/lro/standard/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) Python Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import StandardClientConfiguration - -if TYPE_CHECKING: - from azure.core import PipelineClient - - from ._serialization import Deserializer, Serializer - - -class StandardClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "PipelineClient" - _config: StandardClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/azure/generated/azure-core-lro-standard/specs/azure/core/lro/standard/aio/_client.py b/packages/typespec-python/test/azure/generated/azure-core-lro-standard/specs/azure/core/lro/standard/aio/_client.py index 00be7ffa09b..3504703940e 100644 --- a/packages/typespec-python/test/azure/generated/azure-core-lro-standard/specs/azure/core/lro/standard/aio/_client.py +++ b/packages/typespec-python/test/azure/generated/azure-core-lro-standard/specs/azure/core/lro/standard/aio/_client.py @@ -14,7 +14,7 @@ from azure.core.pipeline import policies from azure.core.rest import AsyncHttpResponse, HttpRequest -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import StandardClientConfiguration from ._operations import StandardClientOperationsMixin diff --git a/packages/typespec-python/test/azure/generated/azure-core-lro-standard/specs/azure/core/lro/standard/aio/_operations/_operations.py b/packages/typespec-python/test/azure/generated/azure-core-lro-standard/specs/azure/core/lro/standard/aio/_operations/_operations.py index 75522377ab7..40f717258ea 100644 --- a/packages/typespec-python/test/azure/generated/azure-core-lro-standard/specs/azure/core/lro/standard/aio/_operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/azure-core-lro-standard/specs/azure/core/lro/standard/aio/_operations/_operations.py @@ -11,6 +11,7 @@ import json from typing import Any, AsyncIterator, Callable, Dict, IO, Optional, TypeVar, Union, cast, overload +from azure.core import AsyncPipelineClient from azure.core.exceptions import ( ClientAuthenticationError, HttpResponseError, @@ -29,20 +30,21 @@ from azure.core.utils import case_insensitive_dict from ... import models as _models -from ..._model_base import SdkJSONEncoder, _deserialize from ..._operations._operations import ( build_standard_create_or_replace_request, build_standard_delete_request, build_standard_export_request, ) -from .._vendor import StandardClientMixinABC +from ..._utils.model_base import SdkJSONEncoder, _deserialize +from ..._utils.utils import ClientMixinABC +from .._configuration import StandardClientConfiguration JSON = MutableMapping[str, Any] T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, AsyncHttpResponse], T, Dict[str, Any]], Any]] -class StandardClientOperationsMixin(StandardClientMixinABC): +class StandardClientOperationsMixin(ClientMixinABC[AsyncPipelineClient, StandardClientConfiguration]): async def _create_or_replace_initial( self, name: str, resource: Union[_models.User, JSON, IO[bytes]], **kwargs: Any diff --git a/packages/typespec-python/test/azure/generated/azure-core-lro-standard/specs/azure/core/lro/standard/aio/_vendor.py b/packages/typespec-python/test/azure/generated/azure-core-lro-standard/specs/azure/core/lro/standard/aio/_vendor.py deleted file mode 100644 index 4461082402a..00000000000 --- a/packages/typespec-python/test/azure/generated/azure-core-lro-standard/specs/azure/core/lro/standard/aio/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) Python Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import StandardClientConfiguration - -if TYPE_CHECKING: - from azure.core import AsyncPipelineClient - - from .._serialization import Deserializer, Serializer - - -class StandardClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "AsyncPipelineClient" - _config: StandardClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/azure/generated/azure-core-lro-standard/specs/azure/core/lro/standard/models/_models.py b/packages/typespec-python/test/azure/generated/azure-core-lro-standard/specs/azure/core/lro/standard/models/_models.py index 5dc2ba3e241..9de7f18d22b 100644 --- a/packages/typespec-python/test/azure/generated/azure-core-lro-standard/specs/azure/core/lro/standard/models/_models.py +++ b/packages/typespec-python/test/azure/generated/azure-core-lro-standard/specs/azure/core/lro/standard/models/_models.py @@ -9,11 +9,10 @@ from typing import Any, Mapping, overload -from .. import _model_base -from .._model_base import rest_field +from .._utils.model_base import Model as _Model, rest_field -class ExportedUser(_model_base.Model): +class ExportedUser(_Model): """The exported user data. :ivar name: The name of user. Required. @@ -46,7 +45,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class User(_model_base.Model): +class User(_Model): """Details about a user. :ivar name: The name of user. Required. diff --git a/packages/typespec-python/test/azure/generated/azure-core-model/specs/azure/core/model/_client.py b/packages/typespec-python/test/azure/generated/azure-core-model/specs/azure/core/model/_client.py index 0a0ab96cc5f..e058323504f 100644 --- a/packages/typespec-python/test/azure/generated/azure-core-model/specs/azure/core/model/_client.py +++ b/packages/typespec-python/test/azure/generated/azure-core-model/specs/azure/core/model/_client.py @@ -15,7 +15,7 @@ from azure.core.rest import HttpRequest, HttpResponse from ._configuration import ModelClientConfiguration -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer from .operations import AzureCoreEmbeddingVectorOperations diff --git a/packages/typespec-python/test/azure/generated/azure-core-model/specs/azure/core/model/_utils/__init__.py b/packages/typespec-python/test/azure/generated/azure-core-model/specs/azure/core/model/_utils/__init__.py new file mode 100644 index 00000000000..8026245c2ab --- /dev/null +++ b/packages/typespec-python/test/azure/generated/azure-core-model/specs/azure/core/model/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) Python Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/typespec-python/test/azure/generated/azure-core-model/specs/azure/core/model/_model_base.py b/packages/typespec-python/test/azure/generated/azure-core-model/specs/azure/core/model/_utils/model_base.py similarity index 100% rename from packages/typespec-python/test/azure/generated/azure-core-model/specs/azure/core/model/_model_base.py rename to packages/typespec-python/test/azure/generated/azure-core-model/specs/azure/core/model/_utils/model_base.py diff --git a/packages/typespec-python/test/azure/generated/azure-core-model/specs/azure/core/model/_serialization.py b/packages/typespec-python/test/azure/generated/azure-core-model/specs/azure/core/model/_utils/serialization.py similarity index 100% rename from packages/typespec-python/test/azure/generated/azure-core-model/specs/azure/core/model/_serialization.py rename to packages/typespec-python/test/azure/generated/azure-core-model/specs/azure/core/model/_utils/serialization.py diff --git a/packages/typespec-python/test/azure/generated/azure-core-model/specs/azure/core/model/aio/_client.py b/packages/typespec-python/test/azure/generated/azure-core-model/specs/azure/core/model/aio/_client.py index 4af89e37fa7..13c47c2bae1 100644 --- a/packages/typespec-python/test/azure/generated/azure-core-model/specs/azure/core/model/aio/_client.py +++ b/packages/typespec-python/test/azure/generated/azure-core-model/specs/azure/core/model/aio/_client.py @@ -14,7 +14,7 @@ from azure.core.pipeline import policies from azure.core.rest import AsyncHttpResponse, HttpRequest -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import ModelClientConfiguration from .operations import AzureCoreEmbeddingVectorOperations diff --git a/packages/typespec-python/test/azure/generated/azure-core-model/specs/azure/core/model/aio/operations/_operations.py b/packages/typespec-python/test/azure/generated/azure-core-model/specs/azure/core/model/aio/operations/_operations.py index 10fe463b06e..47b98789df2 100644 --- a/packages/typespec-python/test/azure/generated/azure-core-model/specs/azure/core/model/aio/operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/azure-core-model/specs/azure/core/model/aio/operations/_operations.py @@ -27,8 +27,8 @@ from azure.core.utils import case_insensitive_dict from ... import models as _models -from ..._model_base import SdkJSONEncoder, _deserialize -from ..._serialization import Deserializer, Serializer +from ..._utils.model_base import SdkJSONEncoder, _deserialize +from ..._utils.serialization import Deserializer, Serializer from ...operations._operations import ( build_azure_core_embedding_vector_get_request, build_azure_core_embedding_vector_post_request, diff --git a/packages/typespec-python/test/azure/generated/azure-core-model/specs/azure/core/model/models/_models.py b/packages/typespec-python/test/azure/generated/azure-core-model/specs/azure/core/model/models/_models.py index a6e7328c818..abb44804e4d 100644 --- a/packages/typespec-python/test/azure/generated/azure-core-model/specs/azure/core/model/models/_models.py +++ b/packages/typespec-python/test/azure/generated/azure-core-model/specs/azure/core/model/models/_models.py @@ -9,11 +9,10 @@ from typing import Any, List, Mapping, overload -from .. import _model_base -from .._model_base import rest_field +from .._utils.model_base import Model as _Model, rest_field -class AzureEmbeddingModel(_model_base.Model): +class AzureEmbeddingModel(_Model): """AzureEmbeddingModel. :ivar embedding: Required. diff --git a/packages/typespec-python/test/azure/generated/azure-core-model/specs/azure/core/model/operations/_operations.py b/packages/typespec-python/test/azure/generated/azure-core-model/specs/azure/core/model/operations/_operations.py index 231406ed609..9594dfbed9e 100644 --- a/packages/typespec-python/test/azure/generated/azure-core-model/specs/azure/core/model/operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/azure-core-model/specs/azure/core/model/operations/_operations.py @@ -28,8 +28,8 @@ from .. import models as _models from .._configuration import ModelClientConfiguration -from .._model_base import SdkJSONEncoder, _deserialize -from .._serialization import Deserializer, Serializer +from .._utils.model_base import SdkJSONEncoder, _deserialize +from .._utils.serialization import Deserializer, Serializer JSON = MutableMapping[str, Any] T = TypeVar("T") diff --git a/packages/typespec-python/test/azure/generated/azure-core-page/specs/azure/core/page/_client.py b/packages/typespec-python/test/azure/generated/azure-core-page/specs/azure/core/page/_client.py index f527f5a60a8..40dafce202d 100644 --- a/packages/typespec-python/test/azure/generated/azure-core-page/specs/azure/core/page/_client.py +++ b/packages/typespec-python/test/azure/generated/azure-core-page/specs/azure/core/page/_client.py @@ -15,7 +15,7 @@ from azure.core.rest import HttpRequest, HttpResponse from ._configuration import PageClientConfiguration -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer from .operations import PageClientOperationsMixin, TwoModelsAsPageItemOperations diff --git a/packages/typespec-python/test/azure/generated/azure-core-page/specs/azure/core/page/_utils/__init__.py b/packages/typespec-python/test/azure/generated/azure-core-page/specs/azure/core/page/_utils/__init__.py new file mode 100644 index 00000000000..8026245c2ab --- /dev/null +++ b/packages/typespec-python/test/azure/generated/azure-core-page/specs/azure/core/page/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) Python Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/typespec-python/test/azure/generated/azure-core-page/specs/azure/core/page/_model_base.py b/packages/typespec-python/test/azure/generated/azure-core-page/specs/azure/core/page/_utils/model_base.py similarity index 100% rename from packages/typespec-python/test/azure/generated/azure-core-page/specs/azure/core/page/_model_base.py rename to packages/typespec-python/test/azure/generated/azure-core-page/specs/azure/core/page/_utils/model_base.py diff --git a/packages/typespec-python/test/azure/generated/azure-core-page/specs/azure/core/page/_serialization.py b/packages/typespec-python/test/azure/generated/azure-core-page/specs/azure/core/page/_utils/serialization.py similarity index 100% rename from packages/typespec-python/test/azure/generated/azure-core-page/specs/azure/core/page/_serialization.py rename to packages/typespec-python/test/azure/generated/azure-core-page/specs/azure/core/page/_utils/serialization.py diff --git a/packages/typespec-python/test/azure/generated/azure-core-page/specs/azure/core/page/_utils/utils.py b/packages/typespec-python/test/azure/generated/azure-core-page/specs/azure/core/page/_utils/utils.py new file mode 100644 index 00000000000..35c9c836f85 --- /dev/null +++ b/packages/typespec-python/test/azure/generated/azure-core-page/specs/azure/core/page/_utils/utils.py @@ -0,0 +1,25 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) Python Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from abc import ABC +from typing import Generic, TYPE_CHECKING, TypeVar + +if TYPE_CHECKING: + from .serialization import Deserializer, Serializer + + +TClient = TypeVar("TClient") +TConfig = TypeVar("TConfig") + + +class ClientMixinABC(ABC, Generic[TClient, TConfig]): + """DO NOT use this class. It is for internal typing use only.""" + + _client: TClient + _config: TConfig + _serialize: "Serializer" + _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/azure/generated/azure-core-page/specs/azure/core/page/_vendor.py b/packages/typespec-python/test/azure/generated/azure-core-page/specs/azure/core/page/_vendor.py deleted file mode 100644 index d4b6b2a9067..00000000000 --- a/packages/typespec-python/test/azure/generated/azure-core-page/specs/azure/core/page/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) Python Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import PageClientConfiguration - -if TYPE_CHECKING: - from azure.core import PipelineClient - - from ._serialization import Deserializer, Serializer - - -class PageClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "PipelineClient" - _config: PageClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/azure/generated/azure-core-page/specs/azure/core/page/aio/_client.py b/packages/typespec-python/test/azure/generated/azure-core-page/specs/azure/core/page/aio/_client.py index eff8a6a3208..c4cf50e607a 100644 --- a/packages/typespec-python/test/azure/generated/azure-core-page/specs/azure/core/page/aio/_client.py +++ b/packages/typespec-python/test/azure/generated/azure-core-page/specs/azure/core/page/aio/_client.py @@ -14,7 +14,7 @@ from azure.core.pipeline import policies from azure.core.rest import AsyncHttpResponse, HttpRequest -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import PageClientConfiguration from .operations import PageClientOperationsMixin, TwoModelsAsPageItemOperations diff --git a/packages/typespec-python/test/azure/generated/azure-core-page/specs/azure/core/page/aio/_vendor.py b/packages/typespec-python/test/azure/generated/azure-core-page/specs/azure/core/page/aio/_vendor.py deleted file mode 100644 index 8d99e4023fd..00000000000 --- a/packages/typespec-python/test/azure/generated/azure-core-page/specs/azure/core/page/aio/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) Python Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import PageClientConfiguration - -if TYPE_CHECKING: - from azure.core import AsyncPipelineClient - - from .._serialization import Deserializer, Serializer - - -class PageClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "AsyncPipelineClient" - _config: PageClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/azure/generated/azure-core-page/specs/azure/core/page/aio/operations/_operations.py b/packages/typespec-python/test/azure/generated/azure-core-page/specs/azure/core/page/aio/operations/_operations.py index 0e8adcd0594..eb9bbb3672a 100644 --- a/packages/typespec-python/test/azure/generated/azure-core-page/specs/azure/core/page/aio/operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/azure-core-page/specs/azure/core/page/aio/operations/_operations.py @@ -28,8 +28,9 @@ from azure.core.utils import case_insensitive_dict from ... import models as _models -from ..._model_base import SdkJSONEncoder, _deserialize -from ..._serialization import Deserializer, Serializer +from ..._utils.model_base import SdkJSONEncoder, _deserialize +from ..._utils.serialization import Deserializer, Serializer +from ..._utils.utils import ClientMixinABC from ...operations._operations import ( build_page_list_with_custom_page_model_request, build_page_list_with_page_request, @@ -39,7 +40,6 @@ build_two_models_as_page_item_list_second_item_request, ) from .._configuration import PageClientConfiguration -from .._vendor import PageClientMixinABC T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, AsyncHttpResponse], T, Dict[str, Any]], Any]] @@ -230,7 +230,7 @@ async def get_next(next_link=None): return AsyncItemPaged(get_next, extract_data) -class PageClientOperationsMixin(PageClientMixinABC): +class PageClientOperationsMixin(ClientMixinABC[AsyncPipelineClient, PageClientConfiguration]): @distributed_trace def list_with_page(self, **kwargs: Any) -> AsyncIterable["_models.User"]: diff --git a/packages/typespec-python/test/azure/generated/azure-core-page/specs/azure/core/page/models/_models.py b/packages/typespec-python/test/azure/generated/azure-core-page/specs/azure/core/page/models/_models.py index ac2679648e5..cf3416a4b17 100644 --- a/packages/typespec-python/test/azure/generated/azure-core-page/specs/azure/core/page/models/_models.py +++ b/packages/typespec-python/test/azure/generated/azure-core-page/specs/azure/core/page/models/_models.py @@ -9,14 +9,13 @@ from typing import Any, List, Mapping, Optional, TYPE_CHECKING, overload -from .. import _model_base -from .._model_base import rest_field +from .._utils.model_base import Model as _Model, rest_field if TYPE_CHECKING: from .. import models as _models -class FirstItem(_model_base.Model): +class FirstItem(_Model): """First item. :ivar id: The id of the item. Required. @@ -27,7 +26,7 @@ class FirstItem(_model_base.Model): """The id of the item. Required.""" -class ListItemInputBody(_model_base.Model): +class ListItemInputBody(_Model): """The body of the input. :ivar input_name: The name of the input. Required. @@ -55,7 +54,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class SecondItem(_model_base.Model): +class SecondItem(_Model): """Second item. :ivar name: The name of the item. Required. @@ -66,7 +65,7 @@ class SecondItem(_model_base.Model): """The name of the item. Required.""" -class User(_model_base.Model): +class User(_Model): """Details about a user. :ivar id: The user's id. Required. @@ -107,7 +106,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class UserOrder(_model_base.Model): +class UserOrder(_Model): """UserOrder for testing list with expand. :ivar id: The user's id. Required. diff --git a/packages/typespec-python/test/azure/generated/azure-core-page/specs/azure/core/page/operations/_operations.py b/packages/typespec-python/test/azure/generated/azure-core-page/specs/azure/core/page/operations/_operations.py index 1a38213c3f0..a963117ca2a 100644 --- a/packages/typespec-python/test/azure/generated/azure-core-page/specs/azure/core/page/operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/azure-core-page/specs/azure/core/page/operations/_operations.py @@ -28,9 +28,9 @@ from .. import models as _models from .._configuration import PageClientConfiguration -from .._model_base import SdkJSONEncoder, _deserialize -from .._serialization import Deserializer, Serializer -from .._vendor import PageClientMixinABC +from .._utils.model_base import SdkJSONEncoder, _deserialize +from .._utils.serialization import Deserializer, Serializer +from .._utils.utils import ClientMixinABC T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] @@ -352,7 +352,7 @@ def get_next(next_link=None): return ItemPaged(get_next, extract_data) -class PageClientOperationsMixin(PageClientMixinABC): +class PageClientOperationsMixin(ClientMixinABC[PipelineClient, PageClientConfiguration]): @distributed_trace def list_with_page(self, **kwargs: Any) -> Iterable["_models.User"]: diff --git a/packages/typespec-python/test/azure/generated/azure-core-scalar/specs/azure/core/scalar/_client.py b/packages/typespec-python/test/azure/generated/azure-core-scalar/specs/azure/core/scalar/_client.py index 279faf218ca..ce90cf2486e 100644 --- a/packages/typespec-python/test/azure/generated/azure-core-scalar/specs/azure/core/scalar/_client.py +++ b/packages/typespec-python/test/azure/generated/azure-core-scalar/specs/azure/core/scalar/_client.py @@ -15,7 +15,7 @@ from azure.core.rest import HttpRequest, HttpResponse from ._configuration import ScalarClientConfiguration -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer from .operations import AzureLocationScalarOperations diff --git a/packages/typespec-python/test/azure/generated/azure-core-scalar/specs/azure/core/scalar/_utils/__init__.py b/packages/typespec-python/test/azure/generated/azure-core-scalar/specs/azure/core/scalar/_utils/__init__.py new file mode 100644 index 00000000000..8026245c2ab --- /dev/null +++ b/packages/typespec-python/test/azure/generated/azure-core-scalar/specs/azure/core/scalar/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) Python Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/typespec-python/test/azure/generated/azure-core-scalar/specs/azure/core/scalar/_model_base.py b/packages/typespec-python/test/azure/generated/azure-core-scalar/specs/azure/core/scalar/_utils/model_base.py similarity index 100% rename from packages/typespec-python/test/azure/generated/azure-core-scalar/specs/azure/core/scalar/_model_base.py rename to packages/typespec-python/test/azure/generated/azure-core-scalar/specs/azure/core/scalar/_utils/model_base.py diff --git a/packages/typespec-python/test/azure/generated/azure-core-scalar/specs/azure/core/scalar/_serialization.py b/packages/typespec-python/test/azure/generated/azure-core-scalar/specs/azure/core/scalar/_utils/serialization.py similarity index 100% rename from packages/typespec-python/test/azure/generated/azure-core-scalar/specs/azure/core/scalar/_serialization.py rename to packages/typespec-python/test/azure/generated/azure-core-scalar/specs/azure/core/scalar/_utils/serialization.py diff --git a/packages/typespec-python/test/azure/generated/azure-core-scalar/specs/azure/core/scalar/aio/_client.py b/packages/typespec-python/test/azure/generated/azure-core-scalar/specs/azure/core/scalar/aio/_client.py index bf4a3c59f26..069a26f68e8 100644 --- a/packages/typespec-python/test/azure/generated/azure-core-scalar/specs/azure/core/scalar/aio/_client.py +++ b/packages/typespec-python/test/azure/generated/azure-core-scalar/specs/azure/core/scalar/aio/_client.py @@ -14,7 +14,7 @@ from azure.core.pipeline import policies from azure.core.rest import AsyncHttpResponse, HttpRequest -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import ScalarClientConfiguration from .operations import AzureLocationScalarOperations diff --git a/packages/typespec-python/test/azure/generated/azure-core-scalar/specs/azure/core/scalar/aio/operations/_operations.py b/packages/typespec-python/test/azure/generated/azure-core-scalar/specs/azure/core/scalar/aio/operations/_operations.py index 08a407a9f99..c4074a38060 100644 --- a/packages/typespec-python/test/azure/generated/azure-core-scalar/specs/azure/core/scalar/aio/operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/azure-core-scalar/specs/azure/core/scalar/aio/operations/_operations.py @@ -27,8 +27,8 @@ from azure.core.utils import case_insensitive_dict from ... import models as _models -from ..._model_base import SdkJSONEncoder, _deserialize -from ..._serialization import Deserializer, Serializer +from ..._utils.model_base import SdkJSONEncoder, _deserialize +from ..._utils.serialization import Deserializer, Serializer from ...operations._operations import ( build_azure_location_scalar_get_request, build_azure_location_scalar_header_request, diff --git a/packages/typespec-python/test/azure/generated/azure-core-scalar/specs/azure/core/scalar/models/_models.py b/packages/typespec-python/test/azure/generated/azure-core-scalar/specs/azure/core/scalar/models/_models.py index f8b6fba7815..7beed76965f 100644 --- a/packages/typespec-python/test/azure/generated/azure-core-scalar/specs/azure/core/scalar/models/_models.py +++ b/packages/typespec-python/test/azure/generated/azure-core-scalar/specs/azure/core/scalar/models/_models.py @@ -9,11 +9,10 @@ from typing import Any, Mapping, overload -from .. import _model_base -from .._model_base import rest_field +from .._utils.model_base import Model as _Model, rest_field -class AzureLocationModel(_model_base.Model): +class AzureLocationModel(_Model): """AzureLocationModel. :ivar location: Required. diff --git a/packages/typespec-python/test/azure/generated/azure-core-scalar/specs/azure/core/scalar/operations/_operations.py b/packages/typespec-python/test/azure/generated/azure-core-scalar/specs/azure/core/scalar/operations/_operations.py index 050316e660b..19b256cf861 100644 --- a/packages/typespec-python/test/azure/generated/azure-core-scalar/specs/azure/core/scalar/operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/azure-core-scalar/specs/azure/core/scalar/operations/_operations.py @@ -28,8 +28,8 @@ from .. import models as _models from .._configuration import ScalarClientConfiguration -from .._model_base import SdkJSONEncoder, _deserialize -from .._serialization import Deserializer, Serializer +from .._utils.model_base import SdkJSONEncoder, _deserialize +from .._utils.serialization import Deserializer, Serializer JSON = MutableMapping[str, Any] T = TypeVar("T") diff --git a/packages/typespec-python/test/azure/generated/azure-core-traits/specs/azure/core/traits/_client.py b/packages/typespec-python/test/azure/generated/azure-core-traits/specs/azure/core/traits/_client.py index 7605acf9274..0c70e760dd5 100644 --- a/packages/typespec-python/test/azure/generated/azure-core-traits/specs/azure/core/traits/_client.py +++ b/packages/typespec-python/test/azure/generated/azure-core-traits/specs/azure/core/traits/_client.py @@ -16,7 +16,7 @@ from ._configuration import TraitsClientConfiguration from ._operations import TraitsClientOperationsMixin -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer class TraitsClient(TraitsClientOperationsMixin): diff --git a/packages/typespec-python/test/azure/generated/azure-core-traits/specs/azure/core/traits/_operations/_operations.py b/packages/typespec-python/test/azure/generated/azure-core-traits/specs/azure/core/traits/_operations/_operations.py index 80a4a8bbe81..1fcd747543c 100644 --- a/packages/typespec-python/test/azure/generated/azure-core-traits/specs/azure/core/traits/_operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/azure-core-traits/specs/azure/core/traits/_operations/_operations.py @@ -12,7 +12,7 @@ from typing import Any, Callable, Dict, IO, Optional, TypeVar, Union, overload import uuid -from azure.core import MatchConditions +from azure.core import MatchConditions, PipelineClient from azure.core.exceptions import ( ClientAuthenticationError, HttpResponseError, @@ -30,9 +30,10 @@ from azure.core.utils import case_insensitive_dict from .. import models as _models -from .._model_base import SdkJSONEncoder, _deserialize -from .._serialization import Serializer -from .._vendor import TraitsClientMixinABC, prep_if_match, prep_if_none_match +from .._configuration import TraitsClientConfiguration +from .._utils.model_base import SdkJSONEncoder, _deserialize +from .._utils.serialization import Serializer +from .._utils.utils import ClientMixinABC, prep_if_match, prep_if_none_match JSON = MutableMapping[str, Any] T = TypeVar("T") @@ -119,7 +120,7 @@ def build_traits_repeatable_action_request(id: int, **kwargs: Any) -> HttpReques return HttpRequest(method="POST", url=_url, params=_params, headers=_headers, **kwargs) -class TraitsClientOperationsMixin(TraitsClientMixinABC): +class TraitsClientOperationsMixin(ClientMixinABC[PipelineClient, TraitsClientConfiguration]): @distributed_trace def smoke_test( diff --git a/packages/typespec-python/test/azure/generated/azure-core-traits/specs/azure/core/traits/_utils/__init__.py b/packages/typespec-python/test/azure/generated/azure-core-traits/specs/azure/core/traits/_utils/__init__.py new file mode 100644 index 00000000000..8026245c2ab --- /dev/null +++ b/packages/typespec-python/test/azure/generated/azure-core-traits/specs/azure/core/traits/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) Python Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/typespec-python/test/azure/generated/azure-core-traits/specs/azure/core/traits/_model_base.py b/packages/typespec-python/test/azure/generated/azure-core-traits/specs/azure/core/traits/_utils/model_base.py similarity index 100% rename from packages/typespec-python/test/azure/generated/azure-core-traits/specs/azure/core/traits/_model_base.py rename to packages/typespec-python/test/azure/generated/azure-core-traits/specs/azure/core/traits/_utils/model_base.py diff --git a/packages/typespec-python/test/azure/generated/azure-core-traits/specs/azure/core/traits/_serialization.py b/packages/typespec-python/test/azure/generated/azure-core-traits/specs/azure/core/traits/_utils/serialization.py similarity index 100% rename from packages/typespec-python/test/azure/generated/azure-core-traits/specs/azure/core/traits/_serialization.py rename to packages/typespec-python/test/azure/generated/azure-core-traits/specs/azure/core/traits/_utils/serialization.py diff --git a/packages/typespec-python/test/azure/generated/azure-core-traits/specs/azure/core/traits/_utils/utils.py b/packages/typespec-python/test/azure/generated/azure-core-traits/specs/azure/core/traits/_utils/utils.py new file mode 100644 index 00000000000..927adb7c8ae --- /dev/null +++ b/packages/typespec-python/test/azure/generated/azure-core-traits/specs/azure/core/traits/_utils/utils.py @@ -0,0 +1,57 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) Python Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from abc import ABC +from typing import Generic, Optional, TYPE_CHECKING, TypeVar + +from azure.core import MatchConditions + +if TYPE_CHECKING: + from .serialization import Deserializer, Serializer + + +TClient = TypeVar("TClient") +TConfig = TypeVar("TConfig") + + +class ClientMixinABC(ABC, Generic[TClient, TConfig]): + """DO NOT use this class. It is for internal typing use only.""" + + _client: TClient + _config: TConfig + _serialize: "Serializer" + _deserialize: "Deserializer" + + +def quote_etag(etag: Optional[str]) -> Optional[str]: + if not etag or etag == "*": + return etag + if etag.startswith("W/"): + return etag + if etag.startswith('"') and etag.endswith('"'): + return etag + if etag.startswith("'") and etag.endswith("'"): + return etag + return '"' + etag + '"' + + +def prep_if_match(etag: Optional[str], match_condition: Optional[MatchConditions]) -> Optional[str]: + if match_condition == MatchConditions.IfNotModified: + if_match = quote_etag(etag) if etag else None + return if_match + if match_condition == MatchConditions.IfPresent: + return "*" + return None + + +def prep_if_none_match(etag: Optional[str], match_condition: Optional[MatchConditions]) -> Optional[str]: + if match_condition == MatchConditions.IfModified: + if_none_match = quote_etag(etag) if etag else None + return if_none_match + if match_condition == MatchConditions.IfMissing: + return "*" + return None diff --git a/packages/typespec-python/test/azure/generated/azure-core-traits/specs/azure/core/traits/_vendor.py b/packages/typespec-python/test/azure/generated/azure-core-traits/specs/azure/core/traits/_vendor.py deleted file mode 100644 index 85a828d8094..00000000000 --- a/packages/typespec-python/test/azure/generated/azure-core-traits/specs/azure/core/traits/_vendor.py +++ /dev/null @@ -1,57 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) Python Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import Optional, TYPE_CHECKING - -from azure.core import MatchConditions - -from ._configuration import TraitsClientConfiguration - -if TYPE_CHECKING: - from azure.core import PipelineClient - - from ._serialization import Deserializer, Serializer - - -class TraitsClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "PipelineClient" - _config: TraitsClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" - - -def quote_etag(etag: Optional[str]) -> Optional[str]: - if not etag or etag == "*": - return etag - if etag.startswith("W/"): - return etag - if etag.startswith('"') and etag.endswith('"'): - return etag - if etag.startswith("'") and etag.endswith("'"): - return etag - return '"' + etag + '"' - - -def prep_if_match(etag: Optional[str], match_condition: Optional[MatchConditions]) -> Optional[str]: - if match_condition == MatchConditions.IfNotModified: - if_match = quote_etag(etag) if etag else None - return if_match - if match_condition == MatchConditions.IfPresent: - return "*" - return None - - -def prep_if_none_match(etag: Optional[str], match_condition: Optional[MatchConditions]) -> Optional[str]: - if match_condition == MatchConditions.IfModified: - if_none_match = quote_etag(etag) if etag else None - return if_none_match - if match_condition == MatchConditions.IfMissing: - return "*" - return None diff --git a/packages/typespec-python/test/azure/generated/azure-core-traits/specs/azure/core/traits/aio/_client.py b/packages/typespec-python/test/azure/generated/azure-core-traits/specs/azure/core/traits/aio/_client.py index a5bd3316230..c8ede062dea 100644 --- a/packages/typespec-python/test/azure/generated/azure-core-traits/specs/azure/core/traits/aio/_client.py +++ b/packages/typespec-python/test/azure/generated/azure-core-traits/specs/azure/core/traits/aio/_client.py @@ -14,7 +14,7 @@ from azure.core.pipeline import policies from azure.core.rest import AsyncHttpResponse, HttpRequest -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import TraitsClientConfiguration from ._operations import TraitsClientOperationsMixin diff --git a/packages/typespec-python/test/azure/generated/azure-core-traits/specs/azure/core/traits/aio/_operations/_operations.py b/packages/typespec-python/test/azure/generated/azure-core-traits/specs/azure/core/traits/aio/_operations/_operations.py index b667729bf47..448c2b9dbdc 100644 --- a/packages/typespec-python/test/azure/generated/azure-core-traits/specs/azure/core/traits/aio/_operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/azure-core-traits/specs/azure/core/traits/aio/_operations/_operations.py @@ -12,7 +12,7 @@ import json from typing import Any, Callable, Dict, IO, Optional, TypeVar, Union, overload -from azure.core import MatchConditions +from azure.core import AsyncPipelineClient, MatchConditions from azure.core.exceptions import ( ClientAuthenticationError, HttpResponseError, @@ -30,16 +30,17 @@ from azure.core.utils import case_insensitive_dict from ... import models as _models -from ..._model_base import SdkJSONEncoder, _deserialize from ..._operations._operations import build_traits_repeatable_action_request, build_traits_smoke_test_request -from .._vendor import TraitsClientMixinABC +from ..._utils.model_base import SdkJSONEncoder, _deserialize +from ..._utils.utils import ClientMixinABC +from .._configuration import TraitsClientConfiguration JSON = MutableMapping[str, Any] T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, AsyncHttpResponse], T, Dict[str, Any]], Any]] -class TraitsClientOperationsMixin(TraitsClientMixinABC): +class TraitsClientOperationsMixin(ClientMixinABC[AsyncPipelineClient, TraitsClientConfiguration]): @distributed_trace_async async def smoke_test( diff --git a/packages/typespec-python/test/azure/generated/azure-core-traits/specs/azure/core/traits/aio/_vendor.py b/packages/typespec-python/test/azure/generated/azure-core-traits/specs/azure/core/traits/aio/_vendor.py deleted file mode 100644 index 206aaefb870..00000000000 --- a/packages/typespec-python/test/azure/generated/azure-core-traits/specs/azure/core/traits/aio/_vendor.py +++ /dev/null @@ -1,57 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) Python Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import Optional, TYPE_CHECKING - -from azure.core import MatchConditions - -from ._configuration import TraitsClientConfiguration - -if TYPE_CHECKING: - from azure.core import AsyncPipelineClient - - from .._serialization import Deserializer, Serializer - - -class TraitsClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "AsyncPipelineClient" - _config: TraitsClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" - - -def quote_etag(etag: Optional[str]) -> Optional[str]: - if not etag or etag == "*": - return etag - if etag.startswith("W/"): - return etag - if etag.startswith('"') and etag.endswith('"'): - return etag - if etag.startswith("'") and etag.endswith("'"): - return etag - return '"' + etag + '"' - - -def prep_if_match(etag: Optional[str], match_condition: Optional[MatchConditions]) -> Optional[str]: - if match_condition == MatchConditions.IfNotModified: - if_match = quote_etag(etag) if etag else None - return if_match - if match_condition == MatchConditions.IfPresent: - return "*" - return None - - -def prep_if_none_match(etag: Optional[str], match_condition: Optional[MatchConditions]) -> Optional[str]: - if match_condition == MatchConditions.IfModified: - if_none_match = quote_etag(etag) if etag else None - return if_none_match - if match_condition == MatchConditions.IfMissing: - return "*" - return None diff --git a/packages/typespec-python/test/azure/generated/azure-core-traits/specs/azure/core/traits/models/_models.py b/packages/typespec-python/test/azure/generated/azure-core-traits/specs/azure/core/traits/models/_models.py index 5b4bb12d34a..6f5eba343aa 100644 --- a/packages/typespec-python/test/azure/generated/azure-core-traits/specs/azure/core/traits/models/_models.py +++ b/packages/typespec-python/test/azure/generated/azure-core-traits/specs/azure/core/traits/models/_models.py @@ -9,11 +9,10 @@ from typing import Any, Mapping, Optional, overload -from .. import _model_base -from .._model_base import rest_field +from .._utils.model_base import Model as _Model, rest_field -class User(_model_base.Model): +class User(_Model): """Sample Model. :ivar id: The user's id. Required. @@ -45,7 +44,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class UserActionParam(_model_base.Model): +class UserActionParam(_Model): """User action param. :ivar user_action_value: User action value. Required. @@ -75,7 +74,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class UserActionResponse(_model_base.Model): +class UserActionResponse(_Model): """User action response. :ivar user_action_result: User action result. Required. diff --git a/packages/typespec-python/test/azure/generated/azure-encode-duration/specs/azure/encode/duration/_client.py b/packages/typespec-python/test/azure/generated/azure-encode-duration/specs/azure/encode/duration/_client.py index ca491fcf4db..88e245f345b 100644 --- a/packages/typespec-python/test/azure/generated/azure-encode-duration/specs/azure/encode/duration/_client.py +++ b/packages/typespec-python/test/azure/generated/azure-encode-duration/specs/azure/encode/duration/_client.py @@ -16,7 +16,7 @@ from ._configuration import DurationClientConfiguration from ._operations import DurationClientOperationsMixin -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer class DurationClient(DurationClientOperationsMixin): # pylint: disable=client-accepts-api-version-keyword diff --git a/packages/typespec-python/test/azure/generated/azure-encode-duration/specs/azure/encode/duration/_operations/_operations.py b/packages/typespec-python/test/azure/generated/azure-encode-duration/specs/azure/encode/duration/_operations/_operations.py index 903ebaa398c..52bc11a5f68 100644 --- a/packages/typespec-python/test/azure/generated/azure-encode-duration/specs/azure/encode/duration/_operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/azure-encode-duration/specs/azure/encode/duration/_operations/_operations.py @@ -10,6 +10,7 @@ import json from typing import Any, Callable, Dict, IO, Optional, TypeVar, Union, overload +from azure.core import PipelineClient from azure.core.exceptions import ( ClientAuthenticationError, HttpResponseError, @@ -24,9 +25,10 @@ from azure.core.utils import case_insensitive_dict from .. import models as _models -from .._model_base import SdkJSONEncoder -from .._serialization import Serializer -from .._vendor import DurationClientMixinABC +from .._configuration import DurationClientConfiguration +from .._utils.model_base import SdkJSONEncoder +from .._utils.serialization import Serializer +from .._utils.utils import ClientMixinABC JSON = MutableMapping[str, Any] T = TypeVar("T") @@ -50,7 +52,7 @@ def build_duration_duration_constant_request(**kwargs: Any) -> HttpRequest: return HttpRequest(method="PUT", url=_url, headers=_headers, **kwargs) -class DurationClientOperationsMixin(DurationClientMixinABC): +class DurationClientOperationsMixin(ClientMixinABC[PipelineClient, DurationClientConfiguration]): @overload def duration_constant( diff --git a/packages/typespec-python/test/azure/generated/azure-encode-duration/specs/azure/encode/duration/_utils/__init__.py b/packages/typespec-python/test/azure/generated/azure-encode-duration/specs/azure/encode/duration/_utils/__init__.py new file mode 100644 index 00000000000..8026245c2ab --- /dev/null +++ b/packages/typespec-python/test/azure/generated/azure-encode-duration/specs/azure/encode/duration/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) Python Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/typespec-python/test/azure/generated/azure-encode-duration/specs/azure/encode/duration/_model_base.py b/packages/typespec-python/test/azure/generated/azure-encode-duration/specs/azure/encode/duration/_utils/model_base.py similarity index 100% rename from packages/typespec-python/test/azure/generated/azure-encode-duration/specs/azure/encode/duration/_model_base.py rename to packages/typespec-python/test/azure/generated/azure-encode-duration/specs/azure/encode/duration/_utils/model_base.py diff --git a/packages/typespec-python/test/azure/generated/azure-encode-duration/specs/azure/encode/duration/_serialization.py b/packages/typespec-python/test/azure/generated/azure-encode-duration/specs/azure/encode/duration/_utils/serialization.py similarity index 100% rename from packages/typespec-python/test/azure/generated/azure-encode-duration/specs/azure/encode/duration/_serialization.py rename to packages/typespec-python/test/azure/generated/azure-encode-duration/specs/azure/encode/duration/_utils/serialization.py diff --git a/packages/typespec-python/test/azure/generated/azure-encode-duration/specs/azure/encode/duration/_utils/utils.py b/packages/typespec-python/test/azure/generated/azure-encode-duration/specs/azure/encode/duration/_utils/utils.py new file mode 100644 index 00000000000..35c9c836f85 --- /dev/null +++ b/packages/typespec-python/test/azure/generated/azure-encode-duration/specs/azure/encode/duration/_utils/utils.py @@ -0,0 +1,25 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) Python Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from abc import ABC +from typing import Generic, TYPE_CHECKING, TypeVar + +if TYPE_CHECKING: + from .serialization import Deserializer, Serializer + + +TClient = TypeVar("TClient") +TConfig = TypeVar("TConfig") + + +class ClientMixinABC(ABC, Generic[TClient, TConfig]): + """DO NOT use this class. It is for internal typing use only.""" + + _client: TClient + _config: TConfig + _serialize: "Serializer" + _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/azure/generated/azure-encode-duration/specs/azure/encode/duration/_vendor.py b/packages/typespec-python/test/azure/generated/azure-encode-duration/specs/azure/encode/duration/_vendor.py deleted file mode 100644 index 2e2565b9894..00000000000 --- a/packages/typespec-python/test/azure/generated/azure-encode-duration/specs/azure/encode/duration/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) Python Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import DurationClientConfiguration - -if TYPE_CHECKING: - from azure.core import PipelineClient - - from ._serialization import Deserializer, Serializer - - -class DurationClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "PipelineClient" - _config: DurationClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/azure/generated/azure-encode-duration/specs/azure/encode/duration/aio/_client.py b/packages/typespec-python/test/azure/generated/azure-encode-duration/specs/azure/encode/duration/aio/_client.py index 9f4fc9ed417..137338dd2f9 100644 --- a/packages/typespec-python/test/azure/generated/azure-encode-duration/specs/azure/encode/duration/aio/_client.py +++ b/packages/typespec-python/test/azure/generated/azure-encode-duration/specs/azure/encode/duration/aio/_client.py @@ -14,7 +14,7 @@ from azure.core.pipeline import policies from azure.core.rest import AsyncHttpResponse, HttpRequest -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import DurationClientConfiguration from ._operations import DurationClientOperationsMixin diff --git a/packages/typespec-python/test/azure/generated/azure-encode-duration/specs/azure/encode/duration/aio/_operations/_operations.py b/packages/typespec-python/test/azure/generated/azure-encode-duration/specs/azure/encode/duration/aio/_operations/_operations.py index 884659100b2..42d9412f51b 100644 --- a/packages/typespec-python/test/azure/generated/azure-encode-duration/specs/azure/encode/duration/aio/_operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/azure-encode-duration/specs/azure/encode/duration/aio/_operations/_operations.py @@ -11,6 +11,7 @@ import json from typing import Any, Callable, Dict, IO, Optional, TypeVar, Union, overload +from azure.core import AsyncPipelineClient from azure.core.exceptions import ( ClientAuthenticationError, HttpResponseError, @@ -25,16 +26,17 @@ from azure.core.utils import case_insensitive_dict from ... import models as _models -from ..._model_base import SdkJSONEncoder from ..._operations._operations import build_duration_duration_constant_request -from .._vendor import DurationClientMixinABC +from ..._utils.model_base import SdkJSONEncoder +from ..._utils.utils import ClientMixinABC +from .._configuration import DurationClientConfiguration JSON = MutableMapping[str, Any] T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, AsyncHttpResponse], T, Dict[str, Any]], Any]] -class DurationClientOperationsMixin(DurationClientMixinABC): +class DurationClientOperationsMixin(ClientMixinABC[AsyncPipelineClient, DurationClientConfiguration]): @overload async def duration_constant( diff --git a/packages/typespec-python/test/azure/generated/azure-encode-duration/specs/azure/encode/duration/aio/_vendor.py b/packages/typespec-python/test/azure/generated/azure-encode-duration/specs/azure/encode/duration/aio/_vendor.py deleted file mode 100644 index e4b6955d9a2..00000000000 --- a/packages/typespec-python/test/azure/generated/azure-encode-duration/specs/azure/encode/duration/aio/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) Python Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import DurationClientConfiguration - -if TYPE_CHECKING: - from azure.core import AsyncPipelineClient - - from .._serialization import Deserializer, Serializer - - -class DurationClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "AsyncPipelineClient" - _config: DurationClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/azure/generated/azure-encode-duration/specs/azure/encode/duration/models/_models.py b/packages/typespec-python/test/azure/generated/azure-encode-duration/specs/azure/encode/duration/models/_models.py index 10672fccf8d..dca924b2a48 100644 --- a/packages/typespec-python/test/azure/generated/azure-encode-duration/specs/azure/encode/duration/models/_models.py +++ b/packages/typespec-python/test/azure/generated/azure-encode-duration/specs/azure/encode/duration/models/_models.py @@ -10,11 +10,10 @@ import datetime from typing import Any, Mapping, overload -from .. import _model_base -from .._model_base import rest_field +from .._utils.model_base import Model as _Model, rest_field -class DurationModel(_model_base.Model): +class DurationModel(_Model): """DurationModel. :ivar input: Required. diff --git a/packages/typespec-python/test/azure/generated/azure-example-basic/specs/azure/example/basic/_client.py b/packages/typespec-python/test/azure/generated/azure-example-basic/specs/azure/example/basic/_client.py index 7733d0ff3e7..8647df8b95f 100644 --- a/packages/typespec-python/test/azure/generated/azure-example-basic/specs/azure/example/basic/_client.py +++ b/packages/typespec-python/test/azure/generated/azure-example-basic/specs/azure/example/basic/_client.py @@ -16,7 +16,7 @@ from ._configuration import AzureExampleClientConfiguration from ._operations import AzureExampleClientOperationsMixin -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer class AzureExampleClient(AzureExampleClientOperationsMixin): diff --git a/packages/typespec-python/test/azure/generated/azure-example-basic/specs/azure/example/basic/_operations/_operations.py b/packages/typespec-python/test/azure/generated/azure-example-basic/specs/azure/example/basic/_operations/_operations.py index 0ed1589df28..5a3175a702e 100644 --- a/packages/typespec-python/test/azure/generated/azure-example-basic/specs/azure/example/basic/_operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/azure-example-basic/specs/azure/example/basic/_operations/_operations.py @@ -10,6 +10,7 @@ import json from typing import Any, Callable, Dict, IO, Optional, TypeVar, Union, overload +from azure.core import PipelineClient from azure.core.exceptions import ( ClientAuthenticationError, HttpResponseError, @@ -26,9 +27,10 @@ from azure.core.utils import case_insensitive_dict from .. import models as _models -from .._model_base import SdkJSONEncoder, _deserialize -from .._serialization import Serializer -from .._vendor import AzureExampleClientMixinABC +from .._configuration import AzureExampleClientConfiguration +from .._utils.model_base import SdkJSONEncoder, _deserialize +from .._utils.serialization import Serializer +from .._utils.utils import ClientMixinABC JSON = MutableMapping[str, Any] T = TypeVar("T") @@ -62,7 +64,7 @@ def build_azure_example_basic_action_request(*, query_param: str, header_param: return HttpRequest(method="POST", url=_url, params=_params, headers=_headers, **kwargs) -class AzureExampleClientOperationsMixin(AzureExampleClientMixinABC): +class AzureExampleClientOperationsMixin(ClientMixinABC[PipelineClient, AzureExampleClientConfiguration]): @overload def basic_action( diff --git a/packages/typespec-python/test/azure/generated/azure-example-basic/specs/azure/example/basic/_utils/__init__.py b/packages/typespec-python/test/azure/generated/azure-example-basic/specs/azure/example/basic/_utils/__init__.py new file mode 100644 index 00000000000..8026245c2ab --- /dev/null +++ b/packages/typespec-python/test/azure/generated/azure-example-basic/specs/azure/example/basic/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) Python Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/typespec-python/test/azure/generated/azure-example-basic/specs/azure/example/basic/_model_base.py b/packages/typespec-python/test/azure/generated/azure-example-basic/specs/azure/example/basic/_utils/model_base.py similarity index 100% rename from packages/typespec-python/test/azure/generated/azure-example-basic/specs/azure/example/basic/_model_base.py rename to packages/typespec-python/test/azure/generated/azure-example-basic/specs/azure/example/basic/_utils/model_base.py diff --git a/packages/typespec-python/test/azure/generated/azure-example-basic/specs/azure/example/basic/_serialization.py b/packages/typespec-python/test/azure/generated/azure-example-basic/specs/azure/example/basic/_utils/serialization.py similarity index 100% rename from packages/typespec-python/test/azure/generated/azure-example-basic/specs/azure/example/basic/_serialization.py rename to packages/typespec-python/test/azure/generated/azure-example-basic/specs/azure/example/basic/_utils/serialization.py diff --git a/packages/typespec-python/test/azure/generated/azure-example-basic/specs/azure/example/basic/_utils/utils.py b/packages/typespec-python/test/azure/generated/azure-example-basic/specs/azure/example/basic/_utils/utils.py new file mode 100644 index 00000000000..35c9c836f85 --- /dev/null +++ b/packages/typespec-python/test/azure/generated/azure-example-basic/specs/azure/example/basic/_utils/utils.py @@ -0,0 +1,25 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) Python Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from abc import ABC +from typing import Generic, TYPE_CHECKING, TypeVar + +if TYPE_CHECKING: + from .serialization import Deserializer, Serializer + + +TClient = TypeVar("TClient") +TConfig = TypeVar("TConfig") + + +class ClientMixinABC(ABC, Generic[TClient, TConfig]): + """DO NOT use this class. It is for internal typing use only.""" + + _client: TClient + _config: TConfig + _serialize: "Serializer" + _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/azure/generated/azure-example-basic/specs/azure/example/basic/_vendor.py b/packages/typespec-python/test/azure/generated/azure-example-basic/specs/azure/example/basic/_vendor.py deleted file mode 100644 index fbed59a5ee8..00000000000 --- a/packages/typespec-python/test/azure/generated/azure-example-basic/specs/azure/example/basic/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) Python Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import AzureExampleClientConfiguration - -if TYPE_CHECKING: - from azure.core import PipelineClient - - from ._serialization import Deserializer, Serializer - - -class AzureExampleClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "PipelineClient" - _config: AzureExampleClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/azure/generated/azure-example-basic/specs/azure/example/basic/aio/_client.py b/packages/typespec-python/test/azure/generated/azure-example-basic/specs/azure/example/basic/aio/_client.py index e21151cf1f7..3eb7fcac632 100644 --- a/packages/typespec-python/test/azure/generated/azure-example-basic/specs/azure/example/basic/aio/_client.py +++ b/packages/typespec-python/test/azure/generated/azure-example-basic/specs/azure/example/basic/aio/_client.py @@ -14,7 +14,7 @@ from azure.core.pipeline import policies from azure.core.rest import AsyncHttpResponse, HttpRequest -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import AzureExampleClientConfiguration from ._operations import AzureExampleClientOperationsMixin diff --git a/packages/typespec-python/test/azure/generated/azure-example-basic/specs/azure/example/basic/aio/_operations/_operations.py b/packages/typespec-python/test/azure/generated/azure-example-basic/specs/azure/example/basic/aio/_operations/_operations.py index 7bc0884cec8..a9158038aee 100644 --- a/packages/typespec-python/test/azure/generated/azure-example-basic/specs/azure/example/basic/aio/_operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/azure-example-basic/specs/azure/example/basic/aio/_operations/_operations.py @@ -11,6 +11,7 @@ import json from typing import Any, Callable, Dict, IO, Optional, TypeVar, Union, overload +from azure.core import AsyncPipelineClient from azure.core.exceptions import ( ClientAuthenticationError, HttpResponseError, @@ -27,16 +28,17 @@ from azure.core.utils import case_insensitive_dict from ... import models as _models -from ..._model_base import SdkJSONEncoder, _deserialize from ..._operations._operations import build_azure_example_basic_action_request -from .._vendor import AzureExampleClientMixinABC +from ..._utils.model_base import SdkJSONEncoder, _deserialize +from ..._utils.utils import ClientMixinABC +from .._configuration import AzureExampleClientConfiguration JSON = MutableMapping[str, Any] T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, AsyncHttpResponse], T, Dict[str, Any]], Any]] -class AzureExampleClientOperationsMixin(AzureExampleClientMixinABC): +class AzureExampleClientOperationsMixin(ClientMixinABC[AsyncPipelineClient, AzureExampleClientConfiguration]): @overload async def basic_action( diff --git a/packages/typespec-python/test/azure/generated/azure-example-basic/specs/azure/example/basic/aio/_vendor.py b/packages/typespec-python/test/azure/generated/azure-example-basic/specs/azure/example/basic/aio/_vendor.py deleted file mode 100644 index 08b0ff0d65e..00000000000 --- a/packages/typespec-python/test/azure/generated/azure-example-basic/specs/azure/example/basic/aio/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) Python Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import AzureExampleClientConfiguration - -if TYPE_CHECKING: - from azure.core import AsyncPipelineClient - - from .._serialization import Deserializer, Serializer - - -class AzureExampleClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "AsyncPipelineClient" - _config: AzureExampleClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/azure/generated/azure-example-basic/specs/azure/example/basic/models/_models.py b/packages/typespec-python/test/azure/generated/azure-example-basic/specs/azure/example/basic/models/_models.py index 37203ba9955..51d9eac12e1 100644 --- a/packages/typespec-python/test/azure/generated/azure-example-basic/specs/azure/example/basic/models/_models.py +++ b/packages/typespec-python/test/azure/generated/azure-example-basic/specs/azure/example/basic/models/_models.py @@ -9,14 +9,13 @@ from typing import Any, Dict, List, Mapping, Optional, TYPE_CHECKING, Union, overload -from .. import _model_base -from .._model_base import rest_field +from .._utils.model_base import Model as _Model, rest_field if TYPE_CHECKING: from .. import models as _models -class ActionRequest(_model_base.Model): +class ActionRequest(_Model): """ActionRequest. :ivar string_property: Required. @@ -62,7 +61,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class ActionResponse(_model_base.Model): +class ActionResponse(_Model): """ActionResponse. :ivar string_property: Required. @@ -108,7 +107,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class Model(_model_base.Model): +class Model(_Model): """Model. :ivar int32_property: diff --git a/packages/typespec-python/test/azure/generated/azure-payload-pageable/specs/azure/payload/pageable/_client.py b/packages/typespec-python/test/azure/generated/azure-payload-pageable/specs/azure/payload/pageable/_client.py index 777f4778bc7..21056cb4fe6 100644 --- a/packages/typespec-python/test/azure/generated/azure-payload-pageable/specs/azure/payload/pageable/_client.py +++ b/packages/typespec-python/test/azure/generated/azure-payload-pageable/specs/azure/payload/pageable/_client.py @@ -16,7 +16,7 @@ from ._configuration import PageableClientConfiguration from ._operations import PageableClientOperationsMixin -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer class PageableClient(PageableClientOperationsMixin): # pylint: disable=client-accepts-api-version-keyword diff --git a/packages/typespec-python/test/azure/generated/azure-payload-pageable/specs/azure/payload/pageable/_operations/_operations.py b/packages/typespec-python/test/azure/generated/azure-payload-pageable/specs/azure/payload/pageable/_operations/_operations.py index 3669f1c8d25..98b297ff791 100644 --- a/packages/typespec-python/test/azure/generated/azure-payload-pageable/specs/azure/payload/pageable/_operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/azure-payload-pageable/specs/azure/payload/pageable/_operations/_operations.py @@ -8,6 +8,7 @@ from collections.abc import MutableMapping from typing import Any, Callable, Dict, Iterable, List, Optional, TypeVar +from azure.core import PipelineClient from azure.core.exceptions import ( ClientAuthenticationError, HttpResponseError, @@ -23,10 +24,11 @@ from azure.core.utils import case_insensitive_dict from .. import models as _models -from .._model_base import _deserialize -from .._serialization import Serializer +from .._configuration import PageableClientConfiguration +from .._utils.model_base import _deserialize +from .._utils.serialization import Serializer +from .._utils.utils import ClientMixinABC from .._validation import api_version_validation -from .._vendor import PageableClientMixinABC T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] @@ -54,7 +56,7 @@ def build_pageable_list_request(*, maxpagesize: Optional[int] = None, **kwargs: return HttpRequest(method="GET", url=_url, params=_params, headers=_headers, **kwargs) -class PageableClientOperationsMixin(PageableClientMixinABC): +class PageableClientOperationsMixin(ClientMixinABC[PipelineClient, PageableClientConfiguration]): @distributed_trace @api_version_validation( diff --git a/packages/typespec-python/test/azure/generated/azure-payload-pageable/specs/azure/payload/pageable/_utils/__init__.py b/packages/typespec-python/test/azure/generated/azure-payload-pageable/specs/azure/payload/pageable/_utils/__init__.py new file mode 100644 index 00000000000..8026245c2ab --- /dev/null +++ b/packages/typespec-python/test/azure/generated/azure-payload-pageable/specs/azure/payload/pageable/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) Python Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/typespec-python/test/azure/generated/azure-payload-pageable/specs/azure/payload/pageable/_model_base.py b/packages/typespec-python/test/azure/generated/azure-payload-pageable/specs/azure/payload/pageable/_utils/model_base.py similarity index 100% rename from packages/typespec-python/test/azure/generated/azure-payload-pageable/specs/azure/payload/pageable/_model_base.py rename to packages/typespec-python/test/azure/generated/azure-payload-pageable/specs/azure/payload/pageable/_utils/model_base.py diff --git a/packages/typespec-python/test/azure/generated/azure-payload-pageable/specs/azure/payload/pageable/_serialization.py b/packages/typespec-python/test/azure/generated/azure-payload-pageable/specs/azure/payload/pageable/_utils/serialization.py similarity index 100% rename from packages/typespec-python/test/azure/generated/azure-payload-pageable/specs/azure/payload/pageable/_serialization.py rename to packages/typespec-python/test/azure/generated/azure-payload-pageable/specs/azure/payload/pageable/_utils/serialization.py diff --git a/packages/typespec-python/test/azure/generated/azure-payload-pageable/specs/azure/payload/pageable/_utils/utils.py b/packages/typespec-python/test/azure/generated/azure-payload-pageable/specs/azure/payload/pageable/_utils/utils.py new file mode 100644 index 00000000000..35c9c836f85 --- /dev/null +++ b/packages/typespec-python/test/azure/generated/azure-payload-pageable/specs/azure/payload/pageable/_utils/utils.py @@ -0,0 +1,25 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) Python Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from abc import ABC +from typing import Generic, TYPE_CHECKING, TypeVar + +if TYPE_CHECKING: + from .serialization import Deserializer, Serializer + + +TClient = TypeVar("TClient") +TConfig = TypeVar("TConfig") + + +class ClientMixinABC(ABC, Generic[TClient, TConfig]): + """DO NOT use this class. It is for internal typing use only.""" + + _client: TClient + _config: TConfig + _serialize: "Serializer" + _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/azure/generated/azure-payload-pageable/specs/azure/payload/pageable/_vendor.py b/packages/typespec-python/test/azure/generated/azure-payload-pageable/specs/azure/payload/pageable/_vendor.py deleted file mode 100644 index 48587d02498..00000000000 --- a/packages/typespec-python/test/azure/generated/azure-payload-pageable/specs/azure/payload/pageable/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) Python Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import PageableClientConfiguration - -if TYPE_CHECKING: - from azure.core import PipelineClient - - from ._serialization import Deserializer, Serializer - - -class PageableClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "PipelineClient" - _config: PageableClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/azure/generated/azure-payload-pageable/specs/azure/payload/pageable/aio/_client.py b/packages/typespec-python/test/azure/generated/azure-payload-pageable/specs/azure/payload/pageable/aio/_client.py index fe807868800..915694fa0a0 100644 --- a/packages/typespec-python/test/azure/generated/azure-payload-pageable/specs/azure/payload/pageable/aio/_client.py +++ b/packages/typespec-python/test/azure/generated/azure-payload-pageable/specs/azure/payload/pageable/aio/_client.py @@ -14,7 +14,7 @@ from azure.core.pipeline import policies from azure.core.rest import AsyncHttpResponse, HttpRequest -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import PageableClientConfiguration from ._operations import PageableClientOperationsMixin diff --git a/packages/typespec-python/test/azure/generated/azure-payload-pageable/specs/azure/payload/pageable/aio/_operations/_operations.py b/packages/typespec-python/test/azure/generated/azure-payload-pageable/specs/azure/payload/pageable/aio/_operations/_operations.py index c02b0ea036e..c122645b09d 100644 --- a/packages/typespec-python/test/azure/generated/azure-payload-pageable/specs/azure/payload/pageable/aio/_operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/azure-payload-pageable/specs/azure/payload/pageable/aio/_operations/_operations.py @@ -9,6 +9,7 @@ from collections.abc import MutableMapping from typing import Any, AsyncIterable, Callable, Dict, List, Optional, TypeVar +from azure.core import AsyncPipelineClient from azure.core.async_paging import AsyncItemPaged, AsyncList from azure.core.exceptions import ( ClientAuthenticationError, @@ -23,16 +24,17 @@ from azure.core.tracing.decorator import distributed_trace from ... import models as _models -from ..._model_base import _deserialize from ..._operations._operations import build_pageable_list_request +from ..._utils.model_base import _deserialize +from ..._utils.utils import ClientMixinABC from ..._validation import api_version_validation -from .._vendor import PageableClientMixinABC +from .._configuration import PageableClientConfiguration T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, AsyncHttpResponse], T, Dict[str, Any]], Any]] -class PageableClientOperationsMixin(PageableClientMixinABC): +class PageableClientOperationsMixin(ClientMixinABC[AsyncPipelineClient, PageableClientConfiguration]): @distributed_trace @api_version_validation( diff --git a/packages/typespec-python/test/azure/generated/azure-payload-pageable/specs/azure/payload/pageable/aio/_vendor.py b/packages/typespec-python/test/azure/generated/azure-payload-pageable/specs/azure/payload/pageable/aio/_vendor.py deleted file mode 100644 index 3c28688d845..00000000000 --- a/packages/typespec-python/test/azure/generated/azure-payload-pageable/specs/azure/payload/pageable/aio/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) Python Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import PageableClientConfiguration - -if TYPE_CHECKING: - from azure.core import AsyncPipelineClient - - from .._serialization import Deserializer, Serializer - - -class PageableClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "AsyncPipelineClient" - _config: PageableClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/azure/generated/azure-payload-pageable/specs/azure/payload/pageable/models/_models.py b/packages/typespec-python/test/azure/generated/azure-payload-pageable/specs/azure/payload/pageable/models/_models.py index 308fc7b4730..f51231d5b9c 100644 --- a/packages/typespec-python/test/azure/generated/azure-payload-pageable/specs/azure/payload/pageable/models/_models.py +++ b/packages/typespec-python/test/azure/generated/azure-payload-pageable/specs/azure/payload/pageable/models/_models.py @@ -9,11 +9,10 @@ from typing import Any, Mapping, overload -from .. import _model_base -from .._model_base import rest_field +from .._utils.model_base import Model as _Model, rest_field -class User(_model_base.Model): +class User(_Model): """User model. :ivar name: User name. Required. diff --git a/packages/typespec-python/test/azure/generated/azure-resource-manager-common-properties/azure/resourcemanager/commonproperties/_client.py b/packages/typespec-python/test/azure/generated/azure-resource-manager-common-properties/azure/resourcemanager/commonproperties/_client.py index cfa4db0329b..c7988363075 100644 --- a/packages/typespec-python/test/azure/generated/azure-resource-manager-common-properties/azure/resourcemanager/commonproperties/_client.py +++ b/packages/typespec-python/test/azure/generated/azure-resource-manager-common-properties/azure/resourcemanager/commonproperties/_client.py @@ -18,7 +18,7 @@ from azure.mgmt.core.tools import get_arm_endpoints from ._configuration import CommonPropertiesClientConfiguration -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer from .operations import ErrorOperations, ManagedIdentityOperations if TYPE_CHECKING: diff --git a/packages/typespec-python/test/azure/generated/azure-resource-manager-common-properties/azure/resourcemanager/commonproperties/_utils/__init__.py b/packages/typespec-python/test/azure/generated/azure-resource-manager-common-properties/azure/resourcemanager/commonproperties/_utils/__init__.py new file mode 100644 index 00000000000..8026245c2ab --- /dev/null +++ b/packages/typespec-python/test/azure/generated/azure-resource-manager-common-properties/azure/resourcemanager/commonproperties/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) Python Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/typespec-python/test/azure/generated/azure-resource-manager-common-properties/azure/resourcemanager/commonproperties/_model_base.py b/packages/typespec-python/test/azure/generated/azure-resource-manager-common-properties/azure/resourcemanager/commonproperties/_utils/model_base.py similarity index 100% rename from packages/typespec-python/test/azure/generated/azure-resource-manager-common-properties/azure/resourcemanager/commonproperties/_model_base.py rename to packages/typespec-python/test/azure/generated/azure-resource-manager-common-properties/azure/resourcemanager/commonproperties/_utils/model_base.py diff --git a/packages/typespec-python/test/azure/generated/azure-resource-manager-common-properties/azure/resourcemanager/commonproperties/_serialization.py b/packages/typespec-python/test/azure/generated/azure-resource-manager-common-properties/azure/resourcemanager/commonproperties/_utils/serialization.py similarity index 100% rename from packages/typespec-python/test/azure/generated/azure-resource-manager-common-properties/azure/resourcemanager/commonproperties/_serialization.py rename to packages/typespec-python/test/azure/generated/azure-resource-manager-common-properties/azure/resourcemanager/commonproperties/_utils/serialization.py diff --git a/packages/typespec-python/test/azure/generated/azure-resource-manager-common-properties/azure/resourcemanager/commonproperties/aio/_client.py b/packages/typespec-python/test/azure/generated/azure-resource-manager-common-properties/azure/resourcemanager/commonproperties/aio/_client.py index 02abca70e16..7fc71bc087d 100644 --- a/packages/typespec-python/test/azure/generated/azure-resource-manager-common-properties/azure/resourcemanager/commonproperties/aio/_client.py +++ b/packages/typespec-python/test/azure/generated/azure-resource-manager-common-properties/azure/resourcemanager/commonproperties/aio/_client.py @@ -17,7 +17,7 @@ from azure.mgmt.core.policies import AsyncARMAutoResourceProviderRegistrationPolicy from azure.mgmt.core.tools import get_arm_endpoints -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import CommonPropertiesClientConfiguration from .operations import ErrorOperations, ManagedIdentityOperations diff --git a/packages/typespec-python/test/azure/generated/azure-resource-manager-common-properties/azure/resourcemanager/commonproperties/aio/operations/_operations.py b/packages/typespec-python/test/azure/generated/azure-resource-manager-common-properties/azure/resourcemanager/commonproperties/aio/operations/_operations.py index 3dfa6c37d50..d000ea9b14f 100644 --- a/packages/typespec-python/test/azure/generated/azure-resource-manager-common-properties/azure/resourcemanager/commonproperties/aio/operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/azure-resource-manager-common-properties/azure/resourcemanager/commonproperties/aio/operations/_operations.py @@ -28,8 +28,8 @@ from azure.mgmt.core.exceptions import ARMErrorFormat from ... import models as _models -from ..._model_base import SdkJSONEncoder, _deserialize, _failsafe_deserialize -from ..._serialization import Deserializer, Serializer +from ..._utils.model_base import SdkJSONEncoder, _deserialize, _failsafe_deserialize +from ..._utils.serialization import Deserializer, Serializer from ...operations._operations import ( build_error_create_for_user_defined_error_request, build_error_get_for_predefined_error_request, diff --git a/packages/typespec-python/test/azure/generated/azure-resource-manager-common-properties/azure/resourcemanager/commonproperties/models/_models.py b/packages/typespec-python/test/azure/generated/azure-resource-manager-common-properties/azure/resourcemanager/commonproperties/models/_models.py index ce7e8c5cb2f..0e4ee4fabcb 100644 --- a/packages/typespec-python/test/azure/generated/azure-resource-manager-common-properties/azure/resourcemanager/commonproperties/models/_models.py +++ b/packages/typespec-python/test/azure/generated/azure-resource-manager-common-properties/azure/resourcemanager/commonproperties/models/_models.py @@ -11,14 +11,13 @@ import datetime from typing import Any, Dict, List, Mapping, Optional, TYPE_CHECKING, Union, overload -from .. import _model_base -from .._model_base import rest_field +from .._utils.model_base import Model as _Model, rest_field if TYPE_CHECKING: from .. import models as _models -class ApiError(_model_base.Model): +class ApiError(_Model): """Api error. :ivar details: The Api error details. @@ -68,7 +67,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class ApiErrorBase(_model_base.Model): +class ApiErrorBase(_Model): """Api error base. :ivar code: The error code. @@ -106,7 +105,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class CloudError(_model_base.Model): +class CloudError(_Model): """An error response. :ivar error: Api error. @@ -134,7 +133,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class Resource(_model_base.Model): +class Resource(_Model): """Common fields that are returned in the response for all Azure Resource Manager resources. :ivar id: Fully qualified resource ID for the resource. Ex - @@ -256,7 +255,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class ConfidentialResourceProperties(_model_base.Model): +class ConfidentialResourceProperties(_Model): """Confidential Resource Properties. :ivar provisioning_state: The status of the last operation. Required. @@ -288,7 +287,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class ErrorAdditionalInfo(_model_base.Model): +class ErrorAdditionalInfo(_Model): """The resource management error additional info. :ivar type: The additional info type. @@ -303,7 +302,7 @@ class ErrorAdditionalInfo(_model_base.Model): """The additional info.""" -class ErrorDetail(_model_base.Model): +class ErrorDetail(_Model): """The error detail. :ivar code: The error code. @@ -333,7 +332,7 @@ class ErrorDetail(_model_base.Model): """The error additional info.""" -class ErrorResponse(_model_base.Model): +class ErrorResponse(_Model): """Common error response for all Azure Resource Manager APIs to return error details for failed operations. @@ -362,7 +361,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class InnerError(_model_base.Model): +class InnerError(_Model): """Inner error details. :ivar exceptiontype: The exception type. @@ -451,7 +450,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class ManagedIdentityTrackedResourceProperties(_model_base.Model): +class ManagedIdentityTrackedResourceProperties(_Model): """Managed Identity Arm Resource Properties. :ivar provisioning_state: The status of the last operation. Required. @@ -462,7 +461,7 @@ class ManagedIdentityTrackedResourceProperties(_model_base.Model): """The status of the last operation. Required.""" -class ManagedServiceIdentity(_model_base.Model): +class ManagedServiceIdentity(_Model): """Managed service identity (system assigned and/or user assigned identities). :ivar principal_id: The service principal ID of the system assigned identity. This property @@ -514,7 +513,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class SystemData(_model_base.Model): +class SystemData(_Model): """Metadata pertaining to creation and last modification of the resource. :ivar created_by: The identity that created the resource. @@ -582,7 +581,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class UserAssignedIdentity(_model_base.Model): +class UserAssignedIdentity(_Model): """User assigned identity properties. :ivar client_id: The client ID of the assigned identity. diff --git a/packages/typespec-python/test/azure/generated/azure-resource-manager-common-properties/azure/resourcemanager/commonproperties/operations/_operations.py b/packages/typespec-python/test/azure/generated/azure-resource-manager-common-properties/azure/resourcemanager/commonproperties/operations/_operations.py index 544f3ea2375..0ef73665ff1 100644 --- a/packages/typespec-python/test/azure/generated/azure-resource-manager-common-properties/azure/resourcemanager/commonproperties/operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/azure-resource-manager-common-properties/azure/resourcemanager/commonproperties/operations/_operations.py @@ -30,8 +30,8 @@ from .. import models as _models from .._configuration import CommonPropertiesClientConfiguration -from .._model_base import SdkJSONEncoder, _deserialize, _failsafe_deserialize -from .._serialization import Deserializer, Serializer +from .._utils.model_base import SdkJSONEncoder, _deserialize, _failsafe_deserialize +from .._utils.serialization import Deserializer, Serializer JSON = MutableMapping[str, Any] T = TypeVar("T") diff --git a/packages/typespec-python/test/azure/generated/azure-resource-manager-non-resource/azure/resourcemanager/nonresource/_client.py b/packages/typespec-python/test/azure/generated/azure-resource-manager-non-resource/azure/resourcemanager/nonresource/_client.py index be913f21fe2..ecd01a03c70 100644 --- a/packages/typespec-python/test/azure/generated/azure-resource-manager-non-resource/azure/resourcemanager/nonresource/_client.py +++ b/packages/typespec-python/test/azure/generated/azure-resource-manager-non-resource/azure/resourcemanager/nonresource/_client.py @@ -18,7 +18,7 @@ from azure.mgmt.core.tools import get_arm_endpoints from ._configuration import NonResourceClientConfiguration -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer from .operations import NonResourceOperationsOperations if TYPE_CHECKING: diff --git a/packages/typespec-python/test/azure/generated/azure-resource-manager-non-resource/azure/resourcemanager/nonresource/_utils/__init__.py b/packages/typespec-python/test/azure/generated/azure-resource-manager-non-resource/azure/resourcemanager/nonresource/_utils/__init__.py new file mode 100644 index 00000000000..8026245c2ab --- /dev/null +++ b/packages/typespec-python/test/azure/generated/azure-resource-manager-non-resource/azure/resourcemanager/nonresource/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) Python Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/typespec-python/test/azure/generated/azure-resource-manager-non-resource/azure/resourcemanager/nonresource/_model_base.py b/packages/typespec-python/test/azure/generated/azure-resource-manager-non-resource/azure/resourcemanager/nonresource/_utils/model_base.py similarity index 100% rename from packages/typespec-python/test/azure/generated/azure-resource-manager-non-resource/azure/resourcemanager/nonresource/_model_base.py rename to packages/typespec-python/test/azure/generated/azure-resource-manager-non-resource/azure/resourcemanager/nonresource/_utils/model_base.py diff --git a/packages/typespec-python/test/azure/generated/azure-resource-manager-non-resource/azure/resourcemanager/nonresource/_serialization.py b/packages/typespec-python/test/azure/generated/azure-resource-manager-non-resource/azure/resourcemanager/nonresource/_utils/serialization.py similarity index 100% rename from packages/typespec-python/test/azure/generated/azure-resource-manager-non-resource/azure/resourcemanager/nonresource/_serialization.py rename to packages/typespec-python/test/azure/generated/azure-resource-manager-non-resource/azure/resourcemanager/nonresource/_utils/serialization.py diff --git a/packages/typespec-python/test/azure/generated/azure-resource-manager-non-resource/azure/resourcemanager/nonresource/aio/_client.py b/packages/typespec-python/test/azure/generated/azure-resource-manager-non-resource/azure/resourcemanager/nonresource/aio/_client.py index da7fc53e4c6..f60ce8937a0 100644 --- a/packages/typespec-python/test/azure/generated/azure-resource-manager-non-resource/azure/resourcemanager/nonresource/aio/_client.py +++ b/packages/typespec-python/test/azure/generated/azure-resource-manager-non-resource/azure/resourcemanager/nonresource/aio/_client.py @@ -17,7 +17,7 @@ from azure.mgmt.core.policies import AsyncARMAutoResourceProviderRegistrationPolicy from azure.mgmt.core.tools import get_arm_endpoints -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import NonResourceClientConfiguration from .operations import NonResourceOperationsOperations diff --git a/packages/typespec-python/test/azure/generated/azure-resource-manager-non-resource/azure/resourcemanager/nonresource/aio/operations/_operations.py b/packages/typespec-python/test/azure/generated/azure-resource-manager-non-resource/azure/resourcemanager/nonresource/aio/operations/_operations.py index 9411ca37f86..214957d166d 100644 --- a/packages/typespec-python/test/azure/generated/azure-resource-manager-non-resource/azure/resourcemanager/nonresource/aio/operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/azure-resource-manager-non-resource/azure/resourcemanager/nonresource/aio/operations/_operations.py @@ -28,8 +28,8 @@ from azure.mgmt.core.exceptions import ARMErrorFormat from ... import models as _models -from ..._model_base import SdkJSONEncoder, _deserialize, _failsafe_deserialize -from ..._serialization import Deserializer, Serializer +from ..._utils.model_base import SdkJSONEncoder, _deserialize, _failsafe_deserialize +from ..._utils.serialization import Deserializer, Serializer from ...operations._operations import ( build_non_resource_operations_create_request, build_non_resource_operations_get_request, diff --git a/packages/typespec-python/test/azure/generated/azure-resource-manager-non-resource/azure/resourcemanager/nonresource/models/_models.py b/packages/typespec-python/test/azure/generated/azure-resource-manager-non-resource/azure/resourcemanager/nonresource/models/_models.py index 3ab58bcec32..73142b27360 100644 --- a/packages/typespec-python/test/azure/generated/azure-resource-manager-non-resource/azure/resourcemanager/nonresource/models/_models.py +++ b/packages/typespec-python/test/azure/generated/azure-resource-manager-non-resource/azure/resourcemanager/nonresource/models/_models.py @@ -9,14 +9,13 @@ from typing import Any, List, Mapping, Optional, TYPE_CHECKING, overload -from .. import _model_base -from .._model_base import rest_field +from .._utils.model_base import Model as _Model, rest_field if TYPE_CHECKING: from .. import models as _models -class ErrorAdditionalInfo(_model_base.Model): +class ErrorAdditionalInfo(_Model): """The resource management error additional info. :ivar type: The additional info type. @@ -31,7 +30,7 @@ class ErrorAdditionalInfo(_model_base.Model): """The additional info.""" -class ErrorDetail(_model_base.Model): +class ErrorDetail(_Model): """The error detail. :ivar code: The error code. @@ -60,7 +59,7 @@ class ErrorDetail(_model_base.Model): """The error additional info.""" -class ErrorResponse(_model_base.Model): +class ErrorResponse(_Model): """Common error response for all Azure Resource Manager APIs to return error details for failed operations. @@ -89,7 +88,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class NonResource(_model_base.Model): +class NonResource(_Model): """Though this model has ``id``, ``name``, ``type`` properties, it is not a resource as it doesn't extends ``Resource``. diff --git a/packages/typespec-python/test/azure/generated/azure-resource-manager-non-resource/azure/resourcemanager/nonresource/operations/_operations.py b/packages/typespec-python/test/azure/generated/azure-resource-manager-non-resource/azure/resourcemanager/nonresource/operations/_operations.py index 6a318783a78..a0eb9e5afd1 100644 --- a/packages/typespec-python/test/azure/generated/azure-resource-manager-non-resource/azure/resourcemanager/nonresource/operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/azure-resource-manager-non-resource/azure/resourcemanager/nonresource/operations/_operations.py @@ -30,8 +30,8 @@ from .. import models as _models from .._configuration import NonResourceClientConfiguration -from .._model_base import SdkJSONEncoder, _deserialize, _failsafe_deserialize -from .._serialization import Deserializer, Serializer +from .._utils.model_base import SdkJSONEncoder, _deserialize, _failsafe_deserialize +from .._utils.serialization import Deserializer, Serializer JSON = MutableMapping[str, Any] T = TypeVar("T") diff --git a/packages/typespec-python/test/azure/generated/azure-resource-manager-operation-templates/azure/resourcemanager/operationtemplates/_client.py b/packages/typespec-python/test/azure/generated/azure-resource-manager-operation-templates/azure/resourcemanager/operationtemplates/_client.py index d6fd162cfb0..319c19461d4 100644 --- a/packages/typespec-python/test/azure/generated/azure-resource-manager-operation-templates/azure/resourcemanager/operationtemplates/_client.py +++ b/packages/typespec-python/test/azure/generated/azure-resource-manager-operation-templates/azure/resourcemanager/operationtemplates/_client.py @@ -18,7 +18,7 @@ from azure.mgmt.core.tools import get_arm_endpoints from ._configuration import OperationTemplatesClientConfiguration -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer from .operations import CheckNameAvailabilityOperations, LroOperations, Operations if TYPE_CHECKING: diff --git a/packages/typespec-python/test/azure/generated/azure-resource-manager-operation-templates/azure/resourcemanager/operationtemplates/_utils/__init__.py b/packages/typespec-python/test/azure/generated/azure-resource-manager-operation-templates/azure/resourcemanager/operationtemplates/_utils/__init__.py new file mode 100644 index 00000000000..8026245c2ab --- /dev/null +++ b/packages/typespec-python/test/azure/generated/azure-resource-manager-operation-templates/azure/resourcemanager/operationtemplates/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) Python Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/typespec-python/test/azure/generated/azure-resource-manager-operation-templates/azure/resourcemanager/operationtemplates/_model_base.py b/packages/typespec-python/test/azure/generated/azure-resource-manager-operation-templates/azure/resourcemanager/operationtemplates/_utils/model_base.py similarity index 100% rename from packages/typespec-python/test/azure/generated/azure-resource-manager-operation-templates/azure/resourcemanager/operationtemplates/_model_base.py rename to packages/typespec-python/test/azure/generated/azure-resource-manager-operation-templates/azure/resourcemanager/operationtemplates/_utils/model_base.py diff --git a/packages/typespec-python/test/azure/generated/azure-resource-manager-operation-templates/azure/resourcemanager/operationtemplates/_serialization.py b/packages/typespec-python/test/azure/generated/azure-resource-manager-operation-templates/azure/resourcemanager/operationtemplates/_utils/serialization.py similarity index 100% rename from packages/typespec-python/test/azure/generated/azure-resource-manager-operation-templates/azure/resourcemanager/operationtemplates/_serialization.py rename to packages/typespec-python/test/azure/generated/azure-resource-manager-operation-templates/azure/resourcemanager/operationtemplates/_utils/serialization.py diff --git a/packages/typespec-python/test/azure/generated/azure-resource-manager-operation-templates/azure/resourcemanager/operationtemplates/aio/_client.py b/packages/typespec-python/test/azure/generated/azure-resource-manager-operation-templates/azure/resourcemanager/operationtemplates/aio/_client.py index 5668367ecd4..2690133d51b 100644 --- a/packages/typespec-python/test/azure/generated/azure-resource-manager-operation-templates/azure/resourcemanager/operationtemplates/aio/_client.py +++ b/packages/typespec-python/test/azure/generated/azure-resource-manager-operation-templates/azure/resourcemanager/operationtemplates/aio/_client.py @@ -17,7 +17,7 @@ from azure.mgmt.core.policies import AsyncARMAutoResourceProviderRegistrationPolicy from azure.mgmt.core.tools import get_arm_endpoints -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import OperationTemplatesClientConfiguration from .operations import CheckNameAvailabilityOperations, LroOperations, Operations diff --git a/packages/typespec-python/test/azure/generated/azure-resource-manager-operation-templates/azure/resourcemanager/operationtemplates/aio/operations/_operations.py b/packages/typespec-python/test/azure/generated/azure-resource-manager-operation-templates/azure/resourcemanager/operationtemplates/aio/operations/_operations.py index 0ee9a00adf7..dc0965765d5 100644 --- a/packages/typespec-python/test/azure/generated/azure-resource-manager-operation-templates/azure/resourcemanager/operationtemplates/aio/operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/azure-resource-manager-operation-templates/azure/resourcemanager/operationtemplates/aio/operations/_operations.py @@ -34,8 +34,8 @@ from azure.mgmt.core.polling.async_arm_polling import AsyncARMPolling from ... import models as _models -from ..._model_base import SdkJSONEncoder, _deserialize, _failsafe_deserialize -from ..._serialization import Deserializer, Serializer +from ..._utils.model_base import SdkJSONEncoder, _deserialize, _failsafe_deserialize +from ..._utils.serialization import Deserializer, Serializer from ...operations._operations import ( build_check_name_availability_check_global_request, build_check_name_availability_check_local_request, diff --git a/packages/typespec-python/test/azure/generated/azure-resource-manager-operation-templates/azure/resourcemanager/operationtemplates/models/_models.py b/packages/typespec-python/test/azure/generated/azure-resource-manager-operation-templates/azure/resourcemanager/operationtemplates/models/_models.py index 8fb824dab0e..4b72aaab3ef 100644 --- a/packages/typespec-python/test/azure/generated/azure-resource-manager-operation-templates/azure/resourcemanager/operationtemplates/models/_models.py +++ b/packages/typespec-python/test/azure/generated/azure-resource-manager-operation-templates/azure/resourcemanager/operationtemplates/models/_models.py @@ -11,14 +11,13 @@ import datetime from typing import Any, Dict, List, Mapping, Optional, TYPE_CHECKING, Union, overload -from .. import _model_base -from .._model_base import rest_field +from .._utils.model_base import Model as _Model, rest_field if TYPE_CHECKING: from .. import models as _models -class CheckNameAvailabilityRequest(_model_base.Model): +class CheckNameAvailabilityRequest(_Model): """The check availability request body. :ivar name: The name of the resource for which availability needs to be checked. @@ -51,7 +50,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class CheckNameAvailabilityResponse(_model_base.Model): +class CheckNameAvailabilityResponse(_Model): """The check availability result. :ivar name_available: Indicates if the resource name is available. @@ -96,7 +95,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class ErrorAdditionalInfo(_model_base.Model): +class ErrorAdditionalInfo(_Model): """The resource management error additional info. :ivar type: The additional info type. @@ -111,7 +110,7 @@ class ErrorAdditionalInfo(_model_base.Model): """The additional info.""" -class ErrorDetail(_model_base.Model): +class ErrorDetail(_Model): """The error detail. :ivar code: The error code. @@ -141,7 +140,7 @@ class ErrorDetail(_model_base.Model): """The error additional info.""" -class ErrorResponse(_model_base.Model): +class ErrorResponse(_Model): """Common error response for all Azure Resource Manager APIs to return error details for failed operations. @@ -170,7 +169,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class ExportRequest(_model_base.Model): +class ExportRequest(_Model): """ExportRequest. :ivar format: Format of the exported order. Required. @@ -198,7 +197,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class ExportResult(_model_base.Model): +class ExportResult(_Model): """ExportResult. :ivar content: Content of the exported order. Required. @@ -226,7 +225,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class Operation(_model_base.Model): +class Operation(_Model): """Details of a REST API operation, returned from the Resource Provider Operations API. :ivar name: The name of the operation, as per Resource-Based Access Control (RBAC). Examples: @@ -283,7 +282,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class OperationDisplay(_model_base.Model): +class OperationDisplay(_Model): """Localized display information for and operation. :ivar provider: The localized friendly form of the resource provider name, e.g. "Microsoft @@ -314,7 +313,7 @@ class OperationDisplay(_model_base.Model): views.""" -class Resource(_model_base.Model): +class Resource(_Model): """Common fields that are returned in the response for all Azure Resource Manager resources. :ivar id: Fully qualified resource ID for the resource. Ex - @@ -435,7 +434,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class OrderProperties(_model_base.Model): +class OrderProperties(_Model): """OrderProperties. :ivar product_id: The product ID of the order. Required. @@ -472,7 +471,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class SystemData(_model_base.Model): +class SystemData(_Model): """Metadata pertaining to creation and last modification of the resource. :ivar created_by: The identity that created the resource. diff --git a/packages/typespec-python/test/azure/generated/azure-resource-manager-operation-templates/azure/resourcemanager/operationtemplates/operations/_operations.py b/packages/typespec-python/test/azure/generated/azure-resource-manager-operation-templates/azure/resourcemanager/operationtemplates/operations/_operations.py index b2906cb9406..927918afffc 100644 --- a/packages/typespec-python/test/azure/generated/azure-resource-manager-operation-templates/azure/resourcemanager/operationtemplates/operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/azure-resource-manager-operation-templates/azure/resourcemanager/operationtemplates/operations/_operations.py @@ -34,8 +34,8 @@ from .. import models as _models from .._configuration import OperationTemplatesClientConfiguration -from .._model_base import SdkJSONEncoder, _deserialize, _failsafe_deserialize -from .._serialization import Deserializer, Serializer +from .._utils.model_base import SdkJSONEncoder, _deserialize, _failsafe_deserialize +from .._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/typespec-python/test/azure/generated/azure-resource-manager-resources/azure/resourcemanager/resources/_client.py b/packages/typespec-python/test/azure/generated/azure-resource-manager-resources/azure/resourcemanager/resources/_client.py index 3b855ea8a9a..65233664115 100644 --- a/packages/typespec-python/test/azure/generated/azure-resource-manager-resources/azure/resourcemanager/resources/_client.py +++ b/packages/typespec-python/test/azure/generated/azure-resource-manager-resources/azure/resourcemanager/resources/_client.py @@ -18,7 +18,7 @@ from azure.mgmt.core.tools import get_arm_endpoints from ._configuration import ResourcesClientConfiguration -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer from .operations import ( ExtensionsResourcesOperations, LocationResourcesOperations, diff --git a/packages/typespec-python/test/azure/generated/azure-resource-manager-resources/azure/resourcemanager/resources/_utils/__init__.py b/packages/typespec-python/test/azure/generated/azure-resource-manager-resources/azure/resourcemanager/resources/_utils/__init__.py new file mode 100644 index 00000000000..8026245c2ab --- /dev/null +++ b/packages/typespec-python/test/azure/generated/azure-resource-manager-resources/azure/resourcemanager/resources/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) Python Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/typespec-python/test/azure/generated/azure-resource-manager-resources/azure/resourcemanager/resources/_model_base.py b/packages/typespec-python/test/azure/generated/azure-resource-manager-resources/azure/resourcemanager/resources/_utils/model_base.py similarity index 100% rename from packages/typespec-python/test/azure/generated/azure-resource-manager-resources/azure/resourcemanager/resources/_model_base.py rename to packages/typespec-python/test/azure/generated/azure-resource-manager-resources/azure/resourcemanager/resources/_utils/model_base.py diff --git a/packages/typespec-python/test/azure/generated/azure-resource-manager-resources/azure/resourcemanager/resources/_serialization.py b/packages/typespec-python/test/azure/generated/azure-resource-manager-resources/azure/resourcemanager/resources/_utils/serialization.py similarity index 100% rename from packages/typespec-python/test/azure/generated/azure-resource-manager-resources/azure/resourcemanager/resources/_serialization.py rename to packages/typespec-python/test/azure/generated/azure-resource-manager-resources/azure/resourcemanager/resources/_utils/serialization.py diff --git a/packages/typespec-python/test/azure/generated/azure-resource-manager-resources/azure/resourcemanager/resources/aio/_client.py b/packages/typespec-python/test/azure/generated/azure-resource-manager-resources/azure/resourcemanager/resources/aio/_client.py index 5d9fb721153..73004491d76 100644 --- a/packages/typespec-python/test/azure/generated/azure-resource-manager-resources/azure/resourcemanager/resources/aio/_client.py +++ b/packages/typespec-python/test/azure/generated/azure-resource-manager-resources/azure/resourcemanager/resources/aio/_client.py @@ -17,7 +17,7 @@ from azure.mgmt.core.policies import AsyncARMAutoResourceProviderRegistrationPolicy from azure.mgmt.core.tools import get_arm_endpoints -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import ResourcesClientConfiguration from .operations import ( ExtensionsResourcesOperations, diff --git a/packages/typespec-python/test/azure/generated/azure-resource-manager-resources/azure/resourcemanager/resources/aio/operations/_operations.py b/packages/typespec-python/test/azure/generated/azure-resource-manager-resources/azure/resourcemanager/resources/aio/operations/_operations.py index 6586f877f3f..9cee1ab4ac8 100644 --- a/packages/typespec-python/test/azure/generated/azure-resource-manager-resources/azure/resourcemanager/resources/aio/operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/azure-resource-manager-resources/azure/resourcemanager/resources/aio/operations/_operations.py @@ -34,8 +34,8 @@ from azure.mgmt.core.polling.async_arm_polling import AsyncARMPolling from ... import models as _models -from ..._model_base import SdkJSONEncoder, _deserialize, _failsafe_deserialize -from ..._serialization import Deserializer, Serializer +from ..._utils.model_base import SdkJSONEncoder, _deserialize, _failsafe_deserialize +from ..._utils.serialization import Deserializer, Serializer from ...operations._operations import ( build_extensions_resources_create_or_update_request, build_extensions_resources_delete_request, diff --git a/packages/typespec-python/test/azure/generated/azure-resource-manager-resources/azure/resourcemanager/resources/models/_models.py b/packages/typespec-python/test/azure/generated/azure-resource-manager-resources/azure/resourcemanager/resources/models/_models.py index d62bd322a1d..fa03a674a70 100644 --- a/packages/typespec-python/test/azure/generated/azure-resource-manager-resources/azure/resourcemanager/resources/models/_models.py +++ b/packages/typespec-python/test/azure/generated/azure-resource-manager-resources/azure/resourcemanager/resources/models/_models.py @@ -11,14 +11,13 @@ import datetime from typing import Any, Dict, List, Mapping, Optional, TYPE_CHECKING, Union, overload -from .. import _model_base -from .._model_base import rest_field +from .._utils.model_base import Model as _Model, rest_field if TYPE_CHECKING: from .. import models as _models -class ErrorAdditionalInfo(_model_base.Model): +class ErrorAdditionalInfo(_Model): """The resource management error additional info. :ivar type: The additional info type. @@ -33,7 +32,7 @@ class ErrorAdditionalInfo(_model_base.Model): """The additional info.""" -class ErrorDetail(_model_base.Model): +class ErrorDetail(_Model): """The error detail. :ivar code: The error code. @@ -62,7 +61,7 @@ class ErrorDetail(_model_base.Model): """The error additional info.""" -class ErrorResponse(_model_base.Model): +class ErrorResponse(_Model): """Common error response for all Azure Resource Manager APIs to return error details for failed operations. @@ -91,7 +90,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class Resource(_model_base.Model): +class Resource(_Model): """Common fields that are returned in the response for all Azure Resource Manager resources. :ivar id: Fully qualified resource ID for the resource. Ex - @@ -178,7 +177,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class ExtensionsResourceProperties(_model_base.Model): +class ExtensionsResourceProperties(_Model): """ExtensionsResource properties. :ivar description: The description of the resource. @@ -274,7 +273,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class LocationResourceProperties(_model_base.Model): +class LocationResourceProperties(_Model): """Location resource properties. :ivar description: The description of the resource. @@ -351,7 +350,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class NestedProxyResourceProperties(_model_base.Model): +class NestedProxyResourceProperties(_Model): """Nested Proxy Resource Properties. :ivar provisioning_state: Provisioning State of the nested child Resource. Known values are: @@ -387,7 +386,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class NotificationDetails(_model_base.Model): +class NotificationDetails(_Model): """The details of a user notification. :ivar message: The notification message. Required. @@ -513,7 +512,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class SingletonTrackedResourceProperties(_model_base.Model): +class SingletonTrackedResourceProperties(_Model): """Singleton Arm Resource Properties. :ivar provisioning_state: The status of the last operation. Known values are: "Succeeded", @@ -549,7 +548,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class SystemData(_model_base.Model): +class SystemData(_Model): """Metadata pertaining to creation and last modification of the resource. :ivar created_by: The identity that created the resource. @@ -664,7 +663,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class TopLevelTrackedResourceProperties(_model_base.Model): +class TopLevelTrackedResourceProperties(_Model): """Top Level Arm Resource Properties. :ivar provisioning_state: The status of the last operation. Known values are: "Succeeded", diff --git a/packages/typespec-python/test/azure/generated/azure-resource-manager-resources/azure/resourcemanager/resources/operations/_operations.py b/packages/typespec-python/test/azure/generated/azure-resource-manager-resources/azure/resourcemanager/resources/operations/_operations.py index c5b671beca5..2cd7afed3b9 100644 --- a/packages/typespec-python/test/azure/generated/azure-resource-manager-resources/azure/resourcemanager/resources/operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/azure-resource-manager-resources/azure/resourcemanager/resources/operations/_operations.py @@ -34,8 +34,8 @@ from .. import models as _models from .._configuration import ResourcesClientConfiguration -from .._model_base import SdkJSONEncoder, _deserialize, _failsafe_deserialize -from .._serialization import Deserializer, Serializer +from .._utils.model_base import SdkJSONEncoder, _deserialize, _failsafe_deserialize +from .._utils.serialization import Deserializer, Serializer JSON = MutableMapping[str, Any] T = TypeVar("T") diff --git a/packages/typespec-python/test/azure/generated/azure-special-headers-client-request-id/azure/specialheaders/xmsclientrequestid/_client.py b/packages/typespec-python/test/azure/generated/azure-special-headers-client-request-id/azure/specialheaders/xmsclientrequestid/_client.py index a4c15831cb8..b8432d7ec75 100644 --- a/packages/typespec-python/test/azure/generated/azure-special-headers-client-request-id/azure/specialheaders/xmsclientrequestid/_client.py +++ b/packages/typespec-python/test/azure/generated/azure-special-headers-client-request-id/azure/specialheaders/xmsclientrequestid/_client.py @@ -16,7 +16,7 @@ from ._configuration import XmsClientRequestIdClientConfiguration from ._operations import XmsClientRequestIdClientOperationsMixin -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer class XmsClientRequestIdClient( diff --git a/packages/typespec-python/test/azure/generated/azure-special-headers-client-request-id/azure/specialheaders/xmsclientrequestid/_operations/_operations.py b/packages/typespec-python/test/azure/generated/azure-special-headers-client-request-id/azure/specialheaders/xmsclientrequestid/_operations/_operations.py index 0c51ef4dd7d..65a9343c66e 100644 --- a/packages/typespec-python/test/azure/generated/azure-special-headers-client-request-id/azure/specialheaders/xmsclientrequestid/_operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/azure-special-headers-client-request-id/azure/specialheaders/xmsclientrequestid/_operations/_operations.py @@ -8,6 +8,7 @@ from collections.abc import MutableMapping from typing import Any, Callable, Dict, Optional, TypeVar +from azure.core import PipelineClient from azure.core.exceptions import ( ClientAuthenticationError, HttpResponseError, @@ -21,8 +22,9 @@ from azure.core.tracing.decorator import distributed_trace from azure.core.utils import case_insensitive_dict -from .._serialization import Serializer -from .._vendor import XmsClientRequestIdClientMixinABC +from .._configuration import XmsClientRequestIdClientConfiguration +from .._utils.serialization import Serializer +from .._utils.utils import ClientMixinABC T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] @@ -42,7 +44,7 @@ def build_xms_client_request_id_get_request(**kwargs: Any) -> HttpRequest: return HttpRequest(method="GET", url=_url, headers=_headers, **kwargs) -class XmsClientRequestIdClientOperationsMixin(XmsClientRequestIdClientMixinABC): +class XmsClientRequestIdClientOperationsMixin(ClientMixinABC[PipelineClient, XmsClientRequestIdClientConfiguration]): @distributed_trace def get(self, **kwargs: Any) -> None: # pylint: disable=inconsistent-return-statements diff --git a/packages/typespec-python/test/azure/generated/azure-special-headers-client-request-id/azure/specialheaders/xmsclientrequestid/_utils/__init__.py b/packages/typespec-python/test/azure/generated/azure-special-headers-client-request-id/azure/specialheaders/xmsclientrequestid/_utils/__init__.py new file mode 100644 index 00000000000..8026245c2ab --- /dev/null +++ b/packages/typespec-python/test/azure/generated/azure-special-headers-client-request-id/azure/specialheaders/xmsclientrequestid/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) Python Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/typespec-python/test/azure/generated/azure-special-headers-client-request-id/azure/specialheaders/xmsclientrequestid/_model_base.py b/packages/typespec-python/test/azure/generated/azure-special-headers-client-request-id/azure/specialheaders/xmsclientrequestid/_utils/model_base.py similarity index 100% rename from packages/typespec-python/test/azure/generated/azure-special-headers-client-request-id/azure/specialheaders/xmsclientrequestid/_model_base.py rename to packages/typespec-python/test/azure/generated/azure-special-headers-client-request-id/azure/specialheaders/xmsclientrequestid/_utils/model_base.py diff --git a/packages/typespec-python/test/azure/generated/azure-special-headers-client-request-id/azure/specialheaders/xmsclientrequestid/_serialization.py b/packages/typespec-python/test/azure/generated/azure-special-headers-client-request-id/azure/specialheaders/xmsclientrequestid/_utils/serialization.py similarity index 100% rename from packages/typespec-python/test/azure/generated/azure-special-headers-client-request-id/azure/specialheaders/xmsclientrequestid/_serialization.py rename to packages/typespec-python/test/azure/generated/azure-special-headers-client-request-id/azure/specialheaders/xmsclientrequestid/_utils/serialization.py diff --git a/packages/typespec-python/test/azure/generated/azure-special-headers-client-request-id/azure/specialheaders/xmsclientrequestid/_utils/utils.py b/packages/typespec-python/test/azure/generated/azure-special-headers-client-request-id/azure/specialheaders/xmsclientrequestid/_utils/utils.py new file mode 100644 index 00000000000..35c9c836f85 --- /dev/null +++ b/packages/typespec-python/test/azure/generated/azure-special-headers-client-request-id/azure/specialheaders/xmsclientrequestid/_utils/utils.py @@ -0,0 +1,25 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) Python Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from abc import ABC +from typing import Generic, TYPE_CHECKING, TypeVar + +if TYPE_CHECKING: + from .serialization import Deserializer, Serializer + + +TClient = TypeVar("TClient") +TConfig = TypeVar("TConfig") + + +class ClientMixinABC(ABC, Generic[TClient, TConfig]): + """DO NOT use this class. It is for internal typing use only.""" + + _client: TClient + _config: TConfig + _serialize: "Serializer" + _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/azure/generated/azure-special-headers-client-request-id/azure/specialheaders/xmsclientrequestid/_vendor.py b/packages/typespec-python/test/azure/generated/azure-special-headers-client-request-id/azure/specialheaders/xmsclientrequestid/_vendor.py deleted file mode 100644 index 1114c6de90e..00000000000 --- a/packages/typespec-python/test/azure/generated/azure-special-headers-client-request-id/azure/specialheaders/xmsclientrequestid/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) Python Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import XmsClientRequestIdClientConfiguration - -if TYPE_CHECKING: - from azure.core import PipelineClient - - from ._serialization import Deserializer, Serializer - - -class XmsClientRequestIdClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "PipelineClient" - _config: XmsClientRequestIdClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/azure/generated/azure-special-headers-client-request-id/azure/specialheaders/xmsclientrequestid/aio/_client.py b/packages/typespec-python/test/azure/generated/azure-special-headers-client-request-id/azure/specialheaders/xmsclientrequestid/aio/_client.py index d1cc6670862..2f5d6c204f9 100644 --- a/packages/typespec-python/test/azure/generated/azure-special-headers-client-request-id/azure/specialheaders/xmsclientrequestid/aio/_client.py +++ b/packages/typespec-python/test/azure/generated/azure-special-headers-client-request-id/azure/specialheaders/xmsclientrequestid/aio/_client.py @@ -14,7 +14,7 @@ from azure.core.pipeline import policies from azure.core.rest import AsyncHttpResponse, HttpRequest -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import XmsClientRequestIdClientConfiguration from ._operations import XmsClientRequestIdClientOperationsMixin diff --git a/packages/typespec-python/test/azure/generated/azure-special-headers-client-request-id/azure/specialheaders/xmsclientrequestid/aio/_operations/_operations.py b/packages/typespec-python/test/azure/generated/azure-special-headers-client-request-id/azure/specialheaders/xmsclientrequestid/aio/_operations/_operations.py index c4b056a6e40..a21f4c97a28 100644 --- a/packages/typespec-python/test/azure/generated/azure-special-headers-client-request-id/azure/specialheaders/xmsclientrequestid/aio/_operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/azure-special-headers-client-request-id/azure/specialheaders/xmsclientrequestid/aio/_operations/_operations.py @@ -9,6 +9,7 @@ from collections.abc import MutableMapping from typing import Any, Callable, Dict, Optional, TypeVar +from azure.core import AsyncPipelineClient from azure.core.exceptions import ( ClientAuthenticationError, HttpResponseError, @@ -22,13 +23,16 @@ from azure.core.tracing.decorator_async import distributed_trace_async from ..._operations._operations import build_xms_client_request_id_get_request -from .._vendor import XmsClientRequestIdClientMixinABC +from ..._utils.utils import ClientMixinABC +from .._configuration import XmsClientRequestIdClientConfiguration T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, AsyncHttpResponse], T, Dict[str, Any]], Any]] -class XmsClientRequestIdClientOperationsMixin(XmsClientRequestIdClientMixinABC): +class XmsClientRequestIdClientOperationsMixin( + ClientMixinABC[AsyncPipelineClient, XmsClientRequestIdClientConfiguration] +): @distributed_trace_async async def get(self, **kwargs: Any) -> None: diff --git a/packages/typespec-python/test/azure/generated/azure-special-headers-client-request-id/azure/specialheaders/xmsclientrequestid/aio/_vendor.py b/packages/typespec-python/test/azure/generated/azure-special-headers-client-request-id/azure/specialheaders/xmsclientrequestid/aio/_vendor.py deleted file mode 100644 index f5bddb4b92b..00000000000 --- a/packages/typespec-python/test/azure/generated/azure-special-headers-client-request-id/azure/specialheaders/xmsclientrequestid/aio/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) Python Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import XmsClientRequestIdClientConfiguration - -if TYPE_CHECKING: - from azure.core import AsyncPipelineClient - - from .._serialization import Deserializer, Serializer - - -class XmsClientRequestIdClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "AsyncPipelineClient" - _config: XmsClientRequestIdClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/azure/generated/client-namespace/client/clientnamespace/_client.py b/packages/typespec-python/test/azure/generated/client-namespace/client/clientnamespace/_client.py index b21473f9297..606077ae3be 100644 --- a/packages/typespec-python/test/azure/generated/client-namespace/client/clientnamespace/_client.py +++ b/packages/typespec-python/test/azure/generated/client-namespace/client/clientnamespace/_client.py @@ -16,7 +16,7 @@ from ._configuration import ClientNamespaceFirstClientConfiguration from ._operations import ClientNamespaceFirstClientOperationsMixin -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer class ClientNamespaceFirstClient( diff --git a/packages/typespec-python/test/azure/generated/client-namespace/client/clientnamespace/_operations/_operations.py b/packages/typespec-python/test/azure/generated/client-namespace/client/clientnamespace/_operations/_operations.py index 82c4d1a25d5..f955e6cddce 100644 --- a/packages/typespec-python/test/azure/generated/client-namespace/client/clientnamespace/_operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/client-namespace/client/clientnamespace/_operations/_operations.py @@ -8,6 +8,7 @@ from collections.abc import MutableMapping from typing import Any, Callable, Dict, Optional, TypeVar +from azure.core import PipelineClient from azure.core.exceptions import ( ClientAuthenticationError, HttpResponseError, @@ -23,9 +24,10 @@ from azure.core.tracing.decorator import distributed_trace from azure.core.utils import case_insensitive_dict -from .._model_base import _deserialize -from .._serialization import Serializer -from .._vendor import ClientNamespaceFirstClientMixinABC +from .._configuration import ClientNamespaceFirstClientConfiguration +from .._utils.model_base import _deserialize +from .._utils.serialization import Serializer +from .._utils.utils import ClientMixinABC from ..first import models as _first_models2 T = TypeVar("T") @@ -49,7 +51,9 @@ def build_client_namespace_first_get_first_request(**kwargs: Any) -> HttpRequest return HttpRequest(method="GET", url=_url, headers=_headers, **kwargs) -class ClientNamespaceFirstClientOperationsMixin(ClientNamespaceFirstClientMixinABC): # pylint: disable=name-too-long +class ClientNamespaceFirstClientOperationsMixin( # pylint: disable=name-too-long + ClientMixinABC[PipelineClient, ClientNamespaceFirstClientConfiguration] +): @distributed_trace def get_first(self, **kwargs: Any) -> _first_models2.FirstClientResult: diff --git a/packages/typespec-python/test/azure/generated/client-namespace/client/clientnamespace/_utils/__init__.py b/packages/typespec-python/test/azure/generated/client-namespace/client/clientnamespace/_utils/__init__.py new file mode 100644 index 00000000000..8026245c2ab --- /dev/null +++ b/packages/typespec-python/test/azure/generated/client-namespace/client/clientnamespace/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) Python Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/typespec-python/test/azure/generated/client-namespace/client/clientnamespace/_model_base.py b/packages/typespec-python/test/azure/generated/client-namespace/client/clientnamespace/_utils/model_base.py similarity index 100% rename from packages/typespec-python/test/azure/generated/client-namespace/client/clientnamespace/_model_base.py rename to packages/typespec-python/test/azure/generated/client-namespace/client/clientnamespace/_utils/model_base.py diff --git a/packages/typespec-python/test/azure/generated/client-namespace/client/clientnamespace/_serialization.py b/packages/typespec-python/test/azure/generated/client-namespace/client/clientnamespace/_utils/serialization.py similarity index 100% rename from packages/typespec-python/test/azure/generated/client-namespace/client/clientnamespace/_serialization.py rename to packages/typespec-python/test/azure/generated/client-namespace/client/clientnamespace/_utils/serialization.py diff --git a/packages/typespec-python/test/azure/generated/client-namespace/client/clientnamespace/_utils/utils.py b/packages/typespec-python/test/azure/generated/client-namespace/client/clientnamespace/_utils/utils.py new file mode 100644 index 00000000000..35c9c836f85 --- /dev/null +++ b/packages/typespec-python/test/azure/generated/client-namespace/client/clientnamespace/_utils/utils.py @@ -0,0 +1,25 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) Python Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from abc import ABC +from typing import Generic, TYPE_CHECKING, TypeVar + +if TYPE_CHECKING: + from .serialization import Deserializer, Serializer + + +TClient = TypeVar("TClient") +TConfig = TypeVar("TConfig") + + +class ClientMixinABC(ABC, Generic[TClient, TConfig]): + """DO NOT use this class. It is for internal typing use only.""" + + _client: TClient + _config: TConfig + _serialize: "Serializer" + _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/azure/generated/client-namespace/client/clientnamespace/_vendor.py b/packages/typespec-python/test/azure/generated/client-namespace/client/clientnamespace/_vendor.py deleted file mode 100644 index 792645e732b..00000000000 --- a/packages/typespec-python/test/azure/generated/client-namespace/client/clientnamespace/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) Python Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import ClientNamespaceFirstClientConfiguration - -if TYPE_CHECKING: - from azure.core import PipelineClient - - from ._serialization import Deserializer, Serializer - - -class ClientNamespaceFirstClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "PipelineClient" - _config: ClientNamespaceFirstClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/azure/generated/client-namespace/client/clientnamespace/aio/_client.py b/packages/typespec-python/test/azure/generated/client-namespace/client/clientnamespace/aio/_client.py index c85c67b0265..49830c68cf9 100644 --- a/packages/typespec-python/test/azure/generated/client-namespace/client/clientnamespace/aio/_client.py +++ b/packages/typespec-python/test/azure/generated/client-namespace/client/clientnamespace/aio/_client.py @@ -14,7 +14,7 @@ from azure.core.pipeline import policies from azure.core.rest import AsyncHttpResponse, HttpRequest -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import ClientNamespaceFirstClientConfiguration from ._operations import ClientNamespaceFirstClientOperationsMixin diff --git a/packages/typespec-python/test/azure/generated/client-namespace/client/clientnamespace/aio/_operations/_operations.py b/packages/typespec-python/test/azure/generated/client-namespace/client/clientnamespace/aio/_operations/_operations.py index 7ff25f6a595..8592b8224e9 100644 --- a/packages/typespec-python/test/azure/generated/client-namespace/client/clientnamespace/aio/_operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/client-namespace/client/clientnamespace/aio/_operations/_operations.py @@ -9,6 +9,7 @@ from collections.abc import MutableMapping from typing import Any, Callable, Dict, Optional, TypeVar +from azure.core import AsyncPipelineClient from azure.core.exceptions import ( ClientAuthenticationError, HttpResponseError, @@ -23,16 +24,19 @@ from azure.core.rest import AsyncHttpResponse, HttpRequest from azure.core.tracing.decorator_async import distributed_trace_async -from ..._model_base import _deserialize from ..._operations._operations import build_client_namespace_first_get_first_request +from ..._utils.model_base import _deserialize +from ..._utils.utils import ClientMixinABC from ...first import models as _first_models3 -from .._vendor import ClientNamespaceFirstClientMixinABC +from .._configuration import ClientNamespaceFirstClientConfiguration T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, AsyncHttpResponse], T, Dict[str, Any]], Any]] -class ClientNamespaceFirstClientOperationsMixin(ClientNamespaceFirstClientMixinABC): # pylint: disable=name-too-long +class ClientNamespaceFirstClientOperationsMixin( # pylint: disable=name-too-long + ClientMixinABC[AsyncPipelineClient, ClientNamespaceFirstClientConfiguration] +): @distributed_trace_async async def get_first(self, **kwargs: Any) -> _first_models3.FirstClientResult: diff --git a/packages/typespec-python/test/azure/generated/client-namespace/client/clientnamespace/aio/_vendor.py b/packages/typespec-python/test/azure/generated/client-namespace/client/clientnamespace/aio/_vendor.py deleted file mode 100644 index 77db2da87b6..00000000000 --- a/packages/typespec-python/test/azure/generated/client-namespace/client/clientnamespace/aio/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) Python Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import ClientNamespaceFirstClientConfiguration - -if TYPE_CHECKING: - from azure.core import AsyncPipelineClient - - from .._serialization import Deserializer, Serializer - - -class ClientNamespaceFirstClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "AsyncPipelineClient" - _config: ClientNamespaceFirstClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/azure/generated/client-namespace/client/clientnamespace/first/models/_models.py b/packages/typespec-python/test/azure/generated/client-namespace/client/clientnamespace/first/models/_models.py index ec2edc6a21d..d105c9fda60 100644 --- a/packages/typespec-python/test/azure/generated/client-namespace/client/clientnamespace/first/models/_models.py +++ b/packages/typespec-python/test/azure/generated/client-namespace/client/clientnamespace/first/models/_models.py @@ -9,11 +9,10 @@ from typing import Any, Mapping, overload -from ... import _model_base -from ..._model_base import rest_field +from ..._utils.model_base import Model as _Model, rest_field -class FirstClientResult(_model_base.Model): +class FirstClientResult(_Model): """FirstClientResult. :ivar name: Required. diff --git a/packages/typespec-python/test/azure/generated/client-namespace/client/clientnamespace/second/_client.py b/packages/typespec-python/test/azure/generated/client-namespace/client/clientnamespace/second/_client.py index bbcc7e4f50d..b57d5f40015 100644 --- a/packages/typespec-python/test/azure/generated/client-namespace/client/clientnamespace/second/_client.py +++ b/packages/typespec-python/test/azure/generated/client-namespace/client/clientnamespace/second/_client.py @@ -14,7 +14,7 @@ from azure.core.pipeline import policies from azure.core.rest import HttpRequest, HttpResponse -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import ClientNamespaceSecondClientConfiguration from ._operations import ClientNamespaceSecondClientOperationsMixin diff --git a/packages/typespec-python/test/azure/generated/client-namespace/client/clientnamespace/second/_operations/_operations.py b/packages/typespec-python/test/azure/generated/client-namespace/client/clientnamespace/second/_operations/_operations.py index 8b21d5c4c0d..ee273813446 100644 --- a/packages/typespec-python/test/azure/generated/client-namespace/client/clientnamespace/second/_operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/client-namespace/client/clientnamespace/second/_operations/_operations.py @@ -8,6 +8,7 @@ from collections.abc import MutableMapping from typing import Any, Callable, Dict, Optional, TypeVar +from azure.core import PipelineClient from azure.core.exceptions import ( ClientAuthenticationError, HttpResponseError, @@ -24,9 +25,10 @@ from azure.core.utils import case_insensitive_dict from .. import models as _models1 -from ..._model_base import _deserialize -from ..._serialization import Serializer -from .._vendor import ClientNamespaceSecondClientMixinABC +from ..._utils.model_base import _deserialize +from ..._utils.serialization import Serializer +from ..._utils.utils import ClientMixinABC +from .._configuration import ClientNamespaceSecondClientConfiguration T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] @@ -49,7 +51,9 @@ def build_client_namespace_second_get_second_request(**kwargs: Any) -> HttpReque return HttpRequest(method="GET", url=_url, headers=_headers, **kwargs) -class ClientNamespaceSecondClientOperationsMixin(ClientNamespaceSecondClientMixinABC): # pylint: disable=name-too-long +class ClientNamespaceSecondClientOperationsMixin( # pylint: disable=name-too-long + ClientMixinABC[PipelineClient, ClientNamespaceSecondClientConfiguration] +): @distributed_trace def get_second(self, **kwargs: Any) -> _models1.SecondClientResult: diff --git a/packages/typespec-python/test/azure/generated/client-namespace/client/clientnamespace/second/_utils/__init__.py b/packages/typespec-python/test/azure/generated/client-namespace/client/clientnamespace/second/_utils/__init__.py new file mode 100644 index 00000000000..8026245c2ab --- /dev/null +++ b/packages/typespec-python/test/azure/generated/client-namespace/client/clientnamespace/second/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) Python Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/typespec-python/test/azure/generated/client-naming/client/naming/_model_base.py b/packages/typespec-python/test/azure/generated/client-namespace/client/clientnamespace/second/_utils/model_base.py similarity index 100% rename from packages/typespec-python/test/azure/generated/client-naming/client/naming/_model_base.py rename to packages/typespec-python/test/azure/generated/client-namespace/client/clientnamespace/second/_utils/model_base.py diff --git a/packages/typespec-python/test/azure/generated/client-naming/client/naming/_serialization.py b/packages/typespec-python/test/azure/generated/client-namespace/client/clientnamespace/second/_utils/serialization.py similarity index 100% rename from packages/typespec-python/test/azure/generated/client-naming/client/naming/_serialization.py rename to packages/typespec-python/test/azure/generated/client-namespace/client/clientnamespace/second/_utils/serialization.py diff --git a/packages/typespec-python/test/azure/generated/client-namespace/client/clientnamespace/second/_utils/utils.py b/packages/typespec-python/test/azure/generated/client-namespace/client/clientnamespace/second/_utils/utils.py new file mode 100644 index 00000000000..35c9c836f85 --- /dev/null +++ b/packages/typespec-python/test/azure/generated/client-namespace/client/clientnamespace/second/_utils/utils.py @@ -0,0 +1,25 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) Python Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from abc import ABC +from typing import Generic, TYPE_CHECKING, TypeVar + +if TYPE_CHECKING: + from .serialization import Deserializer, Serializer + + +TClient = TypeVar("TClient") +TConfig = TypeVar("TConfig") + + +class ClientMixinABC(ABC, Generic[TClient, TConfig]): + """DO NOT use this class. It is for internal typing use only.""" + + _client: TClient + _config: TConfig + _serialize: "Serializer" + _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/azure/generated/client-namespace/client/clientnamespace/second/_vendor.py b/packages/typespec-python/test/azure/generated/client-namespace/client/clientnamespace/second/_vendor.py deleted file mode 100644 index 6707d50a26c..00000000000 --- a/packages/typespec-python/test/azure/generated/client-namespace/client/clientnamespace/second/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) Python Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import ClientNamespaceSecondClientConfiguration - -if TYPE_CHECKING: - from azure.core import PipelineClient - - from .._serialization import Deserializer, Serializer - - -class ClientNamespaceSecondClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "PipelineClient" - _config: ClientNamespaceSecondClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/azure/generated/client-namespace/client/clientnamespace/second/aio/_client.py b/packages/typespec-python/test/azure/generated/client-namespace/client/clientnamespace/second/aio/_client.py index 11e5bf1200a..5614b01c366 100644 --- a/packages/typespec-python/test/azure/generated/client-namespace/client/clientnamespace/second/aio/_client.py +++ b/packages/typespec-python/test/azure/generated/client-namespace/client/clientnamespace/second/aio/_client.py @@ -14,7 +14,7 @@ from azure.core.pipeline import policies from azure.core.rest import AsyncHttpResponse, HttpRequest -from ..._serialization import Deserializer, Serializer +from ..._utils.serialization import Deserializer, Serializer from ._configuration import ClientNamespaceSecondClientConfiguration from ._operations import ClientNamespaceSecondClientOperationsMixin diff --git a/packages/typespec-python/test/azure/generated/client-namespace/client/clientnamespace/second/aio/_operations/_operations.py b/packages/typespec-python/test/azure/generated/client-namespace/client/clientnamespace/second/aio/_operations/_operations.py index 81e31630dcd..699d01349ee 100644 --- a/packages/typespec-python/test/azure/generated/client-namespace/client/clientnamespace/second/aio/_operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/client-namespace/client/clientnamespace/second/aio/_operations/_operations.py @@ -9,6 +9,7 @@ from collections.abc import MutableMapping from typing import Any, Callable, Dict, Optional, TypeVar +from azure.core import AsyncPipelineClient from azure.core.exceptions import ( ClientAuthenticationError, HttpResponseError, @@ -24,15 +25,18 @@ from azure.core.tracing.decorator_async import distributed_trace_async from ... import models as _models2 -from ...._model_base import _deserialize +from ...._utils.model_base import _deserialize +from ...._utils.utils import ClientMixinABC from ..._operations._operations import build_client_namespace_second_get_second_request -from .._vendor import ClientNamespaceSecondClientMixinABC +from .._configuration import ClientNamespaceSecondClientConfiguration T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, AsyncHttpResponse], T, Dict[str, Any]], Any]] -class ClientNamespaceSecondClientOperationsMixin(ClientNamespaceSecondClientMixinABC): # pylint: disable=name-too-long +class ClientNamespaceSecondClientOperationsMixin( # pylint: disable=name-too-long + ClientMixinABC[AsyncPipelineClient, ClientNamespaceSecondClientConfiguration] +): @distributed_trace_async async def get_second(self, **kwargs: Any) -> _models2.SecondClientResult: diff --git a/packages/typespec-python/test/azure/generated/client-namespace/client/clientnamespace/second/aio/_vendor.py b/packages/typespec-python/test/azure/generated/client-namespace/client/clientnamespace/second/aio/_vendor.py deleted file mode 100644 index a8e47916562..00000000000 --- a/packages/typespec-python/test/azure/generated/client-namespace/client/clientnamespace/second/aio/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) Python Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import ClientNamespaceSecondClientConfiguration - -if TYPE_CHECKING: - from azure.core import AsyncPipelineClient - - from ..._serialization import Deserializer, Serializer - - -class ClientNamespaceSecondClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "AsyncPipelineClient" - _config: ClientNamespaceSecondClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/azure/generated/client-namespace/client/clientnamespace/second/models/_models.py b/packages/typespec-python/test/azure/generated/client-namespace/client/clientnamespace/second/models/_models.py index e824ec97b4b..9e74a9906bc 100644 --- a/packages/typespec-python/test/azure/generated/client-namespace/client/clientnamespace/second/models/_models.py +++ b/packages/typespec-python/test/azure/generated/client-namespace/client/clientnamespace/second/models/_models.py @@ -9,14 +9,13 @@ from typing import Any, Mapping, TYPE_CHECKING, Union, overload -from ... import _model_base -from ..._model_base import rest_field +from ..._utils.model_base import Model as _Model, rest_field if TYPE_CHECKING: from ..sub import models as _sub_models2 -class SecondClientResult(_model_base.Model): +class SecondClientResult(_Model): """SecondClientResult. :ivar type: Required. "second" diff --git a/packages/typespec-python/test/azure/generated/client-naming/client/naming/_client.py b/packages/typespec-python/test/azure/generated/client-naming/client/naming/_client.py index 57a0dbf2a9a..635a2e81a56 100644 --- a/packages/typespec-python/test/azure/generated/client-naming/client/naming/_client.py +++ b/packages/typespec-python/test/azure/generated/client-naming/client/naming/_client.py @@ -15,7 +15,7 @@ from azure.core.rest import HttpRequest, HttpResponse from ._configuration import NamingClientConfiguration -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer from .operations import ClientModelOperations, NamingClientOperationsMixin, UnionEnumOperations diff --git a/packages/typespec-python/test/azure/generated/client-naming/client/naming/_utils/__init__.py b/packages/typespec-python/test/azure/generated/client-naming/client/naming/_utils/__init__.py new file mode 100644 index 00000000000..8026245c2ab --- /dev/null +++ b/packages/typespec-python/test/azure/generated/client-naming/client/naming/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) Python Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/typespec-python/test/azure/generated/client-structure-default/client/structure/service/_model_base.py b/packages/typespec-python/test/azure/generated/client-naming/client/naming/_utils/model_base.py similarity index 100% rename from packages/typespec-python/test/azure/generated/client-structure-default/client/structure/service/_model_base.py rename to packages/typespec-python/test/azure/generated/client-naming/client/naming/_utils/model_base.py diff --git a/packages/typespec-python/test/azure/generated/client-structure-default/client/structure/service/_serialization.py b/packages/typespec-python/test/azure/generated/client-naming/client/naming/_utils/serialization.py similarity index 100% rename from packages/typespec-python/test/azure/generated/client-structure-default/client/structure/service/_serialization.py rename to packages/typespec-python/test/azure/generated/client-naming/client/naming/_utils/serialization.py diff --git a/packages/typespec-python/test/azure/generated/client-naming/client/naming/_utils/utils.py b/packages/typespec-python/test/azure/generated/client-naming/client/naming/_utils/utils.py new file mode 100644 index 00000000000..35c9c836f85 --- /dev/null +++ b/packages/typespec-python/test/azure/generated/client-naming/client/naming/_utils/utils.py @@ -0,0 +1,25 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) Python Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from abc import ABC +from typing import Generic, TYPE_CHECKING, TypeVar + +if TYPE_CHECKING: + from .serialization import Deserializer, Serializer + + +TClient = TypeVar("TClient") +TConfig = TypeVar("TConfig") + + +class ClientMixinABC(ABC, Generic[TClient, TConfig]): + """DO NOT use this class. It is for internal typing use only.""" + + _client: TClient + _config: TConfig + _serialize: "Serializer" + _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/azure/generated/client-naming/client/naming/_vendor.py b/packages/typespec-python/test/azure/generated/client-naming/client/naming/_vendor.py deleted file mode 100644 index a2c7563548d..00000000000 --- a/packages/typespec-python/test/azure/generated/client-naming/client/naming/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) Python Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import NamingClientConfiguration - -if TYPE_CHECKING: - from azure.core import PipelineClient - - from ._serialization import Deserializer, Serializer - - -class NamingClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "PipelineClient" - _config: NamingClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/azure/generated/client-naming/client/naming/aio/_client.py b/packages/typespec-python/test/azure/generated/client-naming/client/naming/aio/_client.py index 17403bd6f0d..fb429f873f2 100644 --- a/packages/typespec-python/test/azure/generated/client-naming/client/naming/aio/_client.py +++ b/packages/typespec-python/test/azure/generated/client-naming/client/naming/aio/_client.py @@ -14,7 +14,7 @@ from azure.core.pipeline import policies from azure.core.rest import AsyncHttpResponse, HttpRequest -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import NamingClientConfiguration from .operations import ClientModelOperations, NamingClientOperationsMixin, UnionEnumOperations diff --git a/packages/typespec-python/test/azure/generated/client-naming/client/naming/aio/_vendor.py b/packages/typespec-python/test/azure/generated/client-naming/client/naming/aio/_vendor.py deleted file mode 100644 index ba41624431c..00000000000 --- a/packages/typespec-python/test/azure/generated/client-naming/client/naming/aio/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) Python Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import NamingClientConfiguration - -if TYPE_CHECKING: - from azure.core import AsyncPipelineClient - - from .._serialization import Deserializer, Serializer - - -class NamingClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "AsyncPipelineClient" - _config: NamingClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/azure/generated/client-naming/client/naming/aio/operations/_operations.py b/packages/typespec-python/test/azure/generated/client-naming/client/naming/aio/operations/_operations.py index c324b49ea91..5202abec43c 100644 --- a/packages/typespec-python/test/azure/generated/client-naming/client/naming/aio/operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/client-naming/client/naming/aio/operations/_operations.py @@ -26,8 +26,9 @@ from azure.core.utils import case_insensitive_dict from ... import models as _models -from ..._model_base import SdkJSONEncoder -from ..._serialization import Deserializer, Serializer +from ..._utils.model_base import SdkJSONEncoder +from ..._utils.serialization import Deserializer, Serializer +from ..._utils.utils import ClientMixinABC from ...operations._operations import ( build_client_model_client_request, build_client_model_language_request, @@ -42,7 +43,6 @@ build_union_enum_union_enum_name_request, ) from .._configuration import NamingClientConfiguration -from .._vendor import NamingClientMixinABC JSON = MutableMapping[str, Any] T = TypeVar("T") @@ -385,7 +385,7 @@ async def union_enum_member_name(self, body: Union[str, _models.ExtensibleEnum], return cls(pipeline_response, None, {}) # type: ignore -class NamingClientOperationsMixin(NamingClientMixinABC): +class NamingClientOperationsMixin(ClientMixinABC[AsyncPipelineClient, NamingClientConfiguration]): @distributed_trace_async async def client_name(self, **kwargs: Any) -> None: diff --git a/packages/typespec-python/test/azure/generated/client-naming/client/naming/models/_models.py b/packages/typespec-python/test/azure/generated/client-naming/client/naming/models/_models.py index 50f6302b0ee..21efec01276 100644 --- a/packages/typespec-python/test/azure/generated/client-naming/client/naming/models/_models.py +++ b/packages/typespec-python/test/azure/generated/client-naming/client/naming/models/_models.py @@ -9,11 +9,10 @@ from typing import Any, Mapping, overload -from .. import _model_base -from .._model_base import rest_field +from .._utils.model_base import Model as _Model, rest_field -class ClientModel(_model_base.Model): +class ClientModel(_Model): """ClientModel. :ivar default_name: Pass in true. Required. @@ -41,7 +40,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class ClientNameAndJsonEncodedNameModel(_model_base.Model): +class ClientNameAndJsonEncodedNameModel(_Model): """ClientNameAndJsonEncodedNameModel. :ivar client_name: Pass in true. Required. @@ -69,7 +68,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class ClientNameModel(_model_base.Model): +class ClientNameModel(_Model): """ClientNameModel. :ivar client_name: Pass in true. Required. @@ -97,7 +96,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class LanguageClientNameModel(_model_base.Model): +class LanguageClientNameModel(_Model): """LanguageClientNameModel. :ivar python_name: Pass in true. Required. @@ -125,7 +124,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class PythonModel(_model_base.Model): +class PythonModel(_Model): """PythonModel. :ivar default_name: Pass in true. Required. diff --git a/packages/typespec-python/test/azure/generated/client-naming/client/naming/operations/_operations.py b/packages/typespec-python/test/azure/generated/client-naming/client/naming/operations/_operations.py index 15e45703504..db78d8671ca 100644 --- a/packages/typespec-python/test/azure/generated/client-naming/client/naming/operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/client-naming/client/naming/operations/_operations.py @@ -27,9 +27,9 @@ from .. import models as _models from .._configuration import NamingClientConfiguration -from .._model_base import SdkJSONEncoder -from .._serialization import Deserializer, Serializer -from .._vendor import NamingClientMixinABC +from .._utils.model_base import SdkJSONEncoder +from .._utils.serialization import Deserializer, Serializer +from .._utils.utils import ClientMixinABC JSON = MutableMapping[str, Any] T = TypeVar("T") @@ -515,7 +515,7 @@ def union_enum_member_name( # pylint: disable=inconsistent-return-statements return cls(pipeline_response, None, {}) # type: ignore -class NamingClientOperationsMixin(NamingClientMixinABC): +class NamingClientOperationsMixin(ClientMixinABC[PipelineClient, NamingClientConfiguration]): @distributed_trace def client_name(self, **kwargs: Any) -> None: # pylint: disable=inconsistent-return-statements diff --git a/packages/typespec-python/test/azure/generated/client-structure-default/client/structure/service/_client.py b/packages/typespec-python/test/azure/generated/client-structure-default/client/structure/service/_client.py index e691395fb81..ad8b8c083fe 100644 --- a/packages/typespec-python/test/azure/generated/client-structure-default/client/structure/service/_client.py +++ b/packages/typespec-python/test/azure/generated/client-structure-default/client/structure/service/_client.py @@ -16,7 +16,7 @@ from . import models as _models from ._configuration import ServiceClientConfiguration -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer from .operations import BarOperations, BazOperations, FooOperations, QuxOperations, ServiceClientOperationsMixin diff --git a/packages/typespec-python/test/azure/generated/client-structure-default/client/structure/service/_utils/__init__.py b/packages/typespec-python/test/azure/generated/client-structure-default/client/structure/service/_utils/__init__.py new file mode 100644 index 00000000000..8026245c2ab --- /dev/null +++ b/packages/typespec-python/test/azure/generated/client-structure-default/client/structure/service/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) Python Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/typespec-python/test/azure/generated/client-structure-multiclient/client/structure/multiclient/_model_base.py b/packages/typespec-python/test/azure/generated/client-structure-default/client/structure/service/_utils/model_base.py similarity index 100% rename from packages/typespec-python/test/azure/generated/client-structure-multiclient/client/structure/multiclient/_model_base.py rename to packages/typespec-python/test/azure/generated/client-structure-default/client/structure/service/_utils/model_base.py diff --git a/packages/typespec-python/test/azure/generated/client-structure-multiclient/client/structure/multiclient/_serialization.py b/packages/typespec-python/test/azure/generated/client-structure-default/client/structure/service/_utils/serialization.py similarity index 100% rename from packages/typespec-python/test/azure/generated/client-structure-multiclient/client/structure/multiclient/_serialization.py rename to packages/typespec-python/test/azure/generated/client-structure-default/client/structure/service/_utils/serialization.py diff --git a/packages/typespec-python/test/azure/generated/client-structure-default/client/structure/service/_utils/utils.py b/packages/typespec-python/test/azure/generated/client-structure-default/client/structure/service/_utils/utils.py new file mode 100644 index 00000000000..35c9c836f85 --- /dev/null +++ b/packages/typespec-python/test/azure/generated/client-structure-default/client/structure/service/_utils/utils.py @@ -0,0 +1,25 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) Python Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from abc import ABC +from typing import Generic, TYPE_CHECKING, TypeVar + +if TYPE_CHECKING: + from .serialization import Deserializer, Serializer + + +TClient = TypeVar("TClient") +TConfig = TypeVar("TConfig") + + +class ClientMixinABC(ABC, Generic[TClient, TConfig]): + """DO NOT use this class. It is for internal typing use only.""" + + _client: TClient + _config: TConfig + _serialize: "Serializer" + _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/azure/generated/client-structure-default/client/structure/service/_vendor.py b/packages/typespec-python/test/azure/generated/client-structure-default/client/structure/service/_vendor.py deleted file mode 100644 index f4827264b19..00000000000 --- a/packages/typespec-python/test/azure/generated/client-structure-default/client/structure/service/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) Python Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import ServiceClientConfiguration - -if TYPE_CHECKING: - from azure.core import PipelineClient - - from ._serialization import Deserializer, Serializer - - -class ServiceClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "PipelineClient" - _config: ServiceClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/azure/generated/client-structure-default/client/structure/service/aio/_client.py b/packages/typespec-python/test/azure/generated/client-structure-default/client/structure/service/aio/_client.py index 43429a00819..a9d48c2d9c4 100644 --- a/packages/typespec-python/test/azure/generated/client-structure-default/client/structure/service/aio/_client.py +++ b/packages/typespec-python/test/azure/generated/client-structure-default/client/structure/service/aio/_client.py @@ -15,7 +15,7 @@ from azure.core.rest import AsyncHttpResponse, HttpRequest from .. import models as _models -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import ServiceClientConfiguration from .operations import BarOperations, BazOperations, FooOperations, QuxOperations, ServiceClientOperationsMixin diff --git a/packages/typespec-python/test/azure/generated/client-structure-default/client/structure/service/aio/_vendor.py b/packages/typespec-python/test/azure/generated/client-structure-default/client/structure/service/aio/_vendor.py deleted file mode 100644 index b11ec73753f..00000000000 --- a/packages/typespec-python/test/azure/generated/client-structure-default/client/structure/service/aio/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) Python Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import ServiceClientConfiguration - -if TYPE_CHECKING: - from azure.core import AsyncPipelineClient - - from .._serialization import Deserializer, Serializer - - -class ServiceClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "AsyncPipelineClient" - _config: ServiceClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/azure/generated/client-structure-default/client/structure/service/aio/operations/_operations.py b/packages/typespec-python/test/azure/generated/client-structure-default/client/structure/service/aio/operations/_operations.py index bf454ec36c0..270c3b54bb6 100644 --- a/packages/typespec-python/test/azure/generated/client-structure-default/client/structure/service/aio/operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/client-structure-default/client/structure/service/aio/operations/_operations.py @@ -22,7 +22,8 @@ from azure.core.rest import AsyncHttpResponse, HttpRequest from azure.core.tracing.decorator_async import distributed_trace_async -from ..._serialization import Deserializer, Serializer +from ..._utils.serialization import Deserializer, Serializer +from ..._utils.utils import ClientMixinABC from ...operations._operations import ( build_bar_five_request, build_bar_six_request, @@ -35,7 +36,6 @@ build_service_two_request, ) from .._configuration import ServiceClientConfiguration -from .._vendor import ServiceClientMixinABC T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, AsyncHttpResponse], T, Dict[str, Any]], Any]] @@ -342,7 +342,7 @@ async def six(self, **kwargs: Any) -> None: return cls(pipeline_response, None, {}) # type: ignore -class ServiceClientOperationsMixin(ServiceClientMixinABC): +class ServiceClientOperationsMixin(ClientMixinABC[AsyncPipelineClient, ServiceClientConfiguration]): @distributed_trace_async async def one(self, **kwargs: Any) -> None: diff --git a/packages/typespec-python/test/azure/generated/client-structure-default/client/structure/service/operations/_operations.py b/packages/typespec-python/test/azure/generated/client-structure-default/client/structure/service/operations/_operations.py index 55a13f4c1bb..c19e8e319a4 100644 --- a/packages/typespec-python/test/azure/generated/client-structure-default/client/structure/service/operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/client-structure-default/client/structure/service/operations/_operations.py @@ -22,8 +22,8 @@ from azure.core.tracing.decorator import distributed_trace from .._configuration import ServiceClientConfiguration -from .._serialization import Deserializer, Serializer -from .._vendor import ServiceClientMixinABC +from .._utils.serialization import Deserializer, Serializer +from .._utils.utils import ClientMixinABC T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] @@ -396,7 +396,7 @@ def six(self, **kwargs: Any) -> None: # pylint: disable=inconsistent-return-sta return cls(pipeline_response, None, {}) # type: ignore -class ServiceClientOperationsMixin(ServiceClientMixinABC): +class ServiceClientOperationsMixin(ClientMixinABC[PipelineClient, ServiceClientConfiguration]): @distributed_trace def one(self, **kwargs: Any) -> None: # pylint: disable=inconsistent-return-statements diff --git a/packages/typespec-python/test/azure/generated/client-structure-multiclient/client/structure/multiclient/_client.py b/packages/typespec-python/test/azure/generated/client-structure-multiclient/client/structure/multiclient/_client.py index a31c89b3c39..578d909d635 100644 --- a/packages/typespec-python/test/azure/generated/client-structure-multiclient/client/structure/multiclient/_client.py +++ b/packages/typespec-python/test/azure/generated/client-structure-multiclient/client/structure/multiclient/_client.py @@ -17,7 +17,7 @@ from . import models as _models from ._configuration import ClientAClientConfiguration, ClientBClientConfiguration from ._operations import ClientAClientOperationsMixin, ClientBClientOperationsMixin -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer class ClientAClient(ClientAClientOperationsMixin): # pylint: disable=client-accepts-api-version-keyword diff --git a/packages/typespec-python/test/azure/generated/client-structure-multiclient/client/structure/multiclient/_operations/_operations.py b/packages/typespec-python/test/azure/generated/client-structure-multiclient/client/structure/multiclient/_operations/_operations.py index 9cfea188a37..84a57ff13d6 100644 --- a/packages/typespec-python/test/azure/generated/client-structure-multiclient/client/structure/multiclient/_operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/client-structure-multiclient/client/structure/multiclient/_operations/_operations.py @@ -8,6 +8,7 @@ from collections.abc import MutableMapping from typing import Any, Callable, Dict, Optional, TypeVar +from azure.core import PipelineClient from azure.core.exceptions import ( ClientAuthenticationError, HttpResponseError, @@ -20,8 +21,9 @@ from azure.core.rest import HttpRequest, HttpResponse from azure.core.tracing.decorator import distributed_trace -from .._serialization import Serializer -from .._vendor import ClientAClientMixinABC, ClientBClientMixinABC +from .._configuration import ClientAClientConfiguration, ClientBClientConfiguration +from .._utils.serialization import Serializer +from .._utils.utils import ClientMixinABC T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] @@ -72,7 +74,7 @@ def build_client_b_renamed_six_request(**kwargs: Any) -> HttpRequest: return HttpRequest(method="POST", url=_url, **kwargs) -class ClientAClientOperationsMixin(ClientAClientMixinABC): +class ClientAClientOperationsMixin(ClientMixinABC[PipelineClient, ClientAClientConfiguration]): @distributed_trace def renamed_one(self, **kwargs: Any) -> None: # pylint: disable=inconsistent-return-statements @@ -210,7 +212,7 @@ def renamed_five(self, **kwargs: Any) -> None: # pylint: disable=inconsistent-r return cls(pipeline_response, None, {}) # type: ignore -class ClientBClientOperationsMixin(ClientBClientMixinABC): +class ClientBClientOperationsMixin(ClientMixinABC[PipelineClient, ClientBClientConfiguration]): @distributed_trace def renamed_two(self, **kwargs: Any) -> None: # pylint: disable=inconsistent-return-statements diff --git a/packages/typespec-python/test/azure/generated/client-structure-multiclient/client/structure/multiclient/_utils/__init__.py b/packages/typespec-python/test/azure/generated/client-structure-multiclient/client/structure/multiclient/_utils/__init__.py new file mode 100644 index 00000000000..8026245c2ab --- /dev/null +++ b/packages/typespec-python/test/azure/generated/client-structure-multiclient/client/structure/multiclient/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) Python Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/typespec-python/test/azure/generated/client-structure-renamedoperation/client/structure/renamedoperation/_model_base.py b/packages/typespec-python/test/azure/generated/client-structure-multiclient/client/structure/multiclient/_utils/model_base.py similarity index 100% rename from packages/typespec-python/test/azure/generated/client-structure-renamedoperation/client/structure/renamedoperation/_model_base.py rename to packages/typespec-python/test/azure/generated/client-structure-multiclient/client/structure/multiclient/_utils/model_base.py diff --git a/packages/typespec-python/test/azure/generated/client-structure-renamedoperation/client/structure/renamedoperation/_serialization.py b/packages/typespec-python/test/azure/generated/client-structure-multiclient/client/structure/multiclient/_utils/serialization.py similarity index 100% rename from packages/typespec-python/test/azure/generated/client-structure-renamedoperation/client/structure/renamedoperation/_serialization.py rename to packages/typespec-python/test/azure/generated/client-structure-multiclient/client/structure/multiclient/_utils/serialization.py diff --git a/packages/typespec-python/test/azure/generated/client-structure-multiclient/client/structure/multiclient/_utils/utils.py b/packages/typespec-python/test/azure/generated/client-structure-multiclient/client/structure/multiclient/_utils/utils.py new file mode 100644 index 00000000000..35c9c836f85 --- /dev/null +++ b/packages/typespec-python/test/azure/generated/client-structure-multiclient/client/structure/multiclient/_utils/utils.py @@ -0,0 +1,25 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) Python Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from abc import ABC +from typing import Generic, TYPE_CHECKING, TypeVar + +if TYPE_CHECKING: + from .serialization import Deserializer, Serializer + + +TClient = TypeVar("TClient") +TConfig = TypeVar("TConfig") + + +class ClientMixinABC(ABC, Generic[TClient, TConfig]): + """DO NOT use this class. It is for internal typing use only.""" + + _client: TClient + _config: TConfig + _serialize: "Serializer" + _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/azure/generated/client-structure-multiclient/client/structure/multiclient/_vendor.py b/packages/typespec-python/test/azure/generated/client-structure-multiclient/client/structure/multiclient/_vendor.py deleted file mode 100644 index 3b8be01047d..00000000000 --- a/packages/typespec-python/test/azure/generated/client-structure-multiclient/client/structure/multiclient/_vendor.py +++ /dev/null @@ -1,34 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) Python Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import ClientAClientConfiguration, ClientBClientConfiguration - -if TYPE_CHECKING: - from azure.core import PipelineClient - - from ._serialization import Deserializer, Serializer - - -class ClientAClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "PipelineClient" - _config: ClientAClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" - - -class ClientBClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "PipelineClient" - _config: ClientBClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/azure/generated/client-structure-multiclient/client/structure/multiclient/aio/_client.py b/packages/typespec-python/test/azure/generated/client-structure-multiclient/client/structure/multiclient/aio/_client.py index e346ecd1d11..175d4183b43 100644 --- a/packages/typespec-python/test/azure/generated/client-structure-multiclient/client/structure/multiclient/aio/_client.py +++ b/packages/typespec-python/test/azure/generated/client-structure-multiclient/client/structure/multiclient/aio/_client.py @@ -15,7 +15,7 @@ from azure.core.rest import AsyncHttpResponse, HttpRequest from .. import models as _models -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import ClientAClientConfiguration, ClientBClientConfiguration from ._operations import ClientAClientOperationsMixin, ClientBClientOperationsMixin diff --git a/packages/typespec-python/test/azure/generated/client-structure-multiclient/client/structure/multiclient/aio/_operations/_operations.py b/packages/typespec-python/test/azure/generated/client-structure-multiclient/client/structure/multiclient/aio/_operations/_operations.py index 9cd88018db0..d80b6e193d6 100644 --- a/packages/typespec-python/test/azure/generated/client-structure-multiclient/client/structure/multiclient/aio/_operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/client-structure-multiclient/client/structure/multiclient/aio/_operations/_operations.py @@ -9,6 +9,7 @@ from collections.abc import MutableMapping from typing import Any, Callable, Dict, Optional, TypeVar +from azure.core import AsyncPipelineClient from azure.core.exceptions import ( ClientAuthenticationError, HttpResponseError, @@ -29,13 +30,14 @@ build_client_b_renamed_six_request, build_client_b_renamed_two_request, ) -from .._vendor import ClientAClientMixinABC, ClientBClientMixinABC +from ..._utils.utils import ClientMixinABC +from .._configuration import ClientAClientConfiguration, ClientBClientConfiguration T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, AsyncHttpResponse], T, Dict[str, Any]], Any]] -class ClientAClientOperationsMixin(ClientAClientMixinABC): +class ClientAClientOperationsMixin(ClientMixinABC[AsyncPipelineClient, ClientAClientConfiguration]): @distributed_trace_async async def renamed_one(self, **kwargs: Any) -> None: @@ -173,7 +175,7 @@ async def renamed_five(self, **kwargs: Any) -> None: return cls(pipeline_response, None, {}) # type: ignore -class ClientBClientOperationsMixin(ClientBClientMixinABC): +class ClientBClientOperationsMixin(ClientMixinABC[AsyncPipelineClient, ClientBClientConfiguration]): @distributed_trace_async async def renamed_two(self, **kwargs: Any) -> None: diff --git a/packages/typespec-python/test/azure/generated/client-structure-multiclient/client/structure/multiclient/aio/_vendor.py b/packages/typespec-python/test/azure/generated/client-structure-multiclient/client/structure/multiclient/aio/_vendor.py deleted file mode 100644 index 6e8a9245612..00000000000 --- a/packages/typespec-python/test/azure/generated/client-structure-multiclient/client/structure/multiclient/aio/_vendor.py +++ /dev/null @@ -1,34 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) Python Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import ClientAClientConfiguration, ClientBClientConfiguration - -if TYPE_CHECKING: - from azure.core import AsyncPipelineClient - - from .._serialization import Deserializer, Serializer - - -class ClientAClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "AsyncPipelineClient" - _config: ClientAClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" - - -class ClientBClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "AsyncPipelineClient" - _config: ClientBClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/azure/generated/client-structure-renamedoperation/client/structure/renamedoperation/_client.py b/packages/typespec-python/test/azure/generated/client-structure-renamedoperation/client/structure/renamedoperation/_client.py index 90086d0bbd7..861d5304499 100644 --- a/packages/typespec-python/test/azure/generated/client-structure-renamedoperation/client/structure/renamedoperation/_client.py +++ b/packages/typespec-python/test/azure/generated/client-structure-renamedoperation/client/structure/renamedoperation/_client.py @@ -16,7 +16,7 @@ from . import models as _models from ._configuration import RenamedOperationClientConfiguration -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer from .operations import GroupOperations, RenamedOperationClientOperationsMixin diff --git a/packages/typespec-python/test/azure/generated/client-structure-renamedoperation/client/structure/renamedoperation/_utils/__init__.py b/packages/typespec-python/test/azure/generated/client-structure-renamedoperation/client/structure/renamedoperation/_utils/__init__.py new file mode 100644 index 00000000000..8026245c2ab --- /dev/null +++ b/packages/typespec-python/test/azure/generated/client-structure-renamedoperation/client/structure/renamedoperation/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) Python Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/typespec-python/test/azure/generated/client-structure-twooperationgroup/client/structure/twooperationgroup/_model_base.py b/packages/typespec-python/test/azure/generated/client-structure-renamedoperation/client/structure/renamedoperation/_utils/model_base.py similarity index 100% rename from packages/typespec-python/test/azure/generated/client-structure-twooperationgroup/client/structure/twooperationgroup/_model_base.py rename to packages/typespec-python/test/azure/generated/client-structure-renamedoperation/client/structure/renamedoperation/_utils/model_base.py diff --git a/packages/typespec-python/test/azure/generated/client-structure-twooperationgroup/client/structure/twooperationgroup/_serialization.py b/packages/typespec-python/test/azure/generated/client-structure-renamedoperation/client/structure/renamedoperation/_utils/serialization.py similarity index 100% rename from packages/typespec-python/test/azure/generated/client-structure-twooperationgroup/client/structure/twooperationgroup/_serialization.py rename to packages/typespec-python/test/azure/generated/client-structure-renamedoperation/client/structure/renamedoperation/_utils/serialization.py diff --git a/packages/typespec-python/test/azure/generated/client-structure-renamedoperation/client/structure/renamedoperation/_utils/utils.py b/packages/typespec-python/test/azure/generated/client-structure-renamedoperation/client/structure/renamedoperation/_utils/utils.py new file mode 100644 index 00000000000..35c9c836f85 --- /dev/null +++ b/packages/typespec-python/test/azure/generated/client-structure-renamedoperation/client/structure/renamedoperation/_utils/utils.py @@ -0,0 +1,25 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) Python Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from abc import ABC +from typing import Generic, TYPE_CHECKING, TypeVar + +if TYPE_CHECKING: + from .serialization import Deserializer, Serializer + + +TClient = TypeVar("TClient") +TConfig = TypeVar("TConfig") + + +class ClientMixinABC(ABC, Generic[TClient, TConfig]): + """DO NOT use this class. It is for internal typing use only.""" + + _client: TClient + _config: TConfig + _serialize: "Serializer" + _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/azure/generated/client-structure-renamedoperation/client/structure/renamedoperation/_vendor.py b/packages/typespec-python/test/azure/generated/client-structure-renamedoperation/client/structure/renamedoperation/_vendor.py deleted file mode 100644 index 8b9d2061a65..00000000000 --- a/packages/typespec-python/test/azure/generated/client-structure-renamedoperation/client/structure/renamedoperation/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) Python Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import RenamedOperationClientConfiguration - -if TYPE_CHECKING: - from azure.core import PipelineClient - - from ._serialization import Deserializer, Serializer - - -class RenamedOperationClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "PipelineClient" - _config: RenamedOperationClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/azure/generated/client-structure-renamedoperation/client/structure/renamedoperation/aio/_client.py b/packages/typespec-python/test/azure/generated/client-structure-renamedoperation/client/structure/renamedoperation/aio/_client.py index 5e568152dcc..45058708303 100644 --- a/packages/typespec-python/test/azure/generated/client-structure-renamedoperation/client/structure/renamedoperation/aio/_client.py +++ b/packages/typespec-python/test/azure/generated/client-structure-renamedoperation/client/structure/renamedoperation/aio/_client.py @@ -15,7 +15,7 @@ from azure.core.rest import AsyncHttpResponse, HttpRequest from .. import models as _models -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import RenamedOperationClientConfiguration from .operations import GroupOperations, RenamedOperationClientOperationsMixin diff --git a/packages/typespec-python/test/azure/generated/client-structure-renamedoperation/client/structure/renamedoperation/aio/_vendor.py b/packages/typespec-python/test/azure/generated/client-structure-renamedoperation/client/structure/renamedoperation/aio/_vendor.py deleted file mode 100644 index 6164a637cc6..00000000000 --- a/packages/typespec-python/test/azure/generated/client-structure-renamedoperation/client/structure/renamedoperation/aio/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) Python Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import RenamedOperationClientConfiguration - -if TYPE_CHECKING: - from azure.core import AsyncPipelineClient - - from .._serialization import Deserializer, Serializer - - -class RenamedOperationClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "AsyncPipelineClient" - _config: RenamedOperationClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/azure/generated/client-structure-renamedoperation/client/structure/renamedoperation/aio/operations/_operations.py b/packages/typespec-python/test/azure/generated/client-structure-renamedoperation/client/structure/renamedoperation/aio/operations/_operations.py index c857b70161a..8d50eb1b5dd 100644 --- a/packages/typespec-python/test/azure/generated/client-structure-renamedoperation/client/structure/renamedoperation/aio/operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/client-structure-renamedoperation/client/structure/renamedoperation/aio/operations/_operations.py @@ -22,7 +22,8 @@ from azure.core.rest import AsyncHttpResponse, HttpRequest from azure.core.tracing.decorator_async import distributed_trace_async -from ..._serialization import Deserializer, Serializer +from ..._utils.serialization import Deserializer, Serializer +from ..._utils.utils import ClientMixinABC from ...operations._operations import ( build_group_renamed_four_request, build_group_renamed_six_request, @@ -32,7 +33,6 @@ build_renamed_operation_renamed_three_request, ) from .._configuration import RenamedOperationClientConfiguration -from .._vendor import RenamedOperationClientMixinABC T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, AsyncHttpResponse], T, Dict[str, Any]], Any]] @@ -191,7 +191,7 @@ async def renamed_six(self, **kwargs: Any) -> None: return cls(pipeline_response, None, {}) # type: ignore -class RenamedOperationClientOperationsMixin(RenamedOperationClientMixinABC): +class RenamedOperationClientOperationsMixin(ClientMixinABC[AsyncPipelineClient, RenamedOperationClientConfiguration]): @distributed_trace_async async def renamed_one(self, **kwargs: Any) -> None: diff --git a/packages/typespec-python/test/azure/generated/client-structure-renamedoperation/client/structure/renamedoperation/operations/_operations.py b/packages/typespec-python/test/azure/generated/client-structure-renamedoperation/client/structure/renamedoperation/operations/_operations.py index fa70d32315c..979bbc07f31 100644 --- a/packages/typespec-python/test/azure/generated/client-structure-renamedoperation/client/structure/renamedoperation/operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/client-structure-renamedoperation/client/structure/renamedoperation/operations/_operations.py @@ -22,8 +22,8 @@ from azure.core.tracing.decorator import distributed_trace from .._configuration import RenamedOperationClientConfiguration -from .._serialization import Deserializer, Serializer -from .._vendor import RenamedOperationClientMixinABC +from .._utils.serialization import Deserializer, Serializer +from .._utils.utils import ClientMixinABC T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] @@ -227,7 +227,7 @@ def renamed_six(self, **kwargs: Any) -> None: # pylint: disable=inconsistent-re return cls(pipeline_response, None, {}) # type: ignore -class RenamedOperationClientOperationsMixin(RenamedOperationClientMixinABC): +class RenamedOperationClientOperationsMixin(ClientMixinABC[PipelineClient, RenamedOperationClientConfiguration]): @distributed_trace def renamed_one(self, **kwargs: Any) -> None: # pylint: disable=inconsistent-return-statements diff --git a/packages/typespec-python/test/azure/generated/client-structure-twooperationgroup/client/structure/twooperationgroup/_client.py b/packages/typespec-python/test/azure/generated/client-structure-twooperationgroup/client/structure/twooperationgroup/_client.py index aa31393c743..70e2eca45c0 100644 --- a/packages/typespec-python/test/azure/generated/client-structure-twooperationgroup/client/structure/twooperationgroup/_client.py +++ b/packages/typespec-python/test/azure/generated/client-structure-twooperationgroup/client/structure/twooperationgroup/_client.py @@ -16,7 +16,7 @@ from . import models as _models from ._configuration import TwoOperationGroupClientConfiguration -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer from .operations import Group1Operations, Group2Operations diff --git a/packages/typespec-python/test/azure/generated/client-structure-twooperationgroup/client/structure/twooperationgroup/_utils/__init__.py b/packages/typespec-python/test/azure/generated/client-structure-twooperationgroup/client/structure/twooperationgroup/_utils/__init__.py new file mode 100644 index 00000000000..8026245c2ab --- /dev/null +++ b/packages/typespec-python/test/azure/generated/client-structure-twooperationgroup/client/structure/twooperationgroup/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) Python Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/typespec-python/test/azure/generated/encode-bytes/encode/bytes/_model_base.py b/packages/typespec-python/test/azure/generated/client-structure-twooperationgroup/client/structure/twooperationgroup/_utils/model_base.py similarity index 100% rename from packages/typespec-python/test/azure/generated/encode-bytes/encode/bytes/_model_base.py rename to packages/typespec-python/test/azure/generated/client-structure-twooperationgroup/client/structure/twooperationgroup/_utils/model_base.py diff --git a/packages/typespec-python/test/azure/generated/encode-bytes/encode/bytes/_serialization.py b/packages/typespec-python/test/azure/generated/client-structure-twooperationgroup/client/structure/twooperationgroup/_utils/serialization.py similarity index 100% rename from packages/typespec-python/test/azure/generated/encode-bytes/encode/bytes/_serialization.py rename to packages/typespec-python/test/azure/generated/client-structure-twooperationgroup/client/structure/twooperationgroup/_utils/serialization.py diff --git a/packages/typespec-python/test/azure/generated/client-structure-twooperationgroup/client/structure/twooperationgroup/aio/_client.py b/packages/typespec-python/test/azure/generated/client-structure-twooperationgroup/client/structure/twooperationgroup/aio/_client.py index 2db66e63b73..cc483e5523d 100644 --- a/packages/typespec-python/test/azure/generated/client-structure-twooperationgroup/client/structure/twooperationgroup/aio/_client.py +++ b/packages/typespec-python/test/azure/generated/client-structure-twooperationgroup/client/structure/twooperationgroup/aio/_client.py @@ -15,7 +15,7 @@ from azure.core.rest import AsyncHttpResponse, HttpRequest from .. import models as _models -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import TwoOperationGroupClientConfiguration from .operations import Group1Operations, Group2Operations diff --git a/packages/typespec-python/test/azure/generated/client-structure-twooperationgroup/client/structure/twooperationgroup/aio/operations/_operations.py b/packages/typespec-python/test/azure/generated/client-structure-twooperationgroup/client/structure/twooperationgroup/aio/operations/_operations.py index 89892e09aa5..2f126c80cb6 100644 --- a/packages/typespec-python/test/azure/generated/client-structure-twooperationgroup/client/structure/twooperationgroup/aio/operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/client-structure-twooperationgroup/client/structure/twooperationgroup/aio/operations/_operations.py @@ -21,7 +21,7 @@ from azure.core.rest import AsyncHttpResponse, HttpRequest from azure.core.tracing.decorator_async import distributed_trace_async -from ..._serialization import Deserializer, Serializer +from ..._utils.serialization import Deserializer, Serializer from ...operations._operations import ( build_group1_four_request, build_group1_one_request, diff --git a/packages/typespec-python/test/azure/generated/client-structure-twooperationgroup/client/structure/twooperationgroup/operations/_operations.py b/packages/typespec-python/test/azure/generated/client-structure-twooperationgroup/client/structure/twooperationgroup/operations/_operations.py index 9286a4913b9..7799bfddc63 100644 --- a/packages/typespec-python/test/azure/generated/client-structure-twooperationgroup/client/structure/twooperationgroup/operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/client-structure-twooperationgroup/client/structure/twooperationgroup/operations/_operations.py @@ -22,7 +22,7 @@ from azure.core.tracing.decorator import distributed_trace from .._configuration import TwoOperationGroupClientConfiguration -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/typespec-python/test/azure/generated/encode-bytes/encode/bytes/_client.py b/packages/typespec-python/test/azure/generated/encode-bytes/encode/bytes/_client.py index d4b93015780..804a4e5fb29 100644 --- a/packages/typespec-python/test/azure/generated/encode-bytes/encode/bytes/_client.py +++ b/packages/typespec-python/test/azure/generated/encode-bytes/encode/bytes/_client.py @@ -15,7 +15,7 @@ from azure.core.rest import HttpRequest, HttpResponse from ._configuration import BytesClientConfiguration -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer from .header.operations import HeaderOperations from .property.operations import PropertyOperations from .query.operations import QueryOperations diff --git a/packages/typespec-python/test/azure/generated/encode-bytes/encode/bytes/_utils/__init__.py b/packages/typespec-python/test/azure/generated/encode-bytes/encode/bytes/_utils/__init__.py new file mode 100644 index 00000000000..8026245c2ab --- /dev/null +++ b/packages/typespec-python/test/azure/generated/encode-bytes/encode/bytes/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) Python Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/typespec-python/test/azure/generated/encode-datetime/encode/datetime/_model_base.py b/packages/typespec-python/test/azure/generated/encode-bytes/encode/bytes/_utils/model_base.py similarity index 100% rename from packages/typespec-python/test/azure/generated/encode-datetime/encode/datetime/_model_base.py rename to packages/typespec-python/test/azure/generated/encode-bytes/encode/bytes/_utils/model_base.py diff --git a/packages/typespec-python/test/azure/generated/encode-datetime/encode/datetime/_serialization.py b/packages/typespec-python/test/azure/generated/encode-bytes/encode/bytes/_utils/serialization.py similarity index 100% rename from packages/typespec-python/test/azure/generated/encode-datetime/encode/datetime/_serialization.py rename to packages/typespec-python/test/azure/generated/encode-bytes/encode/bytes/_utils/serialization.py diff --git a/packages/typespec-python/test/azure/generated/encode-bytes/encode/bytes/aio/_client.py b/packages/typespec-python/test/azure/generated/encode-bytes/encode/bytes/aio/_client.py index f02e1d28ddd..a5417e14639 100644 --- a/packages/typespec-python/test/azure/generated/encode-bytes/encode/bytes/aio/_client.py +++ b/packages/typespec-python/test/azure/generated/encode-bytes/encode/bytes/aio/_client.py @@ -14,7 +14,7 @@ from azure.core.pipeline import policies from azure.core.rest import AsyncHttpResponse, HttpRequest -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ..header.aio.operations import HeaderOperations from ..property.aio.operations import PropertyOperations from ..query.aio.operations import QueryOperations diff --git a/packages/typespec-python/test/azure/generated/encode-bytes/encode/bytes/header/aio/operations/_operations.py b/packages/typespec-python/test/azure/generated/encode-bytes/encode/bytes/header/aio/operations/_operations.py index 0a27bb23167..34b01918790 100644 --- a/packages/typespec-python/test/azure/generated/encode-bytes/encode/bytes/header/aio/operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/encode-bytes/encode/bytes/header/aio/operations/_operations.py @@ -21,7 +21,7 @@ from azure.core.rest import AsyncHttpResponse, HttpRequest from azure.core.tracing.decorator_async import distributed_trace_async -from ...._serialization import Deserializer, Serializer +from ...._utils.serialization import Deserializer, Serializer from ....aio._configuration import BytesClientConfiguration from ...operations._operations import ( build_header_base64_request, diff --git a/packages/typespec-python/test/azure/generated/encode-bytes/encode/bytes/header/operations/_operations.py b/packages/typespec-python/test/azure/generated/encode-bytes/encode/bytes/header/operations/_operations.py index aa0121ed3a3..0bbb48efec1 100644 --- a/packages/typespec-python/test/azure/generated/encode-bytes/encode/bytes/header/operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/encode-bytes/encode/bytes/header/operations/_operations.py @@ -23,7 +23,7 @@ from azure.core.utils import case_insensitive_dict from ..._configuration import BytesClientConfiguration -from ..._serialization import Deserializer, Serializer +from ..._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/typespec-python/test/azure/generated/encode-bytes/encode/bytes/models/_models.py b/packages/typespec-python/test/azure/generated/encode-bytes/encode/bytes/models/_models.py index d8c71dd68fe..4cfac3fcf24 100644 --- a/packages/typespec-python/test/azure/generated/encode-bytes/encode/bytes/models/_models.py +++ b/packages/typespec-python/test/azure/generated/encode-bytes/encode/bytes/models/_models.py @@ -9,11 +9,10 @@ from typing import Any, List, Mapping, overload -from .. import _model_base -from .._model_base import rest_field +from .._utils.model_base import Model as _Model, rest_field -class Base64BytesProperty(_model_base.Model): +class Base64BytesProperty(_Model): """Base64BytesProperty. :ivar value: Required. @@ -41,7 +40,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class Base64urlArrayBytesProperty(_model_base.Model): +class Base64urlArrayBytesProperty(_Model): """Base64urlArrayBytesProperty. :ivar value: Required. @@ -69,7 +68,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class Base64urlBytesProperty(_model_base.Model): +class Base64urlBytesProperty(_Model): """Base64urlBytesProperty. :ivar value: Required. @@ -97,7 +96,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class DefaultBytesProperty(_model_base.Model): +class DefaultBytesProperty(_Model): """DefaultBytesProperty. :ivar value: Required. diff --git a/packages/typespec-python/test/azure/generated/encode-bytes/encode/bytes/property/aio/operations/_operations.py b/packages/typespec-python/test/azure/generated/encode-bytes/encode/bytes/property/aio/operations/_operations.py index d04af326398..2ad2a620c35 100644 --- a/packages/typespec-python/test/azure/generated/encode-bytes/encode/bytes/property/aio/operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/encode-bytes/encode/bytes/property/aio/operations/_operations.py @@ -27,8 +27,8 @@ from azure.core.utils import case_insensitive_dict from .... import models as _models3 -from ...._model_base import SdkJSONEncoder, _deserialize -from ...._serialization import Deserializer, Serializer +from ...._utils.model_base import SdkJSONEncoder, _deserialize +from ...._utils.serialization import Deserializer, Serializer from ....aio._configuration import BytesClientConfiguration from ...operations._operations import ( build_property_base64_request, diff --git a/packages/typespec-python/test/azure/generated/encode-bytes/encode/bytes/property/operations/_operations.py b/packages/typespec-python/test/azure/generated/encode-bytes/encode/bytes/property/operations/_operations.py index 33a026ecde6..9b7649605f1 100644 --- a/packages/typespec-python/test/azure/generated/encode-bytes/encode/bytes/property/operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/encode-bytes/encode/bytes/property/operations/_operations.py @@ -28,8 +28,8 @@ from ... import models as _models2 from ..._configuration import BytesClientConfiguration -from ..._model_base import SdkJSONEncoder, _deserialize -from ..._serialization import Deserializer, Serializer +from ..._utils.model_base import SdkJSONEncoder, _deserialize +from ..._utils.serialization import Deserializer, Serializer JSON = MutableMapping[str, Any] T = TypeVar("T") diff --git a/packages/typespec-python/test/azure/generated/encode-bytes/encode/bytes/query/aio/operations/_operations.py b/packages/typespec-python/test/azure/generated/encode-bytes/encode/bytes/query/aio/operations/_operations.py index 40c2303d820..ace97a6099c 100644 --- a/packages/typespec-python/test/azure/generated/encode-bytes/encode/bytes/query/aio/operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/encode-bytes/encode/bytes/query/aio/operations/_operations.py @@ -21,7 +21,7 @@ from azure.core.rest import AsyncHttpResponse, HttpRequest from azure.core.tracing.decorator_async import distributed_trace_async -from ...._serialization import Deserializer, Serializer +from ...._utils.serialization import Deserializer, Serializer from ....aio._configuration import BytesClientConfiguration from ...operations._operations import ( build_query_base64_request, diff --git a/packages/typespec-python/test/azure/generated/encode-bytes/encode/bytes/query/operations/_operations.py b/packages/typespec-python/test/azure/generated/encode-bytes/encode/bytes/query/operations/_operations.py index d2b1dd4ca66..c796922ef2f 100644 --- a/packages/typespec-python/test/azure/generated/encode-bytes/encode/bytes/query/operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/encode-bytes/encode/bytes/query/operations/_operations.py @@ -23,7 +23,7 @@ from azure.core.utils import case_insensitive_dict from ..._configuration import BytesClientConfiguration -from ..._serialization import Deserializer, Serializer +from ..._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/typespec-python/test/azure/generated/encode-bytes/encode/bytes/requestbody/aio/operations/_operations.py b/packages/typespec-python/test/azure/generated/encode-bytes/encode/bytes/requestbody/aio/operations/_operations.py index 17f739b5687..1349671fdc7 100644 --- a/packages/typespec-python/test/azure/generated/encode-bytes/encode/bytes/requestbody/aio/operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/encode-bytes/encode/bytes/requestbody/aio/operations/_operations.py @@ -23,8 +23,8 @@ from azure.core.tracing.decorator_async import distributed_trace_async from azure.core.utils import case_insensitive_dict -from ...._model_base import SdkJSONEncoder -from ...._serialization import Deserializer, Serializer +from ...._utils.model_base import SdkJSONEncoder +from ...._utils.serialization import Deserializer, Serializer from ....aio._configuration import BytesClientConfiguration from ...operations._operations import ( build_request_body_base64_request, diff --git a/packages/typespec-python/test/azure/generated/encode-bytes/encode/bytes/requestbody/operations/_operations.py b/packages/typespec-python/test/azure/generated/encode-bytes/encode/bytes/requestbody/operations/_operations.py index 303237716cc..03519ee3675 100644 --- a/packages/typespec-python/test/azure/generated/encode-bytes/encode/bytes/requestbody/operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/encode-bytes/encode/bytes/requestbody/operations/_operations.py @@ -24,8 +24,8 @@ from azure.core.utils import case_insensitive_dict from ..._configuration import BytesClientConfiguration -from ..._model_base import SdkJSONEncoder -from ..._serialization import Deserializer, Serializer +from ..._utils.model_base import SdkJSONEncoder +from ..._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/typespec-python/test/azure/generated/encode-bytes/encode/bytes/responsebody/aio/operations/_operations.py b/packages/typespec-python/test/azure/generated/encode-bytes/encode/bytes/responsebody/aio/operations/_operations.py index 02d9792fb5f..e9e3946e0ff 100644 --- a/packages/typespec-python/test/azure/generated/encode-bytes/encode/bytes/responsebody/aio/operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/encode-bytes/encode/bytes/responsebody/aio/operations/_operations.py @@ -23,8 +23,8 @@ from azure.core.rest import AsyncHttpResponse, HttpRequest from azure.core.tracing.decorator_async import distributed_trace_async -from ...._model_base import _deserialize -from ...._serialization import Deserializer, Serializer +from ...._utils.model_base import _deserialize +from ...._utils.serialization import Deserializer, Serializer from ....aio._configuration import BytesClientConfiguration from ...operations._operations import ( build_response_body_base64_request, diff --git a/packages/typespec-python/test/azure/generated/encode-bytes/encode/bytes/responsebody/operations/_operations.py b/packages/typespec-python/test/azure/generated/encode-bytes/encode/bytes/responsebody/operations/_operations.py index fb850f0ed31..6ead1d2e634 100644 --- a/packages/typespec-python/test/azure/generated/encode-bytes/encode/bytes/responsebody/operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/encode-bytes/encode/bytes/responsebody/operations/_operations.py @@ -25,8 +25,8 @@ from azure.core.utils import case_insensitive_dict from ..._configuration import BytesClientConfiguration -from ..._model_base import _deserialize -from ..._serialization import Deserializer, Serializer +from ..._utils.model_base import _deserialize +from ..._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/typespec-python/test/azure/generated/encode-datetime/encode/datetime/_client.py b/packages/typespec-python/test/azure/generated/encode-datetime/encode/datetime/_client.py index d54c44b5e08..75e498112af 100644 --- a/packages/typespec-python/test/azure/generated/encode-datetime/encode/datetime/_client.py +++ b/packages/typespec-python/test/azure/generated/encode-datetime/encode/datetime/_client.py @@ -15,7 +15,7 @@ from azure.core.rest import HttpRequest, HttpResponse from ._configuration import DatetimeClientConfiguration -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer from .header.operations import HeaderOperations from .property.operations import PropertyOperations from .query.operations import QueryOperations diff --git a/packages/typespec-python/test/azure/generated/encode-datetime/encode/datetime/_utils/__init__.py b/packages/typespec-python/test/azure/generated/encode-datetime/encode/datetime/_utils/__init__.py new file mode 100644 index 00000000000..8026245c2ab --- /dev/null +++ b/packages/typespec-python/test/azure/generated/encode-datetime/encode/datetime/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) Python Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/typespec-python/test/azure/generated/encode-duration/encode/duration/_model_base.py b/packages/typespec-python/test/azure/generated/encode-datetime/encode/datetime/_utils/model_base.py similarity index 100% rename from packages/typespec-python/test/azure/generated/encode-duration/encode/duration/_model_base.py rename to packages/typespec-python/test/azure/generated/encode-datetime/encode/datetime/_utils/model_base.py diff --git a/packages/typespec-python/test/azure/generated/encode-duration/encode/duration/_serialization.py b/packages/typespec-python/test/azure/generated/encode-datetime/encode/datetime/_utils/serialization.py similarity index 100% rename from packages/typespec-python/test/azure/generated/encode-duration/encode/duration/_serialization.py rename to packages/typespec-python/test/azure/generated/encode-datetime/encode/datetime/_utils/serialization.py diff --git a/packages/typespec-python/test/azure/generated/encode-datetime/encode/datetime/aio/_client.py b/packages/typespec-python/test/azure/generated/encode-datetime/encode/datetime/aio/_client.py index a1d67fb8b11..fdc3587ba26 100644 --- a/packages/typespec-python/test/azure/generated/encode-datetime/encode/datetime/aio/_client.py +++ b/packages/typespec-python/test/azure/generated/encode-datetime/encode/datetime/aio/_client.py @@ -14,7 +14,7 @@ from azure.core.pipeline import policies from azure.core.rest import AsyncHttpResponse, HttpRequest -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ..header.aio.operations import HeaderOperations from ..property.aio.operations import PropertyOperations from ..query.aio.operations import QueryOperations diff --git a/packages/typespec-python/test/azure/generated/encode-datetime/encode/datetime/header/aio/operations/_operations.py b/packages/typespec-python/test/azure/generated/encode-datetime/encode/datetime/header/aio/operations/_operations.py index 2a9b28d4305..16b787ee17c 100644 --- a/packages/typespec-python/test/azure/generated/encode-datetime/encode/datetime/header/aio/operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/encode-datetime/encode/datetime/header/aio/operations/_operations.py @@ -22,7 +22,7 @@ from azure.core.rest import AsyncHttpResponse, HttpRequest from azure.core.tracing.decorator_async import distributed_trace_async -from ...._serialization import Deserializer, Serializer +from ...._utils.serialization import Deserializer, Serializer from ....aio._configuration import DatetimeClientConfiguration from ...operations._operations import ( build_header_default_request, diff --git a/packages/typespec-python/test/azure/generated/encode-datetime/encode/datetime/header/operations/_operations.py b/packages/typespec-python/test/azure/generated/encode-datetime/encode/datetime/header/operations/_operations.py index 35c89544cdd..d5155a31b0b 100644 --- a/packages/typespec-python/test/azure/generated/encode-datetime/encode/datetime/header/operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/encode-datetime/encode/datetime/header/operations/_operations.py @@ -24,7 +24,7 @@ from azure.core.utils import case_insensitive_dict from ..._configuration import DatetimeClientConfiguration -from ..._serialization import Deserializer, Serializer +from ..._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/typespec-python/test/azure/generated/encode-datetime/encode/datetime/models/_models.py b/packages/typespec-python/test/azure/generated/encode-datetime/encode/datetime/models/_models.py index 9d59dcf05a9..97e77c136a0 100644 --- a/packages/typespec-python/test/azure/generated/encode-datetime/encode/datetime/models/_models.py +++ b/packages/typespec-python/test/azure/generated/encode-datetime/encode/datetime/models/_models.py @@ -10,11 +10,10 @@ import datetime from typing import Any, List, Mapping, overload -from .. import _model_base -from .._model_base import rest_field +from .._utils.model_base import Model as _Model, rest_field -class DefaultDatetimeProperty(_model_base.Model): +class DefaultDatetimeProperty(_Model): """DefaultDatetimeProperty. :ivar value: Required. @@ -42,7 +41,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class Rfc3339DatetimeProperty(_model_base.Model): +class Rfc3339DatetimeProperty(_Model): """Rfc3339DatetimeProperty. :ivar value: Required. @@ -70,7 +69,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class Rfc7231DatetimeProperty(_model_base.Model): +class Rfc7231DatetimeProperty(_Model): """Rfc7231DatetimeProperty. :ivar value: Required. @@ -98,7 +97,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class UnixTimestampArrayDatetimeProperty(_model_base.Model): +class UnixTimestampArrayDatetimeProperty(_Model): """UnixTimestampArrayDatetimeProperty. :ivar value: Required. @@ -128,7 +127,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class UnixTimestampDatetimeProperty(_model_base.Model): +class UnixTimestampDatetimeProperty(_Model): """UnixTimestampDatetimeProperty. :ivar value: Required. diff --git a/packages/typespec-python/test/azure/generated/encode-datetime/encode/datetime/property/aio/operations/_operations.py b/packages/typespec-python/test/azure/generated/encode-datetime/encode/datetime/property/aio/operations/_operations.py index 8426b7ccd84..43602775b2a 100644 --- a/packages/typespec-python/test/azure/generated/encode-datetime/encode/datetime/property/aio/operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/encode-datetime/encode/datetime/property/aio/operations/_operations.py @@ -27,8 +27,8 @@ from azure.core.utils import case_insensitive_dict from .... import models as _models3 -from ...._model_base import SdkJSONEncoder, _deserialize -from ...._serialization import Deserializer, Serializer +from ...._utils.model_base import SdkJSONEncoder, _deserialize +from ...._utils.serialization import Deserializer, Serializer from ....aio._configuration import DatetimeClientConfiguration from ...operations._operations import ( build_property_default_request, diff --git a/packages/typespec-python/test/azure/generated/encode-datetime/encode/datetime/property/operations/_operations.py b/packages/typespec-python/test/azure/generated/encode-datetime/encode/datetime/property/operations/_operations.py index 9f44cf4eb10..b18775663b8 100644 --- a/packages/typespec-python/test/azure/generated/encode-datetime/encode/datetime/property/operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/encode-datetime/encode/datetime/property/operations/_operations.py @@ -28,8 +28,8 @@ from ... import models as _models2 from ..._configuration import DatetimeClientConfiguration -from ..._model_base import SdkJSONEncoder, _deserialize -from ..._serialization import Deserializer, Serializer +from ..._utils.model_base import SdkJSONEncoder, _deserialize +from ..._utils.serialization import Deserializer, Serializer JSON = MutableMapping[str, Any] T = TypeVar("T") diff --git a/packages/typespec-python/test/azure/generated/encode-datetime/encode/datetime/query/aio/operations/_operations.py b/packages/typespec-python/test/azure/generated/encode-datetime/encode/datetime/query/aio/operations/_operations.py index 2e6df1d6c43..5ff4fae9282 100644 --- a/packages/typespec-python/test/azure/generated/encode-datetime/encode/datetime/query/aio/operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/encode-datetime/encode/datetime/query/aio/operations/_operations.py @@ -22,7 +22,7 @@ from azure.core.rest import AsyncHttpResponse, HttpRequest from azure.core.tracing.decorator_async import distributed_trace_async -from ...._serialization import Deserializer, Serializer +from ...._utils.serialization import Deserializer, Serializer from ....aio._configuration import DatetimeClientConfiguration from ...operations._operations import ( build_query_default_request, diff --git a/packages/typespec-python/test/azure/generated/encode-datetime/encode/datetime/query/operations/_operations.py b/packages/typespec-python/test/azure/generated/encode-datetime/encode/datetime/query/operations/_operations.py index 3888fcbc6d6..50cf3340a71 100644 --- a/packages/typespec-python/test/azure/generated/encode-datetime/encode/datetime/query/operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/encode-datetime/encode/datetime/query/operations/_operations.py @@ -24,7 +24,7 @@ from azure.core.utils import case_insensitive_dict from ..._configuration import DatetimeClientConfiguration -from ..._serialization import Deserializer, Serializer +from ..._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/typespec-python/test/azure/generated/encode-datetime/encode/datetime/responseheader/aio/operations/_operations.py b/packages/typespec-python/test/azure/generated/encode-datetime/encode/datetime/responseheader/aio/operations/_operations.py index 8e0dfe0fdec..80260c85a99 100644 --- a/packages/typespec-python/test/azure/generated/encode-datetime/encode/datetime/responseheader/aio/operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/encode-datetime/encode/datetime/responseheader/aio/operations/_operations.py @@ -21,7 +21,7 @@ from azure.core.rest import AsyncHttpResponse, HttpRequest from azure.core.tracing.decorator_async import distributed_trace_async -from ...._serialization import Deserializer, Serializer +from ...._utils.serialization import Deserializer, Serializer from ....aio._configuration import DatetimeClientConfiguration from ...operations._operations import ( build_response_header_default_request, diff --git a/packages/typespec-python/test/azure/generated/encode-datetime/encode/datetime/responseheader/operations/_operations.py b/packages/typespec-python/test/azure/generated/encode-datetime/encode/datetime/responseheader/operations/_operations.py index 69deb444b78..485a18a2a54 100644 --- a/packages/typespec-python/test/azure/generated/encode-datetime/encode/datetime/responseheader/operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/encode-datetime/encode/datetime/responseheader/operations/_operations.py @@ -22,7 +22,7 @@ from azure.core.tracing.decorator import distributed_trace from ..._configuration import DatetimeClientConfiguration -from ..._serialization import Deserializer, Serializer +from ..._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/typespec-python/test/azure/generated/encode-duration/encode/duration/_client.py b/packages/typespec-python/test/azure/generated/encode-duration/encode/duration/_client.py index ec866588325..eaa36842d9a 100644 --- a/packages/typespec-python/test/azure/generated/encode-duration/encode/duration/_client.py +++ b/packages/typespec-python/test/azure/generated/encode-duration/encode/duration/_client.py @@ -15,7 +15,7 @@ from azure.core.rest import HttpRequest, HttpResponse from ._configuration import DurationClientConfiguration -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer from .operations import HeaderOperations, PropertyOperations, QueryOperations diff --git a/packages/typespec-python/test/azure/generated/encode-duration/encode/duration/_utils/__init__.py b/packages/typespec-python/test/azure/generated/encode-duration/encode/duration/_utils/__init__.py new file mode 100644 index 00000000000..8026245c2ab --- /dev/null +++ b/packages/typespec-python/test/azure/generated/encode-duration/encode/duration/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) Python Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/typespec-python/test/azure/generated/encode-numeric/encode/numeric/_model_base.py b/packages/typespec-python/test/azure/generated/encode-duration/encode/duration/_utils/model_base.py similarity index 100% rename from packages/typespec-python/test/azure/generated/encode-numeric/encode/numeric/_model_base.py rename to packages/typespec-python/test/azure/generated/encode-duration/encode/duration/_utils/model_base.py diff --git a/packages/typespec-python/test/azure/generated/encode-numeric/encode/numeric/_serialization.py b/packages/typespec-python/test/azure/generated/encode-duration/encode/duration/_utils/serialization.py similarity index 100% rename from packages/typespec-python/test/azure/generated/encode-numeric/encode/numeric/_serialization.py rename to packages/typespec-python/test/azure/generated/encode-duration/encode/duration/_utils/serialization.py diff --git a/packages/typespec-python/test/azure/generated/encode-duration/encode/duration/aio/_client.py b/packages/typespec-python/test/azure/generated/encode-duration/encode/duration/aio/_client.py index e6a73e1e1ac..f67866d4be9 100644 --- a/packages/typespec-python/test/azure/generated/encode-duration/encode/duration/aio/_client.py +++ b/packages/typespec-python/test/azure/generated/encode-duration/encode/duration/aio/_client.py @@ -14,7 +14,7 @@ from azure.core.pipeline import policies from azure.core.rest import AsyncHttpResponse, HttpRequest -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import DurationClientConfiguration from .operations import HeaderOperations, PropertyOperations, QueryOperations diff --git a/packages/typespec-python/test/azure/generated/encode-duration/encode/duration/aio/operations/_operations.py b/packages/typespec-python/test/azure/generated/encode-duration/encode/duration/aio/operations/_operations.py index 516208aaee1..b63b3ac963f 100644 --- a/packages/typespec-python/test/azure/generated/encode-duration/encode/duration/aio/operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/encode-duration/encode/duration/aio/operations/_operations.py @@ -29,8 +29,8 @@ from azure.core.utils import case_insensitive_dict from ... import models as _models -from ..._model_base import SdkJSONEncoder, _deserialize -from ..._serialization import Deserializer, Serializer +from ..._utils.model_base import SdkJSONEncoder, _deserialize +from ..._utils.serialization import Deserializer, Serializer from ...operations._operations import ( build_header_default_request, build_header_float64_seconds_request, diff --git a/packages/typespec-python/test/azure/generated/encode-duration/encode/duration/models/_models.py b/packages/typespec-python/test/azure/generated/encode-duration/encode/duration/models/_models.py index a55bf7e46c4..c73527be7e5 100644 --- a/packages/typespec-python/test/azure/generated/encode-duration/encode/duration/models/_models.py +++ b/packages/typespec-python/test/azure/generated/encode-duration/encode/duration/models/_models.py @@ -10,11 +10,10 @@ import datetime from typing import Any, List, Mapping, overload -from .. import _model_base -from .._model_base import rest_field +from .._utils.model_base import Model as _Model, rest_field -class DefaultDurationProperty(_model_base.Model): +class DefaultDurationProperty(_Model): """DefaultDurationProperty. :ivar value: Required. @@ -42,7 +41,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class Float64SecondsDurationProperty(_model_base.Model): +class Float64SecondsDurationProperty(_Model): """Float64SecondsDurationProperty. :ivar value: Required. @@ -70,7 +69,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class FloatSecondsDurationArrayProperty(_model_base.Model): +class FloatSecondsDurationArrayProperty(_Model): """FloatSecondsDurationArrayProperty. :ivar value: Required. @@ -98,7 +97,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class FloatSecondsDurationProperty(_model_base.Model): +class FloatSecondsDurationProperty(_Model): """FloatSecondsDurationProperty. :ivar value: Required. @@ -126,7 +125,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class Int32SecondsDurationProperty(_model_base.Model): +class Int32SecondsDurationProperty(_Model): """Int32SecondsDurationProperty. :ivar value: Required. @@ -154,7 +153,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class ISO8601DurationProperty(_model_base.Model): +class ISO8601DurationProperty(_Model): """ISO8601DurationProperty. :ivar value: Required. diff --git a/packages/typespec-python/test/azure/generated/encode-duration/encode/duration/operations/_operations.py b/packages/typespec-python/test/azure/generated/encode-duration/encode/duration/operations/_operations.py index 8c270769978..7d034a5f881 100644 --- a/packages/typespec-python/test/azure/generated/encode-duration/encode/duration/operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/encode-duration/encode/duration/operations/_operations.py @@ -30,8 +30,8 @@ from .. import models as _models from .._configuration import DurationClientConfiguration -from .._model_base import SdkJSONEncoder, _deserialize -from .._serialization import Deserializer, Serializer +from .._utils.model_base import SdkJSONEncoder, _deserialize +from .._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/typespec-python/test/azure/generated/encode-numeric/encode/numeric/_client.py b/packages/typespec-python/test/azure/generated/encode-numeric/encode/numeric/_client.py index 1ca830f4eda..72bca37699d 100644 --- a/packages/typespec-python/test/azure/generated/encode-numeric/encode/numeric/_client.py +++ b/packages/typespec-python/test/azure/generated/encode-numeric/encode/numeric/_client.py @@ -15,7 +15,7 @@ from azure.core.rest import HttpRequest, HttpResponse from ._configuration import NumericClientConfiguration -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer from .operations import PropertyOperations diff --git a/packages/typespec-python/test/azure/generated/encode-numeric/encode/numeric/_utils/__init__.py b/packages/typespec-python/test/azure/generated/encode-numeric/encode/numeric/_utils/__init__.py new file mode 100644 index 00000000000..8026245c2ab --- /dev/null +++ b/packages/typespec-python/test/azure/generated/encode-numeric/encode/numeric/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) Python Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/typespec-python/test/azure/generated/headasbooleanfalse/headasbooleanfalse/_model_base.py b/packages/typespec-python/test/azure/generated/encode-numeric/encode/numeric/_utils/model_base.py similarity index 100% rename from packages/typespec-python/test/azure/generated/headasbooleanfalse/headasbooleanfalse/_model_base.py rename to packages/typespec-python/test/azure/generated/encode-numeric/encode/numeric/_utils/model_base.py diff --git a/packages/typespec-python/test/azure/generated/headasbooleanfalse/headasbooleanfalse/_serialization.py b/packages/typespec-python/test/azure/generated/encode-numeric/encode/numeric/_utils/serialization.py similarity index 100% rename from packages/typespec-python/test/azure/generated/headasbooleanfalse/headasbooleanfalse/_serialization.py rename to packages/typespec-python/test/azure/generated/encode-numeric/encode/numeric/_utils/serialization.py diff --git a/packages/typespec-python/test/azure/generated/encode-numeric/encode/numeric/aio/_client.py b/packages/typespec-python/test/azure/generated/encode-numeric/encode/numeric/aio/_client.py index 4ddef49b924..abe20217686 100644 --- a/packages/typespec-python/test/azure/generated/encode-numeric/encode/numeric/aio/_client.py +++ b/packages/typespec-python/test/azure/generated/encode-numeric/encode/numeric/aio/_client.py @@ -14,7 +14,7 @@ from azure.core.pipeline import policies from azure.core.rest import AsyncHttpResponse, HttpRequest -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import NumericClientConfiguration from .operations import PropertyOperations diff --git a/packages/typespec-python/test/azure/generated/encode-numeric/encode/numeric/aio/operations/_operations.py b/packages/typespec-python/test/azure/generated/encode-numeric/encode/numeric/aio/operations/_operations.py index f8092f2d50e..541c4602bfa 100644 --- a/packages/typespec-python/test/azure/generated/encode-numeric/encode/numeric/aio/operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/encode-numeric/encode/numeric/aio/operations/_operations.py @@ -27,8 +27,8 @@ from azure.core.utils import case_insensitive_dict from ... import models as _models -from ..._model_base import SdkJSONEncoder, _deserialize -from ..._serialization import Deserializer, Serializer +from ..._utils.model_base import SdkJSONEncoder, _deserialize +from ..._utils.serialization import Deserializer, Serializer from ...operations._operations import ( build_property_safeint_as_string_request, build_property_uint32_as_string_optional_request, diff --git a/packages/typespec-python/test/azure/generated/encode-numeric/encode/numeric/models/_models.py b/packages/typespec-python/test/azure/generated/encode-numeric/encode/numeric/models/_models.py index 91af13a3300..986b17f1324 100644 --- a/packages/typespec-python/test/azure/generated/encode-numeric/encode/numeric/models/_models.py +++ b/packages/typespec-python/test/azure/generated/encode-numeric/encode/numeric/models/_models.py @@ -9,11 +9,10 @@ from typing import Any, Mapping, Optional, overload -from .. import _model_base -from .._model_base import rest_field +from .._utils.model_base import Model as _Model, rest_field -class SafeintAsStringProperty(_model_base.Model): +class SafeintAsStringProperty(_Model): """SafeintAsStringProperty. :ivar value: Required. @@ -41,7 +40,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class Uint32AsStringProperty(_model_base.Model): +class Uint32AsStringProperty(_Model): """Uint32AsStringProperty. :ivar value: @@ -68,7 +67,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class Uint8AsStringProperty(_model_base.Model): +class Uint8AsStringProperty(_Model): """Uint8AsStringProperty. :ivar value: Required. diff --git a/packages/typespec-python/test/azure/generated/encode-numeric/encode/numeric/operations/_operations.py b/packages/typespec-python/test/azure/generated/encode-numeric/encode/numeric/operations/_operations.py index 0383d92b991..5265093d19a 100644 --- a/packages/typespec-python/test/azure/generated/encode-numeric/encode/numeric/operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/encode-numeric/encode/numeric/operations/_operations.py @@ -28,8 +28,8 @@ from .. import models as _models from .._configuration import NumericClientConfiguration -from .._model_base import SdkJSONEncoder, _deserialize -from .._serialization import Deserializer, Serializer +from .._utils.model_base import SdkJSONEncoder, _deserialize +from .._utils.serialization import Deserializer, Serializer JSON = MutableMapping[str, Any] T = TypeVar("T") diff --git a/packages/typespec-python/test/azure/generated/headasbooleanfalse/headasbooleanfalse/_client.py b/packages/typespec-python/test/azure/generated/headasbooleanfalse/headasbooleanfalse/_client.py index 6bcb252c135..cf9ba9de23d 100644 --- a/packages/typespec-python/test/azure/generated/headasbooleanfalse/headasbooleanfalse/_client.py +++ b/packages/typespec-python/test/azure/generated/headasbooleanfalse/headasbooleanfalse/_client.py @@ -16,7 +16,7 @@ from ._configuration import VisibilityClientConfiguration from ._operations import VisibilityClientOperationsMixin -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer class VisibilityClient(VisibilityClientOperationsMixin): # pylint: disable=client-accepts-api-version-keyword diff --git a/packages/typespec-python/test/azure/generated/headasbooleanfalse/headasbooleanfalse/_operations/_operations.py b/packages/typespec-python/test/azure/generated/headasbooleanfalse/headasbooleanfalse/_operations/_operations.py index 0b9554a9ef0..9843fca7041 100644 --- a/packages/typespec-python/test/azure/generated/headasbooleanfalse/headasbooleanfalse/_operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/headasbooleanfalse/headasbooleanfalse/_operations/_operations.py @@ -10,6 +10,7 @@ import json from typing import Any, Callable, Dict, IO, Optional, TypeVar, Union, overload +from azure.core import PipelineClient from azure.core.exceptions import ( ClientAuthenticationError, HttpResponseError, @@ -26,9 +27,10 @@ from azure.core.utils import case_insensitive_dict from .. import models as _models -from .._model_base import SdkJSONEncoder, _deserialize -from .._serialization import Serializer -from .._vendor import VisibilityClientMixinABC +from .._configuration import VisibilityClientConfiguration +from .._utils.model_base import SdkJSONEncoder, _deserialize +from .._utils.serialization import Serializer +from .._utils.utils import ClientMixinABC JSON = MutableMapping[str, Any] T = TypeVar("T") @@ -150,7 +152,7 @@ def build_visibility_put_read_only_model_request(**kwargs: Any) -> HttpRequest: return HttpRequest(method="PUT", url=_url, headers=_headers, **kwargs) -class VisibilityClientOperationsMixin(VisibilityClientMixinABC): +class VisibilityClientOperationsMixin(ClientMixinABC[PipelineClient, VisibilityClientConfiguration]): @overload def get_model( diff --git a/packages/typespec-python/test/azure/generated/headasbooleanfalse/headasbooleanfalse/_utils/__init__.py b/packages/typespec-python/test/azure/generated/headasbooleanfalse/headasbooleanfalse/_utils/__init__.py new file mode 100644 index 00000000000..8026245c2ab --- /dev/null +++ b/packages/typespec-python/test/azure/generated/headasbooleanfalse/headasbooleanfalse/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) Python Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/typespec-python/test/azure/generated/headasbooleantrue/headasbooleantrue/_model_base.py b/packages/typespec-python/test/azure/generated/headasbooleanfalse/headasbooleanfalse/_utils/model_base.py similarity index 100% rename from packages/typespec-python/test/azure/generated/headasbooleantrue/headasbooleantrue/_model_base.py rename to packages/typespec-python/test/azure/generated/headasbooleanfalse/headasbooleanfalse/_utils/model_base.py diff --git a/packages/typespec-python/test/azure/generated/headasbooleantrue/headasbooleantrue/_serialization.py b/packages/typespec-python/test/azure/generated/headasbooleanfalse/headasbooleanfalse/_utils/serialization.py similarity index 100% rename from packages/typespec-python/test/azure/generated/headasbooleantrue/headasbooleantrue/_serialization.py rename to packages/typespec-python/test/azure/generated/headasbooleanfalse/headasbooleanfalse/_utils/serialization.py diff --git a/packages/typespec-python/test/azure/generated/headasbooleanfalse/headasbooleanfalse/_utils/utils.py b/packages/typespec-python/test/azure/generated/headasbooleanfalse/headasbooleanfalse/_utils/utils.py new file mode 100644 index 00000000000..35c9c836f85 --- /dev/null +++ b/packages/typespec-python/test/azure/generated/headasbooleanfalse/headasbooleanfalse/_utils/utils.py @@ -0,0 +1,25 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) Python Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from abc import ABC +from typing import Generic, TYPE_CHECKING, TypeVar + +if TYPE_CHECKING: + from .serialization import Deserializer, Serializer + + +TClient = TypeVar("TClient") +TConfig = TypeVar("TConfig") + + +class ClientMixinABC(ABC, Generic[TClient, TConfig]): + """DO NOT use this class. It is for internal typing use only.""" + + _client: TClient + _config: TConfig + _serialize: "Serializer" + _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/azure/generated/headasbooleanfalse/headasbooleanfalse/_vendor.py b/packages/typespec-python/test/azure/generated/headasbooleanfalse/headasbooleanfalse/_vendor.py deleted file mode 100644 index f3eb127559a..00000000000 --- a/packages/typespec-python/test/azure/generated/headasbooleanfalse/headasbooleanfalse/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) Python Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import VisibilityClientConfiguration - -if TYPE_CHECKING: - from azure.core import PipelineClient - - from ._serialization import Deserializer, Serializer - - -class VisibilityClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "PipelineClient" - _config: VisibilityClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/azure/generated/headasbooleanfalse/headasbooleanfalse/aio/_client.py b/packages/typespec-python/test/azure/generated/headasbooleanfalse/headasbooleanfalse/aio/_client.py index 4e1e87d614a..8d64d30a7a2 100644 --- a/packages/typespec-python/test/azure/generated/headasbooleanfalse/headasbooleanfalse/aio/_client.py +++ b/packages/typespec-python/test/azure/generated/headasbooleanfalse/headasbooleanfalse/aio/_client.py @@ -14,7 +14,7 @@ from azure.core.pipeline import policies from azure.core.rest import AsyncHttpResponse, HttpRequest -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import VisibilityClientConfiguration from ._operations import VisibilityClientOperationsMixin diff --git a/packages/typespec-python/test/azure/generated/headasbooleanfalse/headasbooleanfalse/aio/_operations/_operations.py b/packages/typespec-python/test/azure/generated/headasbooleanfalse/headasbooleanfalse/aio/_operations/_operations.py index def7ffd3fbc..ef93cd1472a 100644 --- a/packages/typespec-python/test/azure/generated/headasbooleanfalse/headasbooleanfalse/aio/_operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/headasbooleanfalse/headasbooleanfalse/aio/_operations/_operations.py @@ -11,6 +11,7 @@ import json from typing import Any, Callable, Dict, IO, Optional, TypeVar, Union, overload +from azure.core import AsyncPipelineClient from azure.core.exceptions import ( ClientAuthenticationError, HttpResponseError, @@ -27,7 +28,6 @@ from azure.core.utils import case_insensitive_dict from ... import models as _models -from ..._model_base import SdkJSONEncoder, _deserialize from ..._operations._operations import ( build_visibility_delete_model_request, build_visibility_get_model_request, @@ -37,14 +37,16 @@ build_visibility_put_model_request, build_visibility_put_read_only_model_request, ) -from .._vendor import VisibilityClientMixinABC +from ..._utils.model_base import SdkJSONEncoder, _deserialize +from ..._utils.utils import ClientMixinABC +from .._configuration import VisibilityClientConfiguration JSON = MutableMapping[str, Any] T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, AsyncHttpResponse], T, Dict[str, Any]], Any]] -class VisibilityClientOperationsMixin(VisibilityClientMixinABC): +class VisibilityClientOperationsMixin(ClientMixinABC[AsyncPipelineClient, VisibilityClientConfiguration]): @overload async def get_model( diff --git a/packages/typespec-python/test/azure/generated/headasbooleanfalse/headasbooleanfalse/aio/_vendor.py b/packages/typespec-python/test/azure/generated/headasbooleanfalse/headasbooleanfalse/aio/_vendor.py deleted file mode 100644 index 59219e20434..00000000000 --- a/packages/typespec-python/test/azure/generated/headasbooleanfalse/headasbooleanfalse/aio/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) Python Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import VisibilityClientConfiguration - -if TYPE_CHECKING: - from azure.core import AsyncPipelineClient - - from .._serialization import Deserializer, Serializer - - -class VisibilityClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "AsyncPipelineClient" - _config: VisibilityClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/azure/generated/headasbooleanfalse/headasbooleanfalse/models/_models.py b/packages/typespec-python/test/azure/generated/headasbooleanfalse/headasbooleanfalse/models/_models.py index 8bb7ceb2bb3..e4b8dcd1fd4 100644 --- a/packages/typespec-python/test/azure/generated/headasbooleanfalse/headasbooleanfalse/models/_models.py +++ b/packages/typespec-python/test/azure/generated/headasbooleanfalse/headasbooleanfalse/models/_models.py @@ -9,11 +9,10 @@ from typing import Any, Dict, List, Mapping, Optional, overload -from .. import _model_base -from .._model_base import rest_field +from .._utils.model_base import Model as _Model, rest_field -class ReadOnlyModel(_model_base.Model): +class ReadOnlyModel(_Model): """RoundTrip model with readonly optional properties. :ivar optional_nullable_int_list: Optional readonly nullable int list. @@ -28,7 +27,7 @@ class ReadOnlyModel(_model_base.Model): """Optional readonly string dictionary.""" -class VisibilityModel(_model_base.Model): +class VisibilityModel(_Model): """Output model with visibility properties. :ivar read_prop: Required string, illustrating a readonly property. Required. diff --git a/packages/typespec-python/test/azure/generated/headasbooleantrue/headasbooleantrue/_client.py b/packages/typespec-python/test/azure/generated/headasbooleantrue/headasbooleantrue/_client.py index 6bcb252c135..cf9ba9de23d 100644 --- a/packages/typespec-python/test/azure/generated/headasbooleantrue/headasbooleantrue/_client.py +++ b/packages/typespec-python/test/azure/generated/headasbooleantrue/headasbooleantrue/_client.py @@ -16,7 +16,7 @@ from ._configuration import VisibilityClientConfiguration from ._operations import VisibilityClientOperationsMixin -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer class VisibilityClient(VisibilityClientOperationsMixin): # pylint: disable=client-accepts-api-version-keyword diff --git a/packages/typespec-python/test/azure/generated/headasbooleantrue/headasbooleantrue/_operations/_operations.py b/packages/typespec-python/test/azure/generated/headasbooleantrue/headasbooleantrue/_operations/_operations.py index ab55197d24a..d5ba59ab3cc 100644 --- a/packages/typespec-python/test/azure/generated/headasbooleantrue/headasbooleantrue/_operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/headasbooleantrue/headasbooleantrue/_operations/_operations.py @@ -10,6 +10,7 @@ import json from typing import Any, Callable, Dict, IO, Optional, TypeVar, Union, overload +from azure.core import PipelineClient from azure.core.exceptions import ( ClientAuthenticationError, HttpResponseError, @@ -26,9 +27,10 @@ from azure.core.utils import case_insensitive_dict from .. import models as _models -from .._model_base import SdkJSONEncoder, _deserialize -from .._serialization import Serializer -from .._vendor import VisibilityClientMixinABC +from .._configuration import VisibilityClientConfiguration +from .._utils.model_base import SdkJSONEncoder, _deserialize +from .._utils.serialization import Serializer +from .._utils.utils import ClientMixinABC JSON = MutableMapping[str, Any] T = TypeVar("T") @@ -150,7 +152,7 @@ def build_visibility_put_read_only_model_request(**kwargs: Any) -> HttpRequest: return HttpRequest(method="PUT", url=_url, headers=_headers, **kwargs) -class VisibilityClientOperationsMixin(VisibilityClientMixinABC): +class VisibilityClientOperationsMixin(ClientMixinABC[PipelineClient, VisibilityClientConfiguration]): @overload def get_model( diff --git a/packages/typespec-python/test/azure/generated/headasbooleantrue/headasbooleantrue/_utils/__init__.py b/packages/typespec-python/test/azure/generated/headasbooleantrue/headasbooleantrue/_utils/__init__.py new file mode 100644 index 00000000000..8026245c2ab --- /dev/null +++ b/packages/typespec-python/test/azure/generated/headasbooleantrue/headasbooleantrue/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) Python Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/typespec-python/test/azure/generated/parameters-basic/parameters/basic/_model_base.py b/packages/typespec-python/test/azure/generated/headasbooleantrue/headasbooleantrue/_utils/model_base.py similarity index 100% rename from packages/typespec-python/test/azure/generated/parameters-basic/parameters/basic/_model_base.py rename to packages/typespec-python/test/azure/generated/headasbooleantrue/headasbooleantrue/_utils/model_base.py diff --git a/packages/typespec-python/test/azure/generated/parameters-basic/parameters/basic/_serialization.py b/packages/typespec-python/test/azure/generated/headasbooleantrue/headasbooleantrue/_utils/serialization.py similarity index 100% rename from packages/typespec-python/test/azure/generated/parameters-basic/parameters/basic/_serialization.py rename to packages/typespec-python/test/azure/generated/headasbooleantrue/headasbooleantrue/_utils/serialization.py diff --git a/packages/typespec-python/test/azure/generated/headasbooleantrue/headasbooleantrue/_utils/utils.py b/packages/typespec-python/test/azure/generated/headasbooleantrue/headasbooleantrue/_utils/utils.py new file mode 100644 index 00000000000..35c9c836f85 --- /dev/null +++ b/packages/typespec-python/test/azure/generated/headasbooleantrue/headasbooleantrue/_utils/utils.py @@ -0,0 +1,25 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) Python Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from abc import ABC +from typing import Generic, TYPE_CHECKING, TypeVar + +if TYPE_CHECKING: + from .serialization import Deserializer, Serializer + + +TClient = TypeVar("TClient") +TConfig = TypeVar("TConfig") + + +class ClientMixinABC(ABC, Generic[TClient, TConfig]): + """DO NOT use this class. It is for internal typing use only.""" + + _client: TClient + _config: TConfig + _serialize: "Serializer" + _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/azure/generated/headasbooleantrue/headasbooleantrue/_vendor.py b/packages/typespec-python/test/azure/generated/headasbooleantrue/headasbooleantrue/_vendor.py deleted file mode 100644 index f3eb127559a..00000000000 --- a/packages/typespec-python/test/azure/generated/headasbooleantrue/headasbooleantrue/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) Python Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import VisibilityClientConfiguration - -if TYPE_CHECKING: - from azure.core import PipelineClient - - from ._serialization import Deserializer, Serializer - - -class VisibilityClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "PipelineClient" - _config: VisibilityClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/azure/generated/headasbooleantrue/headasbooleantrue/aio/_client.py b/packages/typespec-python/test/azure/generated/headasbooleantrue/headasbooleantrue/aio/_client.py index 4e1e87d614a..8d64d30a7a2 100644 --- a/packages/typespec-python/test/azure/generated/headasbooleantrue/headasbooleantrue/aio/_client.py +++ b/packages/typespec-python/test/azure/generated/headasbooleantrue/headasbooleantrue/aio/_client.py @@ -14,7 +14,7 @@ from azure.core.pipeline import policies from azure.core.rest import AsyncHttpResponse, HttpRequest -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import VisibilityClientConfiguration from ._operations import VisibilityClientOperationsMixin diff --git a/packages/typespec-python/test/azure/generated/headasbooleantrue/headasbooleantrue/aio/_operations/_operations.py b/packages/typespec-python/test/azure/generated/headasbooleantrue/headasbooleantrue/aio/_operations/_operations.py index 6508886729c..35cf5d717ce 100644 --- a/packages/typespec-python/test/azure/generated/headasbooleantrue/headasbooleantrue/aio/_operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/headasbooleantrue/headasbooleantrue/aio/_operations/_operations.py @@ -11,6 +11,7 @@ import json from typing import Any, Callable, Dict, IO, Optional, TypeVar, Union, overload +from azure.core import AsyncPipelineClient from azure.core.exceptions import ( ClientAuthenticationError, HttpResponseError, @@ -27,7 +28,6 @@ from azure.core.utils import case_insensitive_dict from ... import models as _models -from ..._model_base import SdkJSONEncoder, _deserialize from ..._operations._operations import ( build_visibility_delete_model_request, build_visibility_get_model_request, @@ -37,14 +37,16 @@ build_visibility_put_model_request, build_visibility_put_read_only_model_request, ) -from .._vendor import VisibilityClientMixinABC +from ..._utils.model_base import SdkJSONEncoder, _deserialize +from ..._utils.utils import ClientMixinABC +from .._configuration import VisibilityClientConfiguration JSON = MutableMapping[str, Any] T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, AsyncHttpResponse], T, Dict[str, Any]], Any]] -class VisibilityClientOperationsMixin(VisibilityClientMixinABC): +class VisibilityClientOperationsMixin(ClientMixinABC[AsyncPipelineClient, VisibilityClientConfiguration]): @overload async def get_model( diff --git a/packages/typespec-python/test/azure/generated/headasbooleantrue/headasbooleantrue/aio/_vendor.py b/packages/typespec-python/test/azure/generated/headasbooleantrue/headasbooleantrue/aio/_vendor.py deleted file mode 100644 index 59219e20434..00000000000 --- a/packages/typespec-python/test/azure/generated/headasbooleantrue/headasbooleantrue/aio/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) Python Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import VisibilityClientConfiguration - -if TYPE_CHECKING: - from azure.core import AsyncPipelineClient - - from .._serialization import Deserializer, Serializer - - -class VisibilityClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "AsyncPipelineClient" - _config: VisibilityClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/azure/generated/headasbooleantrue/headasbooleantrue/models/_models.py b/packages/typespec-python/test/azure/generated/headasbooleantrue/headasbooleantrue/models/_models.py index 8bb7ceb2bb3..e4b8dcd1fd4 100644 --- a/packages/typespec-python/test/azure/generated/headasbooleantrue/headasbooleantrue/models/_models.py +++ b/packages/typespec-python/test/azure/generated/headasbooleantrue/headasbooleantrue/models/_models.py @@ -9,11 +9,10 @@ from typing import Any, Dict, List, Mapping, Optional, overload -from .. import _model_base -from .._model_base import rest_field +from .._utils.model_base import Model as _Model, rest_field -class ReadOnlyModel(_model_base.Model): +class ReadOnlyModel(_Model): """RoundTrip model with readonly optional properties. :ivar optional_nullable_int_list: Optional readonly nullable int list. @@ -28,7 +27,7 @@ class ReadOnlyModel(_model_base.Model): """Optional readonly string dictionary.""" -class VisibilityModel(_model_base.Model): +class VisibilityModel(_Model): """Output model with visibility properties. :ivar read_prop: Required string, illustrating a readonly property. Required. diff --git a/packages/typespec-python/test/azure/generated/parameters-basic/parameters/basic/_client.py b/packages/typespec-python/test/azure/generated/parameters-basic/parameters/basic/_client.py index 5a31ec336d8..a7ec55a26d3 100644 --- a/packages/typespec-python/test/azure/generated/parameters-basic/parameters/basic/_client.py +++ b/packages/typespec-python/test/azure/generated/parameters-basic/parameters/basic/_client.py @@ -15,7 +15,7 @@ from azure.core.rest import HttpRequest, HttpResponse from ._configuration import BasicClientConfiguration -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer from .operations import ExplicitBodyOperations, ImplicitBodyOperations diff --git a/packages/typespec-python/test/azure/generated/parameters-basic/parameters/basic/_utils/__init__.py b/packages/typespec-python/test/azure/generated/parameters-basic/parameters/basic/_utils/__init__.py new file mode 100644 index 00000000000..8026245c2ab --- /dev/null +++ b/packages/typespec-python/test/azure/generated/parameters-basic/parameters/basic/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) Python Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/typespec-python/test/azure/generated/parameters-body-optionality/parameters/bodyoptionality/_model_base.py b/packages/typespec-python/test/azure/generated/parameters-basic/parameters/basic/_utils/model_base.py similarity index 100% rename from packages/typespec-python/test/azure/generated/parameters-body-optionality/parameters/bodyoptionality/_model_base.py rename to packages/typespec-python/test/azure/generated/parameters-basic/parameters/basic/_utils/model_base.py diff --git a/packages/typespec-python/test/azure/generated/parameters-body-optionality/parameters/bodyoptionality/_serialization.py b/packages/typespec-python/test/azure/generated/parameters-basic/parameters/basic/_utils/serialization.py similarity index 100% rename from packages/typespec-python/test/azure/generated/parameters-body-optionality/parameters/bodyoptionality/_serialization.py rename to packages/typespec-python/test/azure/generated/parameters-basic/parameters/basic/_utils/serialization.py diff --git a/packages/typespec-python/test/azure/generated/parameters-basic/parameters/basic/aio/_client.py b/packages/typespec-python/test/azure/generated/parameters-basic/parameters/basic/aio/_client.py index 8f5d82c0d03..37dde679254 100644 --- a/packages/typespec-python/test/azure/generated/parameters-basic/parameters/basic/aio/_client.py +++ b/packages/typespec-python/test/azure/generated/parameters-basic/parameters/basic/aio/_client.py @@ -14,7 +14,7 @@ from azure.core.pipeline import policies from azure.core.rest import AsyncHttpResponse, HttpRequest -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import BasicClientConfiguration from .operations import ExplicitBodyOperations, ImplicitBodyOperations diff --git a/packages/typespec-python/test/azure/generated/parameters-basic/parameters/basic/aio/operations/_operations.py b/packages/typespec-python/test/azure/generated/parameters-basic/parameters/basic/aio/operations/_operations.py index b0aee317cab..41bf6ffa01d 100644 --- a/packages/typespec-python/test/azure/generated/parameters-basic/parameters/basic/aio/operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/parameters-basic/parameters/basic/aio/operations/_operations.py @@ -25,8 +25,8 @@ from azure.core.utils import case_insensitive_dict from ... import models as _models -from ..._model_base import SdkJSONEncoder -from ..._serialization import Deserializer, Serializer +from ..._utils.model_base import SdkJSONEncoder +from ..._utils.serialization import Deserializer, Serializer from ...operations._operations import build_explicit_body_simple_request, build_implicit_body_simple_request from .._configuration import BasicClientConfiguration diff --git a/packages/typespec-python/test/azure/generated/parameters-basic/parameters/basic/models/_models.py b/packages/typespec-python/test/azure/generated/parameters-basic/parameters/basic/models/_models.py index b068e5f17f7..992007476bc 100644 --- a/packages/typespec-python/test/azure/generated/parameters-basic/parameters/basic/models/_models.py +++ b/packages/typespec-python/test/azure/generated/parameters-basic/parameters/basic/models/_models.py @@ -9,11 +9,10 @@ from typing import Any, Mapping, overload -from .. import _model_base -from .._model_base import rest_field +from .._utils.model_base import Model as _Model, rest_field -class User(_model_base.Model): +class User(_Model): """This is a simple model. :ivar name: Required. diff --git a/packages/typespec-python/test/azure/generated/parameters-basic/parameters/basic/operations/_operations.py b/packages/typespec-python/test/azure/generated/parameters-basic/parameters/basic/operations/_operations.py index 5d97c99e936..634af746fe6 100644 --- a/packages/typespec-python/test/azure/generated/parameters-basic/parameters/basic/operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/parameters-basic/parameters/basic/operations/_operations.py @@ -26,8 +26,8 @@ from .. import models as _models from .._configuration import BasicClientConfiguration -from .._model_base import SdkJSONEncoder -from .._serialization import Deserializer, Serializer +from .._utils.model_base import SdkJSONEncoder +from .._utils.serialization import Deserializer, Serializer JSON = MutableMapping[str, Any] T = TypeVar("T") diff --git a/packages/typespec-python/test/azure/generated/parameters-body-optionality/parameters/bodyoptionality/_client.py b/packages/typespec-python/test/azure/generated/parameters-body-optionality/parameters/bodyoptionality/_client.py index 4aafd29f051..1a77842bca5 100644 --- a/packages/typespec-python/test/azure/generated/parameters-body-optionality/parameters/bodyoptionality/_client.py +++ b/packages/typespec-python/test/azure/generated/parameters-body-optionality/parameters/bodyoptionality/_client.py @@ -16,7 +16,7 @@ from ._configuration import BodyOptionalityClientConfiguration from ._operations import BodyOptionalityClientOperationsMixin -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer from .optionalexplicit.operations import OptionalExplicitOperations diff --git a/packages/typespec-python/test/azure/generated/parameters-body-optionality/parameters/bodyoptionality/_operations/_operations.py b/packages/typespec-python/test/azure/generated/parameters-body-optionality/parameters/bodyoptionality/_operations/_operations.py index 02a966cf1e0..655647d02c4 100644 --- a/packages/typespec-python/test/azure/generated/parameters-body-optionality/parameters/bodyoptionality/_operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/parameters-body-optionality/parameters/bodyoptionality/_operations/_operations.py @@ -10,6 +10,7 @@ import json from typing import Any, Callable, Dict, IO, Optional, TypeVar, Union, overload +from azure.core import PipelineClient from azure.core.exceptions import ( ClientAuthenticationError, HttpResponseError, @@ -24,9 +25,10 @@ from azure.core.utils import case_insensitive_dict from .. import models as _models1 -from .._model_base import SdkJSONEncoder -from .._serialization import Serializer -from .._vendor import BodyOptionalityClientMixinABC +from .._configuration import BodyOptionalityClientConfiguration +from .._utils.model_base import SdkJSONEncoder +from .._utils.serialization import Serializer +from .._utils.utils import ClientMixinABC JSON = MutableMapping[str, Any] _Unset: Any = object() @@ -65,7 +67,7 @@ def build_body_optionality_required_implicit_request(**kwargs: Any) -> HttpReque return HttpRequest(method="POST", url=_url, headers=_headers, **kwargs) -class BodyOptionalityClientOperationsMixin(BodyOptionalityClientMixinABC): +class BodyOptionalityClientOperationsMixin(ClientMixinABC[PipelineClient, BodyOptionalityClientConfiguration]): @overload def required_explicit( diff --git a/packages/typespec-python/test/azure/generated/parameters-body-optionality/parameters/bodyoptionality/_utils/__init__.py b/packages/typespec-python/test/azure/generated/parameters-body-optionality/parameters/bodyoptionality/_utils/__init__.py new file mode 100644 index 00000000000..8026245c2ab --- /dev/null +++ b/packages/typespec-python/test/azure/generated/parameters-body-optionality/parameters/bodyoptionality/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) Python Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/typespec-python/test/azure/generated/parameters-collection-format/parameters/collectionformat/_model_base.py b/packages/typespec-python/test/azure/generated/parameters-body-optionality/parameters/bodyoptionality/_utils/model_base.py similarity index 100% rename from packages/typespec-python/test/azure/generated/parameters-collection-format/parameters/collectionformat/_model_base.py rename to packages/typespec-python/test/azure/generated/parameters-body-optionality/parameters/bodyoptionality/_utils/model_base.py diff --git a/packages/typespec-python/test/azure/generated/parameters-collection-format/parameters/collectionformat/_serialization.py b/packages/typespec-python/test/azure/generated/parameters-body-optionality/parameters/bodyoptionality/_utils/serialization.py similarity index 100% rename from packages/typespec-python/test/azure/generated/parameters-collection-format/parameters/collectionformat/_serialization.py rename to packages/typespec-python/test/azure/generated/parameters-body-optionality/parameters/bodyoptionality/_utils/serialization.py diff --git a/packages/typespec-python/test/azure/generated/parameters-body-optionality/parameters/bodyoptionality/_utils/utils.py b/packages/typespec-python/test/azure/generated/parameters-body-optionality/parameters/bodyoptionality/_utils/utils.py new file mode 100644 index 00000000000..35c9c836f85 --- /dev/null +++ b/packages/typespec-python/test/azure/generated/parameters-body-optionality/parameters/bodyoptionality/_utils/utils.py @@ -0,0 +1,25 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) Python Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from abc import ABC +from typing import Generic, TYPE_CHECKING, TypeVar + +if TYPE_CHECKING: + from .serialization import Deserializer, Serializer + + +TClient = TypeVar("TClient") +TConfig = TypeVar("TConfig") + + +class ClientMixinABC(ABC, Generic[TClient, TConfig]): + """DO NOT use this class. It is for internal typing use only.""" + + _client: TClient + _config: TConfig + _serialize: "Serializer" + _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/azure/generated/parameters-body-optionality/parameters/bodyoptionality/_vendor.py b/packages/typespec-python/test/azure/generated/parameters-body-optionality/parameters/bodyoptionality/_vendor.py deleted file mode 100644 index b3061844306..00000000000 --- a/packages/typespec-python/test/azure/generated/parameters-body-optionality/parameters/bodyoptionality/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) Python Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import BodyOptionalityClientConfiguration - -if TYPE_CHECKING: - from azure.core import PipelineClient - - from ._serialization import Deserializer, Serializer - - -class BodyOptionalityClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "PipelineClient" - _config: BodyOptionalityClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/azure/generated/parameters-body-optionality/parameters/bodyoptionality/aio/_client.py b/packages/typespec-python/test/azure/generated/parameters-body-optionality/parameters/bodyoptionality/aio/_client.py index 3c74e806da3..1d0e19cd535 100644 --- a/packages/typespec-python/test/azure/generated/parameters-body-optionality/parameters/bodyoptionality/aio/_client.py +++ b/packages/typespec-python/test/azure/generated/parameters-body-optionality/parameters/bodyoptionality/aio/_client.py @@ -14,7 +14,7 @@ from azure.core.pipeline import policies from azure.core.rest import AsyncHttpResponse, HttpRequest -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ..optionalexplicit.aio.operations import OptionalExplicitOperations from ._configuration import BodyOptionalityClientConfiguration from ._operations import BodyOptionalityClientOperationsMixin diff --git a/packages/typespec-python/test/azure/generated/parameters-body-optionality/parameters/bodyoptionality/aio/_operations/_operations.py b/packages/typespec-python/test/azure/generated/parameters-body-optionality/parameters/bodyoptionality/aio/_operations/_operations.py index 65a59befe56..885c82c1edf 100644 --- a/packages/typespec-python/test/azure/generated/parameters-body-optionality/parameters/bodyoptionality/aio/_operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/parameters-body-optionality/parameters/bodyoptionality/aio/_operations/_operations.py @@ -11,6 +11,7 @@ import json from typing import Any, Callable, Dict, IO, Optional, TypeVar, Union, overload +from azure.core import AsyncPipelineClient from azure.core.exceptions import ( ClientAuthenticationError, HttpResponseError, @@ -25,12 +26,13 @@ from azure.core.utils import case_insensitive_dict from ... import models as _models2 -from ..._model_base import SdkJSONEncoder from ..._operations._operations import ( build_body_optionality_required_explicit_request, build_body_optionality_required_implicit_request, ) -from .._vendor import BodyOptionalityClientMixinABC +from ..._utils.model_base import SdkJSONEncoder +from ..._utils.utils import ClientMixinABC +from .._configuration import BodyOptionalityClientConfiguration JSON = MutableMapping[str, Any] _Unset: Any = object() @@ -38,7 +40,7 @@ ClsType = Optional[Callable[[PipelineResponse[HttpRequest, AsyncHttpResponse], T, Dict[str, Any]], Any]] -class BodyOptionalityClientOperationsMixin(BodyOptionalityClientMixinABC): +class BodyOptionalityClientOperationsMixin(ClientMixinABC[AsyncPipelineClient, BodyOptionalityClientConfiguration]): @overload async def required_explicit( diff --git a/packages/typespec-python/test/azure/generated/parameters-body-optionality/parameters/bodyoptionality/aio/_vendor.py b/packages/typespec-python/test/azure/generated/parameters-body-optionality/parameters/bodyoptionality/aio/_vendor.py deleted file mode 100644 index 7ed4ad1471a..00000000000 --- a/packages/typespec-python/test/azure/generated/parameters-body-optionality/parameters/bodyoptionality/aio/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) Python Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import BodyOptionalityClientConfiguration - -if TYPE_CHECKING: - from azure.core import AsyncPipelineClient - - from .._serialization import Deserializer, Serializer - - -class BodyOptionalityClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "AsyncPipelineClient" - _config: BodyOptionalityClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/azure/generated/parameters-body-optionality/parameters/bodyoptionality/models/_models.py b/packages/typespec-python/test/azure/generated/parameters-body-optionality/parameters/bodyoptionality/models/_models.py index 40935f73403..fbe3885f0f1 100644 --- a/packages/typespec-python/test/azure/generated/parameters-body-optionality/parameters/bodyoptionality/models/_models.py +++ b/packages/typespec-python/test/azure/generated/parameters-body-optionality/parameters/bodyoptionality/models/_models.py @@ -9,11 +9,10 @@ from typing import Any, Mapping, overload -from .. import _model_base -from .._model_base import rest_field +from .._utils.model_base import Model as _Model, rest_field -class BodyModel(_model_base.Model): +class BodyModel(_Model): """BodyModel. :ivar name: Required. diff --git a/packages/typespec-python/test/azure/generated/parameters-body-optionality/parameters/bodyoptionality/optionalexplicit/aio/operations/_operations.py b/packages/typespec-python/test/azure/generated/parameters-body-optionality/parameters/bodyoptionality/optionalexplicit/aio/operations/_operations.py index d9a55059a8d..975d83a41c9 100644 --- a/packages/typespec-python/test/azure/generated/parameters-body-optionality/parameters/bodyoptionality/optionalexplicit/aio/operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/parameters-body-optionality/parameters/bodyoptionality/optionalexplicit/aio/operations/_operations.py @@ -25,8 +25,8 @@ from azure.core.utils import case_insensitive_dict from .... import models as _models3 -from ...._model_base import SdkJSONEncoder -from ...._serialization import Deserializer, Serializer +from ...._utils.model_base import SdkJSONEncoder +from ...._utils.serialization import Deserializer, Serializer from ....aio._configuration import BodyOptionalityClientConfiguration from ...operations._operations import build_optional_explicit_omit_request, build_optional_explicit_set_request diff --git a/packages/typespec-python/test/azure/generated/parameters-body-optionality/parameters/bodyoptionality/optionalexplicit/operations/_operations.py b/packages/typespec-python/test/azure/generated/parameters-body-optionality/parameters/bodyoptionality/optionalexplicit/operations/_operations.py index f136321cd91..72c756c5c23 100644 --- a/packages/typespec-python/test/azure/generated/parameters-body-optionality/parameters/bodyoptionality/optionalexplicit/operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/parameters-body-optionality/parameters/bodyoptionality/optionalexplicit/operations/_operations.py @@ -26,8 +26,8 @@ from ... import models as _models2 from ..._configuration import BodyOptionalityClientConfiguration -from ..._model_base import SdkJSONEncoder -from ..._serialization import Deserializer, Serializer +from ..._utils.model_base import SdkJSONEncoder +from ..._utils.serialization import Deserializer, Serializer JSON = MutableMapping[str, Any] T = TypeVar("T") diff --git a/packages/typespec-python/test/azure/generated/parameters-collection-format/parameters/collectionformat/_client.py b/packages/typespec-python/test/azure/generated/parameters-collection-format/parameters/collectionformat/_client.py index af16dca5cdc..bd0638069da 100644 --- a/packages/typespec-python/test/azure/generated/parameters-collection-format/parameters/collectionformat/_client.py +++ b/packages/typespec-python/test/azure/generated/parameters-collection-format/parameters/collectionformat/_client.py @@ -15,7 +15,7 @@ from azure.core.rest import HttpRequest, HttpResponse from ._configuration import CollectionFormatClientConfiguration -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer from .header.operations import HeaderOperations from .query.operations import QueryOperations diff --git a/packages/typespec-python/test/azure/generated/parameters-collection-format/parameters/collectionformat/_utils/__init__.py b/packages/typespec-python/test/azure/generated/parameters-collection-format/parameters/collectionformat/_utils/__init__.py new file mode 100644 index 00000000000..8026245c2ab --- /dev/null +++ b/packages/typespec-python/test/azure/generated/parameters-collection-format/parameters/collectionformat/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) Python Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/typespec-python/test/azure/generated/parameters-path/parameters/path/_model_base.py b/packages/typespec-python/test/azure/generated/parameters-collection-format/parameters/collectionformat/_utils/model_base.py similarity index 100% rename from packages/typespec-python/test/azure/generated/parameters-path/parameters/path/_model_base.py rename to packages/typespec-python/test/azure/generated/parameters-collection-format/parameters/collectionformat/_utils/model_base.py diff --git a/packages/typespec-python/test/azure/generated/parameters-path/parameters/path/_serialization.py b/packages/typespec-python/test/azure/generated/parameters-collection-format/parameters/collectionformat/_utils/serialization.py similarity index 100% rename from packages/typespec-python/test/azure/generated/parameters-path/parameters/path/_serialization.py rename to packages/typespec-python/test/azure/generated/parameters-collection-format/parameters/collectionformat/_utils/serialization.py diff --git a/packages/typespec-python/test/azure/generated/parameters-collection-format/parameters/collectionformat/aio/_client.py b/packages/typespec-python/test/azure/generated/parameters-collection-format/parameters/collectionformat/aio/_client.py index 21109ae0f96..bb984ca39ed 100644 --- a/packages/typespec-python/test/azure/generated/parameters-collection-format/parameters/collectionformat/aio/_client.py +++ b/packages/typespec-python/test/azure/generated/parameters-collection-format/parameters/collectionformat/aio/_client.py @@ -14,7 +14,7 @@ from azure.core.pipeline import policies from azure.core.rest import AsyncHttpResponse, HttpRequest -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ..header.aio.operations import HeaderOperations from ..query.aio.operations import QueryOperations from ._configuration import CollectionFormatClientConfiguration diff --git a/packages/typespec-python/test/azure/generated/parameters-collection-format/parameters/collectionformat/header/aio/operations/_operations.py b/packages/typespec-python/test/azure/generated/parameters-collection-format/parameters/collectionformat/header/aio/operations/_operations.py index 911251690b3..e907b230781 100644 --- a/packages/typespec-python/test/azure/generated/parameters-collection-format/parameters/collectionformat/header/aio/operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/parameters-collection-format/parameters/collectionformat/header/aio/operations/_operations.py @@ -21,7 +21,7 @@ from azure.core.rest import AsyncHttpResponse, HttpRequest from azure.core.tracing.decorator_async import distributed_trace_async -from ...._serialization import Deserializer, Serializer +from ...._utils.serialization import Deserializer, Serializer from ....aio._configuration import CollectionFormatClientConfiguration from ...operations._operations import build_header_csv_request diff --git a/packages/typespec-python/test/azure/generated/parameters-collection-format/parameters/collectionformat/header/operations/_operations.py b/packages/typespec-python/test/azure/generated/parameters-collection-format/parameters/collectionformat/header/operations/_operations.py index eafbcde9eff..d5aff748db4 100644 --- a/packages/typespec-python/test/azure/generated/parameters-collection-format/parameters/collectionformat/header/operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/parameters-collection-format/parameters/collectionformat/header/operations/_operations.py @@ -23,7 +23,7 @@ from azure.core.utils import case_insensitive_dict from ..._configuration import CollectionFormatClientConfiguration -from ..._serialization import Deserializer, Serializer +from ..._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/typespec-python/test/azure/generated/parameters-collection-format/parameters/collectionformat/query/aio/operations/_operations.py b/packages/typespec-python/test/azure/generated/parameters-collection-format/parameters/collectionformat/query/aio/operations/_operations.py index 59b0086decb..4a14ab145fb 100644 --- a/packages/typespec-python/test/azure/generated/parameters-collection-format/parameters/collectionformat/query/aio/operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/parameters-collection-format/parameters/collectionformat/query/aio/operations/_operations.py @@ -21,7 +21,7 @@ from azure.core.rest import AsyncHttpResponse, HttpRequest from azure.core.tracing.decorator_async import distributed_trace_async -from ...._serialization import Deserializer, Serializer +from ...._utils.serialization import Deserializer, Serializer from ....aio._configuration import CollectionFormatClientConfiguration from ...operations._operations import ( build_query_csv_request, diff --git a/packages/typespec-python/test/azure/generated/parameters-collection-format/parameters/collectionformat/query/operations/_operations.py b/packages/typespec-python/test/azure/generated/parameters-collection-format/parameters/collectionformat/query/operations/_operations.py index af9680823ea..c17222bc7bd 100644 --- a/packages/typespec-python/test/azure/generated/parameters-collection-format/parameters/collectionformat/query/operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/parameters-collection-format/parameters/collectionformat/query/operations/_operations.py @@ -23,7 +23,7 @@ from azure.core.utils import case_insensitive_dict from ..._configuration import CollectionFormatClientConfiguration -from ..._serialization import Deserializer, Serializer +from ..._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/typespec-python/test/azure/generated/parameters-path/parameters/path/_client.py b/packages/typespec-python/test/azure/generated/parameters-path/parameters/path/_client.py index 62eaef2b044..805f7323996 100644 --- a/packages/typespec-python/test/azure/generated/parameters-path/parameters/path/_client.py +++ b/packages/typespec-python/test/azure/generated/parameters-path/parameters/path/_client.py @@ -16,7 +16,7 @@ from ._configuration import PathClientConfiguration from ._operations import PathClientOperationsMixin -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer class PathClient(PathClientOperationsMixin): # pylint: disable=client-accepts-api-version-keyword diff --git a/packages/typespec-python/test/azure/generated/parameters-path/parameters/path/_operations/_operations.py b/packages/typespec-python/test/azure/generated/parameters-path/parameters/path/_operations/_operations.py index 58695fec477..1490c088520 100644 --- a/packages/typespec-python/test/azure/generated/parameters-path/parameters/path/_operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/parameters-path/parameters/path/_operations/_operations.py @@ -8,6 +8,7 @@ from collections.abc import MutableMapping from typing import Any, Callable, Dict, Optional, TypeVar +from azure.core import PipelineClient from azure.core.exceptions import ( ClientAuthenticationError, HttpResponseError, @@ -20,8 +21,9 @@ from azure.core.rest import HttpRequest, HttpResponse from azure.core.tracing.decorator import distributed_trace -from .._serialization import Serializer -from .._vendor import PathClientMixinABC +from .._configuration import PathClientConfiguration +from .._utils.serialization import Serializer +from .._utils.utils import ClientMixinABC T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] @@ -54,7 +56,7 @@ def build_path_optional_request(*, name: Optional[str] = None, **kwargs: Any) -> return HttpRequest(method="GET", url=_url, **kwargs) -class PathClientOperationsMixin(PathClientMixinABC): +class PathClientOperationsMixin(ClientMixinABC[PipelineClient, PathClientConfiguration]): @distributed_trace def normal(self, name: str, **kwargs: Any) -> None: # pylint: disable=inconsistent-return-statements diff --git a/packages/typespec-python/test/azure/generated/parameters-path/parameters/path/_utils/__init__.py b/packages/typespec-python/test/azure/generated/parameters-path/parameters/path/_utils/__init__.py new file mode 100644 index 00000000000..8026245c2ab --- /dev/null +++ b/packages/typespec-python/test/azure/generated/parameters-path/parameters/path/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) Python Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/typespec-python/test/azure/generated/parameters-spread/parameters/spread/_model_base.py b/packages/typespec-python/test/azure/generated/parameters-path/parameters/path/_utils/model_base.py similarity index 100% rename from packages/typespec-python/test/azure/generated/parameters-spread/parameters/spread/_model_base.py rename to packages/typespec-python/test/azure/generated/parameters-path/parameters/path/_utils/model_base.py diff --git a/packages/typespec-python/test/azure/generated/parameters-spread/parameters/spread/_serialization.py b/packages/typespec-python/test/azure/generated/parameters-path/parameters/path/_utils/serialization.py similarity index 100% rename from packages/typespec-python/test/azure/generated/parameters-spread/parameters/spread/_serialization.py rename to packages/typespec-python/test/azure/generated/parameters-path/parameters/path/_utils/serialization.py diff --git a/packages/typespec-python/test/azure/generated/parameters-path/parameters/path/_utils/utils.py b/packages/typespec-python/test/azure/generated/parameters-path/parameters/path/_utils/utils.py new file mode 100644 index 00000000000..35c9c836f85 --- /dev/null +++ b/packages/typespec-python/test/azure/generated/parameters-path/parameters/path/_utils/utils.py @@ -0,0 +1,25 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) Python Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from abc import ABC +from typing import Generic, TYPE_CHECKING, TypeVar + +if TYPE_CHECKING: + from .serialization import Deserializer, Serializer + + +TClient = TypeVar("TClient") +TConfig = TypeVar("TConfig") + + +class ClientMixinABC(ABC, Generic[TClient, TConfig]): + """DO NOT use this class. It is for internal typing use only.""" + + _client: TClient + _config: TConfig + _serialize: "Serializer" + _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/azure/generated/parameters-path/parameters/path/_vendor.py b/packages/typespec-python/test/azure/generated/parameters-path/parameters/path/_vendor.py deleted file mode 100644 index 745b900e6f6..00000000000 --- a/packages/typespec-python/test/azure/generated/parameters-path/parameters/path/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) Python Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import PathClientConfiguration - -if TYPE_CHECKING: - from azure.core import PipelineClient - - from ._serialization import Deserializer, Serializer - - -class PathClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "PipelineClient" - _config: PathClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/azure/generated/parameters-path/parameters/path/aio/_client.py b/packages/typespec-python/test/azure/generated/parameters-path/parameters/path/aio/_client.py index a98956660c2..b77489e29ea 100644 --- a/packages/typespec-python/test/azure/generated/parameters-path/parameters/path/aio/_client.py +++ b/packages/typespec-python/test/azure/generated/parameters-path/parameters/path/aio/_client.py @@ -14,7 +14,7 @@ from azure.core.pipeline import policies from azure.core.rest import AsyncHttpResponse, HttpRequest -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import PathClientConfiguration from ._operations import PathClientOperationsMixin diff --git a/packages/typespec-python/test/azure/generated/parameters-path/parameters/path/aio/_operations/_operations.py b/packages/typespec-python/test/azure/generated/parameters-path/parameters/path/aio/_operations/_operations.py index bc5a0e58677..15de169e701 100644 --- a/packages/typespec-python/test/azure/generated/parameters-path/parameters/path/aio/_operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/parameters-path/parameters/path/aio/_operations/_operations.py @@ -9,6 +9,7 @@ from collections.abc import MutableMapping from typing import Any, Callable, Dict, Optional, TypeVar +from azure.core import AsyncPipelineClient from azure.core.exceptions import ( ClientAuthenticationError, HttpResponseError, @@ -22,13 +23,14 @@ from azure.core.tracing.decorator_async import distributed_trace_async from ..._operations._operations import build_path_normal_request, build_path_optional_request -from .._vendor import PathClientMixinABC +from ..._utils.utils import ClientMixinABC +from .._configuration import PathClientConfiguration T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, AsyncHttpResponse], T, Dict[str, Any]], Any]] -class PathClientOperationsMixin(PathClientMixinABC): +class PathClientOperationsMixin(ClientMixinABC[AsyncPipelineClient, PathClientConfiguration]): @distributed_trace_async async def normal(self, name: str, **kwargs: Any) -> None: diff --git a/packages/typespec-python/test/azure/generated/parameters-path/parameters/path/aio/_vendor.py b/packages/typespec-python/test/azure/generated/parameters-path/parameters/path/aio/_vendor.py deleted file mode 100644 index 1373fa6986b..00000000000 --- a/packages/typespec-python/test/azure/generated/parameters-path/parameters/path/aio/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) Python Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import PathClientConfiguration - -if TYPE_CHECKING: - from azure.core import AsyncPipelineClient - - from .._serialization import Deserializer, Serializer - - -class PathClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "AsyncPipelineClient" - _config: PathClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/azure/generated/parameters-spread/parameters/spread/_client.py b/packages/typespec-python/test/azure/generated/parameters-spread/parameters/spread/_client.py index d622deba213..e33cf068f4b 100644 --- a/packages/typespec-python/test/azure/generated/parameters-spread/parameters/spread/_client.py +++ b/packages/typespec-python/test/azure/generated/parameters-spread/parameters/spread/_client.py @@ -15,7 +15,7 @@ from azure.core.rest import HttpRequest, HttpResponse from ._configuration import SpreadClientConfiguration -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer from .operations import AliasOperations, ModelOperations diff --git a/packages/typespec-python/test/azure/generated/parameters-spread/parameters/spread/_utils/__init__.py b/packages/typespec-python/test/azure/generated/parameters-spread/parameters/spread/_utils/__init__.py new file mode 100644 index 00000000000..8026245c2ab --- /dev/null +++ b/packages/typespec-python/test/azure/generated/parameters-spread/parameters/spread/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) Python Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/typespec-python/test/azure/generated/payload-content-negotiation/payload/contentnegotiation/_model_base.py b/packages/typespec-python/test/azure/generated/parameters-spread/parameters/spread/_utils/model_base.py similarity index 100% rename from packages/typespec-python/test/azure/generated/payload-content-negotiation/payload/contentnegotiation/_model_base.py rename to packages/typespec-python/test/azure/generated/parameters-spread/parameters/spread/_utils/model_base.py diff --git a/packages/typespec-python/test/azure/generated/payload-content-negotiation/payload/contentnegotiation/_serialization.py b/packages/typespec-python/test/azure/generated/parameters-spread/parameters/spread/_utils/serialization.py similarity index 100% rename from packages/typespec-python/test/azure/generated/payload-content-negotiation/payload/contentnegotiation/_serialization.py rename to packages/typespec-python/test/azure/generated/parameters-spread/parameters/spread/_utils/serialization.py diff --git a/packages/typespec-python/test/azure/generated/parameters-spread/parameters/spread/aio/_client.py b/packages/typespec-python/test/azure/generated/parameters-spread/parameters/spread/aio/_client.py index 9622d760a3e..1fe65ba2639 100644 --- a/packages/typespec-python/test/azure/generated/parameters-spread/parameters/spread/aio/_client.py +++ b/packages/typespec-python/test/azure/generated/parameters-spread/parameters/spread/aio/_client.py @@ -14,7 +14,7 @@ from azure.core.pipeline import policies from azure.core.rest import AsyncHttpResponse, HttpRequest -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import SpreadClientConfiguration from .operations import AliasOperations, ModelOperations diff --git a/packages/typespec-python/test/azure/generated/parameters-spread/parameters/spread/aio/operations/_operations.py b/packages/typespec-python/test/azure/generated/parameters-spread/parameters/spread/aio/operations/_operations.py index 1a0ca24972a..0a687e5efe2 100644 --- a/packages/typespec-python/test/azure/generated/parameters-spread/parameters/spread/aio/operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/parameters-spread/parameters/spread/aio/operations/_operations.py @@ -26,8 +26,8 @@ from azure.core.utils import case_insensitive_dict from ... import models as _models -from ..._model_base import SdkJSONEncoder -from ..._serialization import Deserializer, Serializer +from ..._utils.model_base import SdkJSONEncoder +from ..._utils.serialization import Deserializer, Serializer from ...operations._operations import ( build_alias_spread_as_request_body_request, build_alias_spread_as_request_parameter_request, diff --git a/packages/typespec-python/test/azure/generated/parameters-spread/parameters/spread/models/_models.py b/packages/typespec-python/test/azure/generated/parameters-spread/parameters/spread/models/_models.py index bce4236681e..8a50b6f095b 100644 --- a/packages/typespec-python/test/azure/generated/parameters-spread/parameters/spread/models/_models.py +++ b/packages/typespec-python/test/azure/generated/parameters-spread/parameters/spread/models/_models.py @@ -9,11 +9,10 @@ from typing import Any, Mapping, overload -from .. import _model_base -from .._model_base import rest_field +from .._utils.model_base import Model as _Model, rest_field -class BodyParameter(_model_base.Model): +class BodyParameter(_Model): """This is a simple model. :ivar name: Required. diff --git a/packages/typespec-python/test/azure/generated/parameters-spread/parameters/spread/operations/_operations.py b/packages/typespec-python/test/azure/generated/parameters-spread/parameters/spread/operations/_operations.py index 58d43ad4316..2a11a3da471 100644 --- a/packages/typespec-python/test/azure/generated/parameters-spread/parameters/spread/operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/parameters-spread/parameters/spread/operations/_operations.py @@ -27,8 +27,8 @@ from .. import models as _models from .._configuration import SpreadClientConfiguration -from .._model_base import SdkJSONEncoder -from .._serialization import Deserializer, Serializer +from .._utils.model_base import SdkJSONEncoder +from .._utils.serialization import Deserializer, Serializer JSON = MutableMapping[str, Any] _Unset: Any = object() diff --git a/packages/typespec-python/test/azure/generated/payload-content-negotiation/payload/contentnegotiation/_client.py b/packages/typespec-python/test/azure/generated/payload-content-negotiation/payload/contentnegotiation/_client.py index f67ef0f3814..7065690fe7a 100644 --- a/packages/typespec-python/test/azure/generated/payload-content-negotiation/payload/contentnegotiation/_client.py +++ b/packages/typespec-python/test/azure/generated/payload-content-negotiation/payload/contentnegotiation/_client.py @@ -15,7 +15,7 @@ from azure.core.rest import HttpRequest, HttpResponse from ._configuration import ContentNegotiationClientConfiguration -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer from .operations import DifferentBodyOperations, SameBodyOperations diff --git a/packages/typespec-python/test/azure/generated/payload-content-negotiation/payload/contentnegotiation/_utils/__init__.py b/packages/typespec-python/test/azure/generated/payload-content-negotiation/payload/contentnegotiation/_utils/__init__.py new file mode 100644 index 00000000000..8026245c2ab --- /dev/null +++ b/packages/typespec-python/test/azure/generated/payload-content-negotiation/payload/contentnegotiation/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) Python Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/typespec-python/test/azure/generated/payload-json-merge-patch/payload/jsonmergepatch/_model_base.py b/packages/typespec-python/test/azure/generated/payload-content-negotiation/payload/contentnegotiation/_utils/model_base.py similarity index 100% rename from packages/typespec-python/test/azure/generated/payload-json-merge-patch/payload/jsonmergepatch/_model_base.py rename to packages/typespec-python/test/azure/generated/payload-content-negotiation/payload/contentnegotiation/_utils/model_base.py diff --git a/packages/typespec-python/test/azure/generated/payload-json-merge-patch/payload/jsonmergepatch/_serialization.py b/packages/typespec-python/test/azure/generated/payload-content-negotiation/payload/contentnegotiation/_utils/serialization.py similarity index 100% rename from packages/typespec-python/test/azure/generated/payload-json-merge-patch/payload/jsonmergepatch/_serialization.py rename to packages/typespec-python/test/azure/generated/payload-content-negotiation/payload/contentnegotiation/_utils/serialization.py diff --git a/packages/typespec-python/test/azure/generated/payload-content-negotiation/payload/contentnegotiation/aio/_client.py b/packages/typespec-python/test/azure/generated/payload-content-negotiation/payload/contentnegotiation/aio/_client.py index 7eaa63d93df..5880c31f1ab 100644 --- a/packages/typespec-python/test/azure/generated/payload-content-negotiation/payload/contentnegotiation/aio/_client.py +++ b/packages/typespec-python/test/azure/generated/payload-content-negotiation/payload/contentnegotiation/aio/_client.py @@ -14,7 +14,7 @@ from azure.core.pipeline import policies from azure.core.rest import AsyncHttpResponse, HttpRequest -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import ContentNegotiationClientConfiguration from .operations import DifferentBodyOperations, SameBodyOperations diff --git a/packages/typespec-python/test/azure/generated/payload-content-negotiation/payload/contentnegotiation/aio/operations/_operations.py b/packages/typespec-python/test/azure/generated/payload-content-negotiation/payload/contentnegotiation/aio/operations/_operations.py index 58551e9f2f9..56c23d1b46a 100644 --- a/packages/typespec-python/test/azure/generated/payload-content-negotiation/payload/contentnegotiation/aio/operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/payload-content-negotiation/payload/contentnegotiation/aio/operations/_operations.py @@ -25,8 +25,8 @@ from azure.core.utils import case_insensitive_dict from ... import models as _models -from ..._model_base import _deserialize -from ..._serialization import Deserializer, Serializer +from ..._utils.model_base import _deserialize +from ..._utils.serialization import Deserializer, Serializer from ...operations._operations import ( build_different_body_get_avatar_as_json_request, build_different_body_get_avatar_as_png_request, diff --git a/packages/typespec-python/test/azure/generated/payload-content-negotiation/payload/contentnegotiation/models/_models.py b/packages/typespec-python/test/azure/generated/payload-content-negotiation/payload/contentnegotiation/models/_models.py index 872fb18c037..df3d23f1039 100644 --- a/packages/typespec-python/test/azure/generated/payload-content-negotiation/payload/contentnegotiation/models/_models.py +++ b/packages/typespec-python/test/azure/generated/payload-content-negotiation/payload/contentnegotiation/models/_models.py @@ -9,11 +9,10 @@ from typing import Any, Mapping, overload -from .. import _model_base -from .._model_base import rest_field +from .._utils.model_base import Model as _Model, rest_field -class PngImageAsJson(_model_base.Model): +class PngImageAsJson(_Model): """PngImageAsJson. :ivar content: Required. diff --git a/packages/typespec-python/test/azure/generated/payload-content-negotiation/payload/contentnegotiation/operations/_operations.py b/packages/typespec-python/test/azure/generated/payload-content-negotiation/payload/contentnegotiation/operations/_operations.py index 9b13d910dbc..5f1805f22e8 100644 --- a/packages/typespec-python/test/azure/generated/payload-content-negotiation/payload/contentnegotiation/operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/payload-content-negotiation/payload/contentnegotiation/operations/_operations.py @@ -26,8 +26,8 @@ from .. import models as _models from .._configuration import ContentNegotiationClientConfiguration -from .._model_base import _deserialize -from .._serialization import Deserializer, Serializer +from .._utils.model_base import _deserialize +from .._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/typespec-python/test/azure/generated/payload-json-merge-patch/payload/jsonmergepatch/_client.py b/packages/typespec-python/test/azure/generated/payload-json-merge-patch/payload/jsonmergepatch/_client.py index 44e599af5e3..c21b7332509 100644 --- a/packages/typespec-python/test/azure/generated/payload-json-merge-patch/payload/jsonmergepatch/_client.py +++ b/packages/typespec-python/test/azure/generated/payload-json-merge-patch/payload/jsonmergepatch/_client.py @@ -16,7 +16,7 @@ from ._configuration import JsonMergePatchClientConfiguration from ._operations import JsonMergePatchClientOperationsMixin -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer class JsonMergePatchClient(JsonMergePatchClientOperationsMixin): # pylint: disable=client-accepts-api-version-keyword diff --git a/packages/typespec-python/test/azure/generated/payload-json-merge-patch/payload/jsonmergepatch/_operations/_operations.py b/packages/typespec-python/test/azure/generated/payload-json-merge-patch/payload/jsonmergepatch/_operations/_operations.py index cee2d373bfa..bb598649c5d 100644 --- a/packages/typespec-python/test/azure/generated/payload-json-merge-patch/payload/jsonmergepatch/_operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/payload-json-merge-patch/payload/jsonmergepatch/_operations/_operations.py @@ -10,6 +10,7 @@ import json from typing import Any, Callable, Dict, IO, Optional, TypeVar, Union, overload +from azure.core import PipelineClient from azure.core.exceptions import ( ClientAuthenticationError, HttpResponseError, @@ -26,9 +27,10 @@ from azure.core.utils import case_insensitive_dict from .. import models as _models -from .._model_base import SdkJSONEncoder, _deserialize -from .._serialization import Serializer -from .._vendor import JsonMergePatchClientMixinABC +from .._configuration import JsonMergePatchClientConfiguration +from .._utils.model_base import SdkJSONEncoder, _deserialize +from .._utils.serialization import Serializer +from .._utils.utils import ClientMixinABC JSON = MutableMapping[str, Any] T = TypeVar("T") @@ -91,7 +93,7 @@ def build_json_merge_patch_update_optional_resource_request( # pylint: disable= return HttpRequest(method="PATCH", url=_url, headers=_headers, **kwargs) -class JsonMergePatchClientOperationsMixin(JsonMergePatchClientMixinABC): +class JsonMergePatchClientOperationsMixin(ClientMixinABC[PipelineClient, JsonMergePatchClientConfiguration]): @overload def create_resource( diff --git a/packages/typespec-python/test/azure/generated/payload-json-merge-patch/payload/jsonmergepatch/_utils/__init__.py b/packages/typespec-python/test/azure/generated/payload-json-merge-patch/payload/jsonmergepatch/_utils/__init__.py new file mode 100644 index 00000000000..8026245c2ab --- /dev/null +++ b/packages/typespec-python/test/azure/generated/payload-json-merge-patch/payload/jsonmergepatch/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) Python Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/typespec-python/test/azure/generated/payload-media-type/payload/mediatype/_model_base.py b/packages/typespec-python/test/azure/generated/payload-json-merge-patch/payload/jsonmergepatch/_utils/model_base.py similarity index 100% rename from packages/typespec-python/test/azure/generated/payload-media-type/payload/mediatype/_model_base.py rename to packages/typespec-python/test/azure/generated/payload-json-merge-patch/payload/jsonmergepatch/_utils/model_base.py diff --git a/packages/typespec-python/test/azure/generated/payload-media-type/payload/mediatype/_serialization.py b/packages/typespec-python/test/azure/generated/payload-json-merge-patch/payload/jsonmergepatch/_utils/serialization.py similarity index 100% rename from packages/typespec-python/test/azure/generated/payload-media-type/payload/mediatype/_serialization.py rename to packages/typespec-python/test/azure/generated/payload-json-merge-patch/payload/jsonmergepatch/_utils/serialization.py diff --git a/packages/typespec-python/test/azure/generated/payload-json-merge-patch/payload/jsonmergepatch/_utils/utils.py b/packages/typespec-python/test/azure/generated/payload-json-merge-patch/payload/jsonmergepatch/_utils/utils.py new file mode 100644 index 00000000000..35c9c836f85 --- /dev/null +++ b/packages/typespec-python/test/azure/generated/payload-json-merge-patch/payload/jsonmergepatch/_utils/utils.py @@ -0,0 +1,25 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) Python Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from abc import ABC +from typing import Generic, TYPE_CHECKING, TypeVar + +if TYPE_CHECKING: + from .serialization import Deserializer, Serializer + + +TClient = TypeVar("TClient") +TConfig = TypeVar("TConfig") + + +class ClientMixinABC(ABC, Generic[TClient, TConfig]): + """DO NOT use this class. It is for internal typing use only.""" + + _client: TClient + _config: TConfig + _serialize: "Serializer" + _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/azure/generated/payload-json-merge-patch/payload/jsonmergepatch/_vendor.py b/packages/typespec-python/test/azure/generated/payload-json-merge-patch/payload/jsonmergepatch/_vendor.py deleted file mode 100644 index fe248e82828..00000000000 --- a/packages/typespec-python/test/azure/generated/payload-json-merge-patch/payload/jsonmergepatch/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) Python Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import JsonMergePatchClientConfiguration - -if TYPE_CHECKING: - from azure.core import PipelineClient - - from ._serialization import Deserializer, Serializer - - -class JsonMergePatchClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "PipelineClient" - _config: JsonMergePatchClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/azure/generated/payload-json-merge-patch/payload/jsonmergepatch/aio/_client.py b/packages/typespec-python/test/azure/generated/payload-json-merge-patch/payload/jsonmergepatch/aio/_client.py index 5c337e4eb42..af591930437 100644 --- a/packages/typespec-python/test/azure/generated/payload-json-merge-patch/payload/jsonmergepatch/aio/_client.py +++ b/packages/typespec-python/test/azure/generated/payload-json-merge-patch/payload/jsonmergepatch/aio/_client.py @@ -14,7 +14,7 @@ from azure.core.pipeline import policies from azure.core.rest import AsyncHttpResponse, HttpRequest -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import JsonMergePatchClientConfiguration from ._operations import JsonMergePatchClientOperationsMixin diff --git a/packages/typespec-python/test/azure/generated/payload-json-merge-patch/payload/jsonmergepatch/aio/_operations/_operations.py b/packages/typespec-python/test/azure/generated/payload-json-merge-patch/payload/jsonmergepatch/aio/_operations/_operations.py index 7b30e917b8e..88a01ca22fc 100644 --- a/packages/typespec-python/test/azure/generated/payload-json-merge-patch/payload/jsonmergepatch/aio/_operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/payload-json-merge-patch/payload/jsonmergepatch/aio/_operations/_operations.py @@ -11,6 +11,7 @@ import json from typing import Any, Callable, Dict, IO, Optional, TypeVar, Union, overload +from azure.core import AsyncPipelineClient from azure.core.exceptions import ( ClientAuthenticationError, HttpResponseError, @@ -27,20 +28,21 @@ from azure.core.utils import case_insensitive_dict from ... import models as _models -from ..._model_base import SdkJSONEncoder, _deserialize from ..._operations._operations import ( build_json_merge_patch_create_resource_request, build_json_merge_patch_update_optional_resource_request, build_json_merge_patch_update_resource_request, ) -from .._vendor import JsonMergePatchClientMixinABC +from ..._utils.model_base import SdkJSONEncoder, _deserialize +from ..._utils.utils import ClientMixinABC +from .._configuration import JsonMergePatchClientConfiguration JSON = MutableMapping[str, Any] T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, AsyncHttpResponse], T, Dict[str, Any]], Any]] -class JsonMergePatchClientOperationsMixin(JsonMergePatchClientMixinABC): +class JsonMergePatchClientOperationsMixin(ClientMixinABC[AsyncPipelineClient, JsonMergePatchClientConfiguration]): @overload async def create_resource( diff --git a/packages/typespec-python/test/azure/generated/payload-json-merge-patch/payload/jsonmergepatch/aio/_vendor.py b/packages/typespec-python/test/azure/generated/payload-json-merge-patch/payload/jsonmergepatch/aio/_vendor.py deleted file mode 100644 index 48a6bf8b21a..00000000000 --- a/packages/typespec-python/test/azure/generated/payload-json-merge-patch/payload/jsonmergepatch/aio/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) Python Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import JsonMergePatchClientConfiguration - -if TYPE_CHECKING: - from azure.core import AsyncPipelineClient - - from .._serialization import Deserializer, Serializer - - -class JsonMergePatchClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "AsyncPipelineClient" - _config: JsonMergePatchClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/azure/generated/payload-json-merge-patch/payload/jsonmergepatch/models/_models.py b/packages/typespec-python/test/azure/generated/payload-json-merge-patch/payload/jsonmergepatch/models/_models.py index 6257fe5d464..11d83f5e8b4 100644 --- a/packages/typespec-python/test/azure/generated/payload-json-merge-patch/payload/jsonmergepatch/models/_models.py +++ b/packages/typespec-python/test/azure/generated/payload-json-merge-patch/payload/jsonmergepatch/models/_models.py @@ -9,14 +9,13 @@ from typing import Any, Dict, List, Mapping, Optional, TYPE_CHECKING, overload -from .. import _model_base -from .._model_base import rest_field +from .._utils.model_base import Model as _Model, rest_field if TYPE_CHECKING: from .. import models as _models -class InnerModel(_model_base.Model): +class InnerModel(_Model): """It is the model used by Resource model. :ivar name: @@ -47,7 +46,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class Resource(_model_base.Model): +class Resource(_Model): """Details about a resource. :ivar name: Required. @@ -111,7 +110,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class ResourcePatch(_model_base.Model): +class ResourcePatch(_Model): """Details about a resource for patch operation. :ivar description: diff --git a/packages/typespec-python/test/azure/generated/payload-media-type/payload/mediatype/_client.py b/packages/typespec-python/test/azure/generated/payload-media-type/payload/mediatype/_client.py index e556a75689b..9caa9feb5b6 100644 --- a/packages/typespec-python/test/azure/generated/payload-media-type/payload/mediatype/_client.py +++ b/packages/typespec-python/test/azure/generated/payload-media-type/payload/mediatype/_client.py @@ -15,7 +15,7 @@ from azure.core.rest import HttpRequest, HttpResponse from ._configuration import MediaTypeClientConfiguration -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer from .stringbody.operations import StringBodyOperations diff --git a/packages/typespec-python/test/azure/generated/payload-media-type/payload/mediatype/_utils/__init__.py b/packages/typespec-python/test/azure/generated/payload-media-type/payload/mediatype/_utils/__init__.py new file mode 100644 index 00000000000..8026245c2ab --- /dev/null +++ b/packages/typespec-python/test/azure/generated/payload-media-type/payload/mediatype/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) Python Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/typespec-python/test/azure/generated/payload-multipart/payload/multipart/_model_base.py b/packages/typespec-python/test/azure/generated/payload-media-type/payload/mediatype/_utils/model_base.py similarity index 100% rename from packages/typespec-python/test/azure/generated/payload-multipart/payload/multipart/_model_base.py rename to packages/typespec-python/test/azure/generated/payload-media-type/payload/mediatype/_utils/model_base.py diff --git a/packages/typespec-python/test/azure/generated/payload-multipart/payload/multipart/_serialization.py b/packages/typespec-python/test/azure/generated/payload-media-type/payload/mediatype/_utils/serialization.py similarity index 100% rename from packages/typespec-python/test/azure/generated/payload-multipart/payload/multipart/_serialization.py rename to packages/typespec-python/test/azure/generated/payload-media-type/payload/mediatype/_utils/serialization.py diff --git a/packages/typespec-python/test/azure/generated/payload-media-type/payload/mediatype/aio/_client.py b/packages/typespec-python/test/azure/generated/payload-media-type/payload/mediatype/aio/_client.py index 97be665dfb4..79c18ef8621 100644 --- a/packages/typespec-python/test/azure/generated/payload-media-type/payload/mediatype/aio/_client.py +++ b/packages/typespec-python/test/azure/generated/payload-media-type/payload/mediatype/aio/_client.py @@ -14,7 +14,7 @@ from azure.core.pipeline import policies from azure.core.rest import AsyncHttpResponse, HttpRequest -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ..stringbody.aio.operations import StringBodyOperations from ._configuration import MediaTypeClientConfiguration diff --git a/packages/typespec-python/test/azure/generated/payload-media-type/payload/mediatype/stringbody/aio/operations/_operations.py b/packages/typespec-python/test/azure/generated/payload-media-type/payload/mediatype/stringbody/aio/operations/_operations.py index f98eaa4c1b9..bf6e2f7acbf 100644 --- a/packages/typespec-python/test/azure/generated/payload-media-type/payload/mediatype/stringbody/aio/operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/payload-media-type/payload/mediatype/stringbody/aio/operations/_operations.py @@ -25,8 +25,8 @@ from azure.core.tracing.decorator_async import distributed_trace_async from azure.core.utils import case_insensitive_dict -from ...._model_base import SdkJSONEncoder, _deserialize -from ...._serialization import Deserializer, Serializer +from ...._utils.model_base import SdkJSONEncoder, _deserialize +from ...._utils.serialization import Deserializer, Serializer from ....aio._configuration import MediaTypeClientConfiguration from ...operations._operations import ( build_string_body_get_as_json_request, diff --git a/packages/typespec-python/test/azure/generated/payload-media-type/payload/mediatype/stringbody/operations/_operations.py b/packages/typespec-python/test/azure/generated/payload-media-type/payload/mediatype/stringbody/operations/_operations.py index 8e14fc649e4..0164a477a32 100644 --- a/packages/typespec-python/test/azure/generated/payload-media-type/payload/mediatype/stringbody/operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/payload-media-type/payload/mediatype/stringbody/operations/_operations.py @@ -26,8 +26,8 @@ from azure.core.utils import case_insensitive_dict from ..._configuration import MediaTypeClientConfiguration -from ..._model_base import SdkJSONEncoder, _deserialize -from ..._serialization import Deserializer, Serializer +from ..._utils.model_base import SdkJSONEncoder, _deserialize +from ..._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/typespec-python/test/azure/generated/payload-multipart/payload/multipart/_client.py b/packages/typespec-python/test/azure/generated/payload-multipart/payload/multipart/_client.py index 8bfeaccb7cf..96dedc4fa3e 100644 --- a/packages/typespec-python/test/azure/generated/payload-multipart/payload/multipart/_client.py +++ b/packages/typespec-python/test/azure/generated/payload-multipart/payload/multipart/_client.py @@ -15,7 +15,7 @@ from azure.core.rest import HttpRequest, HttpResponse from ._configuration import MultiPartClientConfiguration -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer from .operations import FormDataOperations diff --git a/packages/typespec-python/test/azure/generated/payload-multipart/payload/multipart/_utils/__init__.py b/packages/typespec-python/test/azure/generated/payload-multipart/payload/multipart/_utils/__init__.py new file mode 100644 index 00000000000..8026245c2ab --- /dev/null +++ b/packages/typespec-python/test/azure/generated/payload-multipart/payload/multipart/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) Python Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/typespec-python/test/azure/generated/payload-pageable/payload/pageable/_model_base.py b/packages/typespec-python/test/azure/generated/payload-multipart/payload/multipart/_utils/model_base.py similarity index 100% rename from packages/typespec-python/test/azure/generated/payload-pageable/payload/pageable/_model_base.py rename to packages/typespec-python/test/azure/generated/payload-multipart/payload/multipart/_utils/model_base.py diff --git a/packages/typespec-python/test/azure/generated/payload-pageable/payload/pageable/_serialization.py b/packages/typespec-python/test/azure/generated/payload-multipart/payload/multipart/_utils/serialization.py similarity index 100% rename from packages/typespec-python/test/azure/generated/payload-pageable/payload/pageable/_serialization.py rename to packages/typespec-python/test/azure/generated/payload-multipart/payload/multipart/_utils/serialization.py diff --git a/packages/typespec-python/test/azure/generated/payload-multipart/payload/multipart/_utils/utils.py b/packages/typespec-python/test/azure/generated/payload-multipart/payload/multipart/_utils/utils.py new file mode 100644 index 00000000000..34c2f1082c5 --- /dev/null +++ b/packages/typespec-python/test/azure/generated/payload-multipart/payload/multipart/_utils/utils.py @@ -0,0 +1,50 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) Python Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +import json +from typing import Any, Dict, IO, List, Mapping, Optional, Tuple, Union + +from .._utils.model_base import Model, SdkJSONEncoder + + +# file-like tuple could be `(filename, IO (or bytes))` or `(filename, IO (or bytes), content_type)` +FileContent = Union[str, bytes, IO[str], IO[bytes]] + +FileType = Union[ + # file (or bytes) + FileContent, + # (filename, file (or bytes)) + Tuple[Optional[str], FileContent], + # (filename, file (or bytes), content_type) + Tuple[Optional[str], FileContent, Optional[str]], +] + + +def serialize_multipart_data_entry(data_entry: Any) -> Any: + if isinstance(data_entry, (list, tuple, dict, Model)): + return json.dumps(data_entry, cls=SdkJSONEncoder, exclude_readonly=True) + return data_entry + + +def prepare_multipart_form_data( + body: Mapping[str, Any], multipart_fields: List[str], data_fields: List[str] +) -> Tuple[List[FileType], Dict[str, Any]]: + files: List[FileType] = [] + data: Dict[str, Any] = {} + for multipart_field in multipart_fields: + multipart_entry = body.get(multipart_field) + if isinstance(multipart_entry, list): + files.extend([(multipart_field, e) for e in multipart_entry]) + elif multipart_entry: + files.append((multipart_field, multipart_entry)) + + for data_field in data_fields: + data_entry = body.get(data_field) + if data_entry: + data[data_field] = serialize_multipart_data_entry(data_entry) + + return files, data diff --git a/packages/typespec-python/test/azure/generated/payload-multipart/payload/multipart/_vendor.py b/packages/typespec-python/test/azure/generated/payload-multipart/payload/multipart/_vendor.py deleted file mode 100644 index e6f01093482..00000000000 --- a/packages/typespec-python/test/azure/generated/payload-multipart/payload/multipart/_vendor.py +++ /dev/null @@ -1,50 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) Python Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -import json -from typing import Any, Dict, IO, List, Mapping, Optional, Tuple, Union - -from ._model_base import Model, SdkJSONEncoder - - -# file-like tuple could be `(filename, IO (or bytes))` or `(filename, IO (or bytes), content_type)` -FileContent = Union[str, bytes, IO[str], IO[bytes]] - -FileType = Union[ - # file (or bytes) - FileContent, - # (filename, file (or bytes)) - Tuple[Optional[str], FileContent], - # (filename, file (or bytes), content_type) - Tuple[Optional[str], FileContent, Optional[str]], -] - - -def serialize_multipart_data_entry(data_entry: Any) -> Any: - if isinstance(data_entry, (list, tuple, dict, Model)): - return json.dumps(data_entry, cls=SdkJSONEncoder, exclude_readonly=True) - return data_entry - - -def prepare_multipart_form_data( - body: Mapping[str, Any], multipart_fields: List[str], data_fields: List[str] -) -> Tuple[List[FileType], Dict[str, Any]]: - files: List[FileType] = [] - data: Dict[str, Any] = {} - for multipart_field in multipart_fields: - multipart_entry = body.get(multipart_field) - if isinstance(multipart_entry, list): - files.extend([(multipart_field, e) for e in multipart_entry]) - elif multipart_entry: - files.append((multipart_field, multipart_entry)) - - for data_field in data_fields: - data_entry = body.get(data_field) - if data_entry: - data[data_field] = serialize_multipart_data_entry(data_entry) - - return files, data diff --git a/packages/typespec-python/test/azure/generated/payload-multipart/payload/multipart/aio/_client.py b/packages/typespec-python/test/azure/generated/payload-multipart/payload/multipart/aio/_client.py index 44793fc0e69..2405f08bb79 100644 --- a/packages/typespec-python/test/azure/generated/payload-multipart/payload/multipart/aio/_client.py +++ b/packages/typespec-python/test/azure/generated/payload-multipart/payload/multipart/aio/_client.py @@ -14,7 +14,7 @@ from azure.core.pipeline import policies from azure.core.rest import AsyncHttpResponse, HttpRequest -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import MultiPartClientConfiguration from .operations import FormDataOperations diff --git a/packages/typespec-python/test/azure/generated/payload-multipart/payload/multipart/aio/operations/_operations.py b/packages/typespec-python/test/azure/generated/payload-multipart/payload/multipart/aio/operations/_operations.py index 8a75d225adc..de42c33ab22 100644 --- a/packages/typespec-python/test/azure/generated/payload-multipart/payload/multipart/aio/operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/payload-multipart/payload/multipart/aio/operations/_operations.py @@ -22,9 +22,10 @@ from azure.core.rest import AsyncHttpResponse, HttpRequest from azure.core.tracing.decorator_async import distributed_trace_async -from ... import _model_base, models as _models -from ..._serialization import Deserializer, Serializer -from ..._vendor import prepare_multipart_form_data +from ... import models as _models +from ..._utils.model_base import Model as _Model +from ..._utils.serialization import Deserializer, Serializer +from ..._utils.utils import prepare_multipart_form_data from ...operations._operations import ( build_form_data_anonymous_model_request, build_form_data_basic_request, @@ -110,7 +111,7 @@ async def basic(self, body: Union[_models.MultiPartRequest, JSON], **kwargs: Any cls: ClsType[None] = kwargs.pop("cls", None) - _body = body.as_dict() if isinstance(body, _model_base.Model) else body + _body = body.as_dict() if isinstance(body, _Model) else body _file_fields: List[str] = ["profileImage"] _data_fields: List[str] = ["id"] _files, _data = prepare_multipart_form_data(_body, _file_fields, _data_fields) @@ -185,7 +186,7 @@ async def file_array_and_basic(self, body: Union[_models.ComplexPartsRequest, JS cls: ClsType[None] = kwargs.pop("cls", None) - _body = body.as_dict() if isinstance(body, _model_base.Model) else body + _body = body.as_dict() if isinstance(body, _Model) else body _file_fields: List[str] = ["profileImage", "pictures"] _data_fields: List[str] = ["id", "address"] _files, _data = prepare_multipart_form_data(_body, _file_fields, _data_fields) @@ -260,7 +261,7 @@ async def json_part(self, body: Union[_models.JsonPartRequest, JSON], **kwargs: cls: ClsType[None] = kwargs.pop("cls", None) - _body = body.as_dict() if isinstance(body, _model_base.Model) else body + _body = body.as_dict() if isinstance(body, _Model) else body _file_fields: List[str] = ["profileImage"] _data_fields: List[str] = ["address"] _files, _data = prepare_multipart_form_data(_body, _file_fields, _data_fields) @@ -335,7 +336,7 @@ async def binary_array_parts(self, body: Union[_models.BinaryArrayPartsRequest, cls: ClsType[None] = kwargs.pop("cls", None) - _body = body.as_dict() if isinstance(body, _model_base.Model) else body + _body = body.as_dict() if isinstance(body, _Model) else body _file_fields: List[str] = ["pictures"] _data_fields: List[str] = ["id"] _files, _data = prepare_multipart_form_data(_body, _file_fields, _data_fields) @@ -410,7 +411,7 @@ async def multi_binary_parts(self, body: Union[_models.MultiBinaryPartsRequest, cls: ClsType[None] = kwargs.pop("cls", None) - _body = body.as_dict() if isinstance(body, _model_base.Model) else body + _body = body.as_dict() if isinstance(body, _Model) else body _file_fields: List[str] = ["profileImage", "picture"] _data_fields: List[str] = [] _files, _data = prepare_multipart_form_data(_body, _file_fields, _data_fields) @@ -487,7 +488,7 @@ async def check_file_name_and_content_type( cls: ClsType[None] = kwargs.pop("cls", None) - _body = body.as_dict() if isinstance(body, _model_base.Model) else body + _body = body.as_dict() if isinstance(body, _Model) else body _file_fields: List[str] = ["profileImage"] _data_fields: List[str] = ["id"] _files, _data = prepare_multipart_form_data(_body, _file_fields, _data_fields) @@ -562,7 +563,7 @@ async def anonymous_model(self, body: Union[_models.AnonymousModelRequest, JSON] cls: ClsType[None] = kwargs.pop("cls", None) - _body = body.as_dict() if isinstance(body, _model_base.Model) else body + _body = body.as_dict() if isinstance(body, _Model) else body _file_fields: List[str] = ["profileImage"] _data_fields: List[str] = [] _files, _data = prepare_multipart_form_data(_body, _file_fields, _data_fields) @@ -664,7 +665,7 @@ async def json_array_and_file_array( cls: ClsType[None] = kwargs.pop("cls", None) - _body = body.as_dict() if isinstance(body, _model_base.Model) else body + _body = body.as_dict() if isinstance(body, _Model) else body _file_fields: List[str] = ["profileImage", "pictures"] _data_fields: List[str] = ["id", "address", "previousAddresses"] _files, _data = prepare_multipart_form_data(_body, _file_fields, _data_fields) @@ -762,7 +763,7 @@ async def image_jpeg_content_type( cls: ClsType[None] = kwargs.pop("cls", None) - _body = body.as_dict() if isinstance(body, _model_base.Model) else body + _body = body.as_dict() if isinstance(body, _Model) else body _file_fields: List[str] = ["profileImage"] _data_fields: List[str] = [] _files, _data = prepare_multipart_form_data(_body, _file_fields, _data_fields) @@ -842,7 +843,7 @@ async def required_content_type( cls: ClsType[None] = kwargs.pop("cls", None) - _body = body.as_dict() if isinstance(body, _model_base.Model) else body + _body = body.as_dict() if isinstance(body, _Model) else body _file_fields: List[str] = ["profileImage"] _data_fields: List[str] = [] _files, _data = prepare_multipart_form_data(_body, _file_fields, _data_fields) @@ -922,7 +923,7 @@ async def optional_content_type( cls: ClsType[None] = kwargs.pop("cls", None) - _body = body.as_dict() if isinstance(body, _model_base.Model) else body + _body = body.as_dict() if isinstance(body, _Model) else body _file_fields: List[str] = ["profileImage"] _data_fields: List[str] = [] _files, _data = prepare_multipart_form_data(_body, _file_fields, _data_fields) @@ -1015,7 +1016,7 @@ async def float(self, body: Union[_models.FloatRequest, JSON], **kwargs: Any) -> cls: ClsType[None] = kwargs.pop("cls", None) - _body = body.as_dict() if isinstance(body, _model_base.Model) else body + _body = body.as_dict() if isinstance(body, _Model) else body _file_fields: List[str] = [] _data_fields: List[str] = ["temperature"] _files, _data = prepare_multipart_form_data(_body, _file_fields, _data_fields) diff --git a/packages/typespec-python/test/azure/generated/payload-multipart/payload/multipart/models/_models.py b/packages/typespec-python/test/azure/generated/payload-multipart/payload/multipart/models/_models.py index 98b2d1f106b..8a6083c3ead 100644 --- a/packages/typespec-python/test/azure/generated/payload-multipart/payload/multipart/models/_models.py +++ b/packages/typespec-python/test/azure/generated/payload-multipart/payload/multipart/models/_models.py @@ -9,15 +9,14 @@ from typing import Any, List, Mapping, Optional, TYPE_CHECKING, overload -from .. import _model_base -from .._model_base import rest_field -from .._vendor import FileType +from .._utils.model_base import Model as _Model, rest_field +from .._utils.utils import FileType if TYPE_CHECKING: from .. import models as _models -class Address(_model_base.Model): +class Address(_Model): """Address. :ivar city: Required. @@ -45,11 +44,11 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class AnonymousModelRequest(_model_base.Model): +class AnonymousModelRequest(_Model): """AnonymousModelRequest. :ivar profile_image: Required. - :vartype profile_image: ~payload.multipart._vendor.FileType + :vartype profile_image: ~payload.multipart._utils.utils.FileType """ profile_image: FileType = rest_field( @@ -75,13 +74,13 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class BinaryArrayPartsRequest(_model_base.Model): +class BinaryArrayPartsRequest(_Model): """BinaryArrayPartsRequest. :ivar id: Required. :vartype id: str :ivar pictures: Required. - :vartype pictures: list[~payload.multipart._vendor.FileType] + :vartype pictures: list[~payload.multipart._utils.utils.FileType] """ id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) @@ -110,7 +109,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class ComplexHttpPartsModelRequest(_model_base.Model): +class ComplexHttpPartsModelRequest(_Model): """ComplexHttpPartsModelRequest. :ivar id: Required. @@ -118,11 +117,11 @@ class ComplexHttpPartsModelRequest(_model_base.Model): :ivar address: Required. :vartype address: ~payload.multipart.models.Address :ivar profile_image: Required. - :vartype profile_image: ~payload.multipart._vendor.FileType + :vartype profile_image: ~payload.multipart._utils.utils.FileType :ivar previous_addresses: Required. :vartype previous_addresses: list[~payload.multipart.models.Address] :ivar pictures: Required. - :vartype pictures: list[~payload.multipart._vendor.FileType] + :vartype pictures: list[~payload.multipart._utils.utils.FileType] """ id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) @@ -164,7 +163,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class ComplexPartsRequest(_model_base.Model): +class ComplexPartsRequest(_Model): """ComplexPartsRequest. :ivar id: Required. @@ -172,9 +171,9 @@ class ComplexPartsRequest(_model_base.Model): :ivar address: Required. :vartype address: ~payload.multipart.models.Address :ivar profile_image: Required. - :vartype profile_image: ~payload.multipart._vendor.FileType + :vartype profile_image: ~payload.multipart._utils.utils.FileType :ivar pictures: Required. - :vartype pictures: list[~payload.multipart._vendor.FileType] + :vartype pictures: list[~payload.multipart._utils.utils.FileType] """ id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) @@ -211,11 +210,11 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class FileWithHttpPartOptionalContentTypeRequest(_model_base.Model): # pylint: disable=name-too-long +class FileWithHttpPartOptionalContentTypeRequest(_Model): # pylint: disable=name-too-long """FileWithHttpPartOptionalContentTypeRequest. :ivar profile_image: Required. - :vartype profile_image: ~payload.multipart._vendor.FileType + :vartype profile_image: ~payload.multipart._utils.utils.FileType """ profile_image: FileType = rest_field( @@ -241,11 +240,11 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class FileWithHttpPartRequiredContentTypeRequest(_model_base.Model): # pylint: disable=name-too-long +class FileWithHttpPartRequiredContentTypeRequest(_Model): # pylint: disable=name-too-long """FileWithHttpPartRequiredContentTypeRequest. :ivar profile_image: Required. - :vartype profile_image: ~payload.multipart._vendor.FileType + :vartype profile_image: ~payload.multipart._utils.utils.FileType """ profile_image: FileType = rest_field( @@ -271,11 +270,11 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class FileWithHttpPartSpecificContentTypeRequest(_model_base.Model): # pylint: disable=name-too-long +class FileWithHttpPartSpecificContentTypeRequest(_Model): # pylint: disable=name-too-long """FileWithHttpPartSpecificContentTypeRequest. :ivar profile_image: Required. - :vartype profile_image: ~payload.multipart._vendor.FileType + :vartype profile_image: ~payload.multipart._utils.utils.FileType """ profile_image: FileType = rest_field( @@ -301,7 +300,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class FloatRequest(_model_base.Model): +class FloatRequest(_Model): """FloatRequest. :ivar temperature: Required. @@ -329,13 +328,13 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class JsonPartRequest(_model_base.Model): +class JsonPartRequest(_Model): """JsonPartRequest. :ivar address: Required. :vartype address: ~payload.multipart.models.Address :ivar profile_image: Required. - :vartype profile_image: ~payload.multipart._vendor.FileType + :vartype profile_image: ~payload.multipart._utils.utils.FileType """ address: "_models.Address" = rest_field(visibility=["read", "create", "update", "delete", "query"]) @@ -364,13 +363,13 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class MultiBinaryPartsRequest(_model_base.Model): +class MultiBinaryPartsRequest(_Model): """MultiBinaryPartsRequest. :ivar profile_image: Required. - :vartype profile_image: ~payload.multipart._vendor.FileType + :vartype profile_image: ~payload.multipart._utils.utils.FileType :ivar picture: - :vartype picture: ~payload.multipart._vendor.FileType + :vartype picture: ~payload.multipart._utils.utils.FileType """ profile_image: FileType = rest_field( @@ -400,13 +399,13 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class MultiPartRequest(_model_base.Model): +class MultiPartRequest(_Model): """MultiPartRequest. :ivar id: Required. :vartype id: str :ivar profile_image: Required. - :vartype profile_image: ~payload.multipart._vendor.FileType + :vartype profile_image: ~payload.multipart._utils.utils.FileType """ id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) diff --git a/packages/typespec-python/test/azure/generated/payload-multipart/payload/multipart/operations/_operations.py b/packages/typespec-python/test/azure/generated/payload-multipart/payload/multipart/operations/_operations.py index d9705f2da2b..c719c7324a5 100644 --- a/packages/typespec-python/test/azure/generated/payload-multipart/payload/multipart/operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/payload-multipart/payload/multipart/operations/_operations.py @@ -23,10 +23,11 @@ from azure.core.tracing.decorator import distributed_trace from azure.core.utils import case_insensitive_dict -from .. import _model_base, models as _models +from .. import models as _models from .._configuration import MultiPartClientConfiguration -from .._serialization import Deserializer, Serializer -from .._vendor import prepare_multipart_form_data +from .._utils.model_base import Model as _Model +from .._utils.serialization import Deserializer, Serializer +from .._utils.utils import prepare_multipart_form_data JSON = MutableMapping[str, Any] T = TypeVar("T") @@ -220,7 +221,7 @@ def basic( # pylint: disable=inconsistent-return-statements cls: ClsType[None] = kwargs.pop("cls", None) - _body = body.as_dict() if isinstance(body, _model_base.Model) else body + _body = body.as_dict() if isinstance(body, _Model) else body _file_fields: List[str] = ["profileImage"] _data_fields: List[str] = ["id"] _files, _data = prepare_multipart_form_data(_body, _file_fields, _data_fields) @@ -297,7 +298,7 @@ def file_array_and_basic( # pylint: disable=inconsistent-return-statements cls: ClsType[None] = kwargs.pop("cls", None) - _body = body.as_dict() if isinstance(body, _model_base.Model) else body + _body = body.as_dict() if isinstance(body, _Model) else body _file_fields: List[str] = ["profileImage", "pictures"] _data_fields: List[str] = ["id", "address"] _files, _data = prepare_multipart_form_data(_body, _file_fields, _data_fields) @@ -374,7 +375,7 @@ def json_part( # pylint: disable=inconsistent-return-statements cls: ClsType[None] = kwargs.pop("cls", None) - _body = body.as_dict() if isinstance(body, _model_base.Model) else body + _body = body.as_dict() if isinstance(body, _Model) else body _file_fields: List[str] = ["profileImage"] _data_fields: List[str] = ["address"] _files, _data = prepare_multipart_form_data(_body, _file_fields, _data_fields) @@ -451,7 +452,7 @@ def binary_array_parts( # pylint: disable=inconsistent-return-statements cls: ClsType[None] = kwargs.pop("cls", None) - _body = body.as_dict() if isinstance(body, _model_base.Model) else body + _body = body.as_dict() if isinstance(body, _Model) else body _file_fields: List[str] = ["pictures"] _data_fields: List[str] = ["id"] _files, _data = prepare_multipart_form_data(_body, _file_fields, _data_fields) @@ -528,7 +529,7 @@ def multi_binary_parts( # pylint: disable=inconsistent-return-statements cls: ClsType[None] = kwargs.pop("cls", None) - _body = body.as_dict() if isinstance(body, _model_base.Model) else body + _body = body.as_dict() if isinstance(body, _Model) else body _file_fields: List[str] = ["profileImage", "picture"] _data_fields: List[str] = [] _files, _data = prepare_multipart_form_data(_body, _file_fields, _data_fields) @@ -605,7 +606,7 @@ def check_file_name_and_content_type( # pylint: disable=inconsistent-return-sta cls: ClsType[None] = kwargs.pop("cls", None) - _body = body.as_dict() if isinstance(body, _model_base.Model) else body + _body = body.as_dict() if isinstance(body, _Model) else body _file_fields: List[str] = ["profileImage"] _data_fields: List[str] = ["id"] _files, _data = prepare_multipart_form_data(_body, _file_fields, _data_fields) @@ -682,7 +683,7 @@ def anonymous_model( # pylint: disable=inconsistent-return-statements cls: ClsType[None] = kwargs.pop("cls", None) - _body = body.as_dict() if isinstance(body, _model_base.Model) else body + _body = body.as_dict() if isinstance(body, _Model) else body _file_fields: List[str] = ["profileImage"] _data_fields: List[str] = [] _files, _data = prepare_multipart_form_data(_body, _file_fields, _data_fields) @@ -784,7 +785,7 @@ def json_array_and_file_array( # pylint: disable=inconsistent-return-statements cls: ClsType[None] = kwargs.pop("cls", None) - _body = body.as_dict() if isinstance(body, _model_base.Model) else body + _body = body.as_dict() if isinstance(body, _Model) else body _file_fields: List[str] = ["profileImage", "pictures"] _data_fields: List[str] = ["id", "address", "previousAddresses"] _files, _data = prepare_multipart_form_data(_body, _file_fields, _data_fields) @@ -880,7 +881,7 @@ def image_jpeg_content_type( # pylint: disable=inconsistent-return-statements cls: ClsType[None] = kwargs.pop("cls", None) - _body = body.as_dict() if isinstance(body, _model_base.Model) else body + _body = body.as_dict() if isinstance(body, _Model) else body _file_fields: List[str] = ["profileImage"] _data_fields: List[str] = [] _files, _data = prepare_multipart_form_data(_body, _file_fields, _data_fields) @@ -958,7 +959,7 @@ def required_content_type( # pylint: disable=inconsistent-return-statements cls: ClsType[None] = kwargs.pop("cls", None) - _body = body.as_dict() if isinstance(body, _model_base.Model) else body + _body = body.as_dict() if isinstance(body, _Model) else body _file_fields: List[str] = ["profileImage"] _data_fields: List[str] = [] _files, _data = prepare_multipart_form_data(_body, _file_fields, _data_fields) @@ -1036,7 +1037,7 @@ def optional_content_type( # pylint: disable=inconsistent-return-statements cls: ClsType[None] = kwargs.pop("cls", None) - _body = body.as_dict() if isinstance(body, _model_base.Model) else body + _body = body.as_dict() if isinstance(body, _Model) else body _file_fields: List[str] = ["profileImage"] _data_fields: List[str] = [] _files, _data = prepare_multipart_form_data(_body, _file_fields, _data_fields) @@ -1131,7 +1132,7 @@ def float( # pylint: disable=inconsistent-return-statements cls: ClsType[None] = kwargs.pop("cls", None) - _body = body.as_dict() if isinstance(body, _model_base.Model) else body + _body = body.as_dict() if isinstance(body, _Model) else body _file_fields: List[str] = [] _data_fields: List[str] = ["temperature"] _files, _data = prepare_multipart_form_data(_body, _file_fields, _data_fields) diff --git a/packages/typespec-python/test/azure/generated/payload-pageable/payload/pageable/_client.py b/packages/typespec-python/test/azure/generated/payload-pageable/payload/pageable/_client.py index 3ff33850ac2..743645c07c7 100644 --- a/packages/typespec-python/test/azure/generated/payload-pageable/payload/pageable/_client.py +++ b/packages/typespec-python/test/azure/generated/payload-pageable/payload/pageable/_client.py @@ -15,7 +15,7 @@ from azure.core.rest import HttpRequest, HttpResponse from ._configuration import PageableClientConfiguration -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer from .serverdrivenpagination.operations import ServerDrivenPaginationOperations diff --git a/packages/typespec-python/test/azure/generated/payload-pageable/payload/pageable/_utils/__init__.py b/packages/typespec-python/test/azure/generated/payload-pageable/payload/pageable/_utils/__init__.py new file mode 100644 index 00000000000..8026245c2ab --- /dev/null +++ b/packages/typespec-python/test/azure/generated/payload-pageable/payload/pageable/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) Python Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/typespec-python/test/azure/generated/payload-xml/payload/xml/_model_base.py b/packages/typespec-python/test/azure/generated/payload-pageable/payload/pageable/_utils/model_base.py similarity index 100% rename from packages/typespec-python/test/azure/generated/payload-xml/payload/xml/_model_base.py rename to packages/typespec-python/test/azure/generated/payload-pageable/payload/pageable/_utils/model_base.py diff --git a/packages/typespec-python/test/azure/generated/payload-xml/payload/xml/_serialization.py b/packages/typespec-python/test/azure/generated/payload-pageable/payload/pageable/_utils/serialization.py similarity index 100% rename from packages/typespec-python/test/azure/generated/payload-xml/payload/xml/_serialization.py rename to packages/typespec-python/test/azure/generated/payload-pageable/payload/pageable/_utils/serialization.py diff --git a/packages/typespec-python/test/azure/generated/payload-pageable/payload/pageable/aio/_client.py b/packages/typespec-python/test/azure/generated/payload-pageable/payload/pageable/aio/_client.py index 55b9bdefdaf..1b5bd24fe4e 100644 --- a/packages/typespec-python/test/azure/generated/payload-pageable/payload/pageable/aio/_client.py +++ b/packages/typespec-python/test/azure/generated/payload-pageable/payload/pageable/aio/_client.py @@ -14,7 +14,7 @@ from azure.core.pipeline import policies from azure.core.rest import AsyncHttpResponse, HttpRequest -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ..serverdrivenpagination.aio.operations import ServerDrivenPaginationOperations from ._configuration import PageableClientConfiguration diff --git a/packages/typespec-python/test/azure/generated/payload-pageable/payload/pageable/models/_models.py b/packages/typespec-python/test/azure/generated/payload-pageable/payload/pageable/models/_models.py index 0bdafff4dcc..222a8739e63 100644 --- a/packages/typespec-python/test/azure/generated/payload-pageable/payload/pageable/models/_models.py +++ b/packages/typespec-python/test/azure/generated/payload-pageable/payload/pageable/models/_models.py @@ -9,11 +9,10 @@ from typing import Any, Mapping, overload -from .. import _model_base -from .._model_base import rest_field +from .._utils.model_base import Model as _Model, rest_field -class Pet(_model_base.Model): +class Pet(_Model): """Pet. :ivar id: Required. diff --git a/packages/typespec-python/test/azure/generated/payload-pageable/payload/pageable/serverdrivenpagination/aio/operations/_operations.py b/packages/typespec-python/test/azure/generated/payload-pageable/payload/pageable/serverdrivenpagination/aio/operations/_operations.py index 195fabdcefc..5fd2465d9fd 100644 --- a/packages/typespec-python/test/azure/generated/payload-pageable/payload/pageable/serverdrivenpagination/aio/operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/payload-pageable/payload/pageable/serverdrivenpagination/aio/operations/_operations.py @@ -23,8 +23,8 @@ from azure.core.tracing.decorator import distributed_trace from .... import models as _models3 -from ...._model_base import _deserialize -from ...._serialization import Deserializer, Serializer +from ...._utils.model_base import _deserialize +from ...._utils.serialization import Deserializer, Serializer from ....aio._configuration import PageableClientConfiguration from ...continuationtoken.aio.operations._operations import ServerDrivenPaginationContinuationTokenOperations from ...operations._operations import build_server_driven_pagination_link_request diff --git a/packages/typespec-python/test/azure/generated/payload-pageable/payload/pageable/serverdrivenpagination/continuationtoken/aio/operations/_operations.py b/packages/typespec-python/test/azure/generated/payload-pageable/payload/pageable/serverdrivenpagination/continuationtoken/aio/operations/_operations.py index b88c90664c4..fdefe473c1b 100644 --- a/packages/typespec-python/test/azure/generated/payload-pageable/payload/pageable/serverdrivenpagination/continuationtoken/aio/operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/payload-pageable/payload/pageable/serverdrivenpagination/continuationtoken/aio/operations/_operations.py @@ -23,8 +23,8 @@ from azure.core.tracing.decorator import distributed_trace from ..... import models as _models4 -from ....._model_base import _deserialize -from ....._serialization import Deserializer, Serializer +from ....._utils.model_base import _deserialize +from ....._utils.serialization import Deserializer, Serializer from .....aio._configuration import PageableClientConfiguration from ...operations._operations import ( build_server_driven_pagination_continuation_token_request_header_response_body_request, diff --git a/packages/typespec-python/test/azure/generated/payload-pageable/payload/pageable/serverdrivenpagination/continuationtoken/operations/_operations.py b/packages/typespec-python/test/azure/generated/payload-pageable/payload/pageable/serverdrivenpagination/continuationtoken/operations/_operations.py index cc0cbcacff3..143e2ce1f7d 100644 --- a/packages/typespec-python/test/azure/generated/payload-pageable/payload/pageable/serverdrivenpagination/continuationtoken/operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/payload-pageable/payload/pageable/serverdrivenpagination/continuationtoken/operations/_operations.py @@ -26,8 +26,8 @@ from .... import models as _models3 from ...._configuration import PageableClientConfiguration -from ...._model_base import _deserialize -from ...._serialization import Deserializer, Serializer +from ...._utils.model_base import _deserialize +from ...._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/typespec-python/test/azure/generated/payload-pageable/payload/pageable/serverdrivenpagination/operations/_operations.py b/packages/typespec-python/test/azure/generated/payload-pageable/payload/pageable/serverdrivenpagination/operations/_operations.py index 4ee3991a7db..0e215f58ebe 100644 --- a/packages/typespec-python/test/azure/generated/payload-pageable/payload/pageable/serverdrivenpagination/operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/payload-pageable/payload/pageable/serverdrivenpagination/operations/_operations.py @@ -25,8 +25,8 @@ from ... import models as _models2 from ..._configuration import PageableClientConfiguration -from ..._model_base import _deserialize -from ..._serialization import Deserializer, Serializer +from ..._utils.model_base import _deserialize +from ..._utils.serialization import Deserializer, Serializer from ..continuationtoken.operations._operations import ServerDrivenPaginationContinuationTokenOperations T = TypeVar("T") diff --git a/packages/typespec-python/test/azure/generated/payload-xml/payload/xml/_client.py b/packages/typespec-python/test/azure/generated/payload-xml/payload/xml/_client.py index 8ea8d78c2ee..05d84532b37 100644 --- a/packages/typespec-python/test/azure/generated/payload-xml/payload/xml/_client.py +++ b/packages/typespec-python/test/azure/generated/payload-xml/payload/xml/_client.py @@ -15,7 +15,7 @@ from azure.core.rest import HttpRequest, HttpResponse from ._configuration import XmlClientConfiguration -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer from .operations import ( ModelWithArrayOfModelValueOperations, ModelWithAttributesValueOperations, diff --git a/packages/typespec-python/test/azure/generated/payload-xml/payload/xml/_utils/__init__.py b/packages/typespec-python/test/azure/generated/payload-xml/payload/xml/_utils/__init__.py new file mode 100644 index 00000000000..8026245c2ab --- /dev/null +++ b/packages/typespec-python/test/azure/generated/payload-xml/payload/xml/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) Python Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/typespec-python/test/azure/generated/resiliency-srv-driven1/resiliency/srv/driven1/_model_base.py b/packages/typespec-python/test/azure/generated/payload-xml/payload/xml/_utils/model_base.py similarity index 100% rename from packages/typespec-python/test/azure/generated/resiliency-srv-driven1/resiliency/srv/driven1/_model_base.py rename to packages/typespec-python/test/azure/generated/payload-xml/payload/xml/_utils/model_base.py diff --git a/packages/typespec-python/test/azure/generated/resiliency-srv-driven1/resiliency/srv/driven1/_serialization.py b/packages/typespec-python/test/azure/generated/payload-xml/payload/xml/_utils/serialization.py similarity index 100% rename from packages/typespec-python/test/azure/generated/resiliency-srv-driven1/resiliency/srv/driven1/_serialization.py rename to packages/typespec-python/test/azure/generated/payload-xml/payload/xml/_utils/serialization.py diff --git a/packages/typespec-python/test/azure/generated/payload-xml/payload/xml/aio/_client.py b/packages/typespec-python/test/azure/generated/payload-xml/payload/xml/aio/_client.py index 05d33cfc25c..9bff62debf6 100644 --- a/packages/typespec-python/test/azure/generated/payload-xml/payload/xml/aio/_client.py +++ b/packages/typespec-python/test/azure/generated/payload-xml/payload/xml/aio/_client.py @@ -14,7 +14,7 @@ from azure.core.pipeline import policies from azure.core.rest import AsyncHttpResponse, HttpRequest -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import XmlClientConfiguration from .operations import ( ModelWithArrayOfModelValueOperations, diff --git a/packages/typespec-python/test/azure/generated/payload-xml/payload/xml/aio/operations/_operations.py b/packages/typespec-python/test/azure/generated/payload-xml/payload/xml/aio/operations/_operations.py index 30d0156776d..1155ae7e712 100644 --- a/packages/typespec-python/test/azure/generated/payload-xml/payload/xml/aio/operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/payload-xml/payload/xml/aio/operations/_operations.py @@ -26,8 +26,8 @@ from azure.core.utils import case_insensitive_dict from ... import models as _models -from ..._model_base import _deserialize_xml, _get_element -from ..._serialization import Deserializer, Serializer +from ..._utils.model_base import _deserialize_xml, _get_element +from ..._utils.serialization import Deserializer, Serializer from ...operations._operations import ( build_model_with_array_of_model_value_get_request, build_model_with_array_of_model_value_put_request, diff --git a/packages/typespec-python/test/azure/generated/payload-xml/payload/xml/models/_models.py b/packages/typespec-python/test/azure/generated/payload-xml/payload/xml/models/_models.py index 25fc1866be4..e6b4f8c75b8 100644 --- a/packages/typespec-python/test/azure/generated/payload-xml/payload/xml/models/_models.py +++ b/packages/typespec-python/test/azure/generated/payload-xml/payload/xml/models/_models.py @@ -9,14 +9,13 @@ from typing import Any, Dict, List, Mapping, Optional, TYPE_CHECKING, overload -from .. import _model_base -from .._model_base import rest_field +from .._utils.model_base import Model as _Model, rest_field if TYPE_CHECKING: from .. import models as _models -class ModelWithArrayOfModel(_model_base.Model): +class ModelWithArrayOfModel(_Model): """Contains an array of models. :ivar items_property: Required. @@ -50,7 +49,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class ModelWithAttributes(_model_base.Model): +class ModelWithAttributes(_Model): """Contains fields that are XML attributes. :ivar id1: Required. @@ -99,7 +98,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class ModelWithDictionary(_model_base.Model): +class ModelWithDictionary(_Model): """Contains a dictionary of key value pairs. :ivar metadata: Required. @@ -132,7 +131,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class ModelWithEmptyArray(_model_base.Model): +class ModelWithEmptyArray(_Model): """Contains an array of models that's supposed to be sent/received as an empty XML element. :ivar items_property: Required. @@ -166,7 +165,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class ModelWithEncodedNames(_model_base.Model): +class ModelWithEncodedNames(_Model): """Uses encodedName instead of Xml.Name which is functionally equivalent. :ivar model_data: Required. @@ -208,7 +207,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class ModelWithOptionalField(_model_base.Model): +class ModelWithOptionalField(_Model): """Contains an optional field. :ivar item: Required. @@ -248,7 +247,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class ModelWithRenamedArrays(_model_base.Model): +class ModelWithRenamedArrays(_Model): """Contains fields of wrapped and unwrapped arrays of primitive types that have different XML representations. @@ -290,7 +289,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class ModelWithRenamedFields(_model_base.Model): +class ModelWithRenamedFields(_Model): """Contains fields of the same type that have different XML representation. :ivar input_data: Required. @@ -333,7 +332,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class ModelWithSimpleArrays(_model_base.Model): +class ModelWithSimpleArrays(_Model): """Contains fields of arrays of primitive types. :ivar colors: Required. @@ -374,7 +373,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class ModelWithText(_model_base.Model): +class ModelWithText(_Model): """Contains an attribute and text. :ivar language: Required. @@ -415,7 +414,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class ModelWithUnwrappedArray(_model_base.Model): +class ModelWithUnwrappedArray(_Model): """Contains fields of wrapped and unwrapped arrays of primitive types. :ivar colors: Required. @@ -456,7 +455,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class SimpleModel(_model_base.Model): +class SimpleModel(_Model): """Contains fields of primitive types. :ivar name: Required. diff --git a/packages/typespec-python/test/azure/generated/payload-xml/payload/xml/operations/_operations.py b/packages/typespec-python/test/azure/generated/payload-xml/payload/xml/operations/_operations.py index 0d8fc2e24bf..f464b6bae65 100644 --- a/packages/typespec-python/test/azure/generated/payload-xml/payload/xml/operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/payload-xml/payload/xml/operations/_operations.py @@ -27,8 +27,8 @@ from .. import models as _models from .._configuration import XmlClientConfiguration -from .._model_base import _deserialize_xml, _get_element -from .._serialization import Deserializer, Serializer +from .._utils.model_base import _deserialize_xml, _get_element +from .._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/typespec-python/test/azure/generated/resiliency-srv-driven1/resiliency/srv/driven1/_client.py b/packages/typespec-python/test/azure/generated/resiliency-srv-driven1/resiliency/srv/driven1/_client.py index 945892153ed..04b53faf8ff 100644 --- a/packages/typespec-python/test/azure/generated/resiliency-srv-driven1/resiliency/srv/driven1/_client.py +++ b/packages/typespec-python/test/azure/generated/resiliency-srv-driven1/resiliency/srv/driven1/_client.py @@ -16,7 +16,7 @@ from ._configuration import ResiliencyServiceDrivenClientConfiguration from ._operations import ResiliencyServiceDrivenClientOperationsMixin -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer class ResiliencyServiceDrivenClient(ResiliencyServiceDrivenClientOperationsMixin): diff --git a/packages/typespec-python/test/azure/generated/resiliency-srv-driven1/resiliency/srv/driven1/_operations/_operations.py b/packages/typespec-python/test/azure/generated/resiliency-srv-driven1/resiliency/srv/driven1/_operations/_operations.py index 48e70606b46..0c5f953d2aa 100644 --- a/packages/typespec-python/test/azure/generated/resiliency-srv-driven1/resiliency/srv/driven1/_operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/resiliency-srv-driven1/resiliency/srv/driven1/_operations/_operations.py @@ -8,6 +8,7 @@ from collections.abc import MutableMapping from typing import Any, Callable, Dict, Optional, TypeVar +from azure.core import PipelineClient from azure.core.exceptions import ( ClientAuthenticationError, HttpResponseError, @@ -21,8 +22,9 @@ from azure.core.tracing.decorator import distributed_trace from azure.core.utils import case_insensitive_dict -from .._serialization import Serializer -from .._vendor import ResiliencyServiceDrivenClientMixinABC +from .._configuration import ResiliencyServiceDrivenClientConfiguration +from .._utils.serialization import Serializer +from .._utils.utils import ClientMixinABC T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] @@ -68,7 +70,7 @@ def build_resiliency_service_driven_from_one_optional_request( # pylint: disabl class ResiliencyServiceDrivenClientOperationsMixin( # pylint: disable=name-too-long - ResiliencyServiceDrivenClientMixinABC + ClientMixinABC[PipelineClient, ResiliencyServiceDrivenClientConfiguration] ): @distributed_trace diff --git a/packages/typespec-python/test/azure/generated/resiliency-srv-driven1/resiliency/srv/driven1/_utils/__init__.py b/packages/typespec-python/test/azure/generated/resiliency-srv-driven1/resiliency/srv/driven1/_utils/__init__.py new file mode 100644 index 00000000000..8026245c2ab --- /dev/null +++ b/packages/typespec-python/test/azure/generated/resiliency-srv-driven1/resiliency/srv/driven1/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) Python Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/typespec-python/test/azure/generated/resiliency-srv-driven2/resiliency/srv/driven2/_model_base.py b/packages/typespec-python/test/azure/generated/resiliency-srv-driven1/resiliency/srv/driven1/_utils/model_base.py similarity index 100% rename from packages/typespec-python/test/azure/generated/resiliency-srv-driven2/resiliency/srv/driven2/_model_base.py rename to packages/typespec-python/test/azure/generated/resiliency-srv-driven1/resiliency/srv/driven1/_utils/model_base.py diff --git a/packages/typespec-python/test/azure/generated/resiliency-srv-driven2/resiliency/srv/driven2/_serialization.py b/packages/typespec-python/test/azure/generated/resiliency-srv-driven1/resiliency/srv/driven1/_utils/serialization.py similarity index 100% rename from packages/typespec-python/test/azure/generated/resiliency-srv-driven2/resiliency/srv/driven2/_serialization.py rename to packages/typespec-python/test/azure/generated/resiliency-srv-driven1/resiliency/srv/driven1/_utils/serialization.py diff --git a/packages/typespec-python/test/azure/generated/resiliency-srv-driven1/resiliency/srv/driven1/_utils/utils.py b/packages/typespec-python/test/azure/generated/resiliency-srv-driven1/resiliency/srv/driven1/_utils/utils.py new file mode 100644 index 00000000000..35c9c836f85 --- /dev/null +++ b/packages/typespec-python/test/azure/generated/resiliency-srv-driven1/resiliency/srv/driven1/_utils/utils.py @@ -0,0 +1,25 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) Python Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from abc import ABC +from typing import Generic, TYPE_CHECKING, TypeVar + +if TYPE_CHECKING: + from .serialization import Deserializer, Serializer + + +TClient = TypeVar("TClient") +TConfig = TypeVar("TConfig") + + +class ClientMixinABC(ABC, Generic[TClient, TConfig]): + """DO NOT use this class. It is for internal typing use only.""" + + _client: TClient + _config: TConfig + _serialize: "Serializer" + _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/azure/generated/resiliency-srv-driven1/resiliency/srv/driven1/_vendor.py b/packages/typespec-python/test/azure/generated/resiliency-srv-driven1/resiliency/srv/driven1/_vendor.py deleted file mode 100644 index 7bcc56a09c5..00000000000 --- a/packages/typespec-python/test/azure/generated/resiliency-srv-driven1/resiliency/srv/driven1/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) Python Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import ResiliencyServiceDrivenClientConfiguration - -if TYPE_CHECKING: - from azure.core import PipelineClient - - from ._serialization import Deserializer, Serializer - - -class ResiliencyServiceDrivenClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "PipelineClient" - _config: ResiliencyServiceDrivenClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/azure/generated/resiliency-srv-driven1/resiliency/srv/driven1/aio/_client.py b/packages/typespec-python/test/azure/generated/resiliency-srv-driven1/resiliency/srv/driven1/aio/_client.py index 08a497dda68..c6196ed7c31 100644 --- a/packages/typespec-python/test/azure/generated/resiliency-srv-driven1/resiliency/srv/driven1/aio/_client.py +++ b/packages/typespec-python/test/azure/generated/resiliency-srv-driven1/resiliency/srv/driven1/aio/_client.py @@ -14,7 +14,7 @@ from azure.core.pipeline import policies from azure.core.rest import AsyncHttpResponse, HttpRequest -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import ResiliencyServiceDrivenClientConfiguration from ._operations import ResiliencyServiceDrivenClientOperationsMixin diff --git a/packages/typespec-python/test/azure/generated/resiliency-srv-driven1/resiliency/srv/driven1/aio/_operations/_operations.py b/packages/typespec-python/test/azure/generated/resiliency-srv-driven1/resiliency/srv/driven1/aio/_operations/_operations.py index 91ba5467f3e..5d4f9a127ee 100644 --- a/packages/typespec-python/test/azure/generated/resiliency-srv-driven1/resiliency/srv/driven1/aio/_operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/resiliency-srv-driven1/resiliency/srv/driven1/aio/_operations/_operations.py @@ -9,6 +9,7 @@ from collections.abc import MutableMapping from typing import Any, Callable, Dict, Optional, TypeVar +from azure.core import AsyncPipelineClient from azure.core.exceptions import ( ClientAuthenticationError, HttpResponseError, @@ -26,14 +27,15 @@ build_resiliency_service_driven_from_one_optional_request, build_resiliency_service_driven_from_one_required_request, ) -from .._vendor import ResiliencyServiceDrivenClientMixinABC +from ..._utils.utils import ClientMixinABC +from .._configuration import ResiliencyServiceDrivenClientConfiguration T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, AsyncHttpResponse], T, Dict[str, Any]], Any]] class ResiliencyServiceDrivenClientOperationsMixin( # pylint: disable=name-too-long - ResiliencyServiceDrivenClientMixinABC + ClientMixinABC[AsyncPipelineClient, ResiliencyServiceDrivenClientConfiguration] ): @distributed_trace_async diff --git a/packages/typespec-python/test/azure/generated/resiliency-srv-driven1/resiliency/srv/driven1/aio/_vendor.py b/packages/typespec-python/test/azure/generated/resiliency-srv-driven1/resiliency/srv/driven1/aio/_vendor.py deleted file mode 100644 index f673ada5d49..00000000000 --- a/packages/typespec-python/test/azure/generated/resiliency-srv-driven1/resiliency/srv/driven1/aio/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) Python Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import ResiliencyServiceDrivenClientConfiguration - -if TYPE_CHECKING: - from azure.core import AsyncPipelineClient - - from .._serialization import Deserializer, Serializer - - -class ResiliencyServiceDrivenClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "AsyncPipelineClient" - _config: ResiliencyServiceDrivenClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/azure/generated/resiliency-srv-driven2/resiliency/srv/driven2/_client.py b/packages/typespec-python/test/azure/generated/resiliency-srv-driven2/resiliency/srv/driven2/_client.py index ae4f25e0b23..7893af70ced 100644 --- a/packages/typespec-python/test/azure/generated/resiliency-srv-driven2/resiliency/srv/driven2/_client.py +++ b/packages/typespec-python/test/azure/generated/resiliency-srv-driven2/resiliency/srv/driven2/_client.py @@ -16,7 +16,7 @@ from ._configuration import ResiliencyServiceDrivenClientConfiguration from ._operations import ResiliencyServiceDrivenClientOperationsMixin -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer class ResiliencyServiceDrivenClient(ResiliencyServiceDrivenClientOperationsMixin): diff --git a/packages/typespec-python/test/azure/generated/resiliency-srv-driven2/resiliency/srv/driven2/_operations/_operations.py b/packages/typespec-python/test/azure/generated/resiliency-srv-driven2/resiliency/srv/driven2/_operations/_operations.py index fd1266b3bb7..006dd9af2de 100644 --- a/packages/typespec-python/test/azure/generated/resiliency-srv-driven2/resiliency/srv/driven2/_operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/resiliency-srv-driven2/resiliency/srv/driven2/_operations/_operations.py @@ -8,6 +8,7 @@ from collections.abc import MutableMapping from typing import Any, Callable, Dict, Optional, TypeVar +from azure.core import PipelineClient from azure.core.exceptions import ( ClientAuthenticationError, HttpResponseError, @@ -21,9 +22,10 @@ from azure.core.tracing.decorator import distributed_trace from azure.core.utils import case_insensitive_dict -from .._serialization import Serializer +from .._configuration import ResiliencyServiceDrivenClientConfiguration +from .._utils.serialization import Serializer +from .._utils.utils import ClientMixinABC from .._validation import api_version_validation -from .._vendor import ResiliencyServiceDrivenClientMixinABC T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] @@ -90,7 +92,7 @@ def build_resiliency_service_driven_from_one_optional_request( # pylint: disabl class ResiliencyServiceDrivenClientOperationsMixin( # pylint: disable=name-too-long - ResiliencyServiceDrivenClientMixinABC + ClientMixinABC[PipelineClient, ResiliencyServiceDrivenClientConfiguration] ): @distributed_trace diff --git a/packages/typespec-python/test/azure/generated/resiliency-srv-driven2/resiliency/srv/driven2/_utils/__init__.py b/packages/typespec-python/test/azure/generated/resiliency-srv-driven2/resiliency/srv/driven2/_utils/__init__.py new file mode 100644 index 00000000000..8026245c2ab --- /dev/null +++ b/packages/typespec-python/test/azure/generated/resiliency-srv-driven2/resiliency/srv/driven2/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) Python Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/typespec-python/test/azure/generated/response-status-code-range/response/statuscoderange/_model_base.py b/packages/typespec-python/test/azure/generated/resiliency-srv-driven2/resiliency/srv/driven2/_utils/model_base.py similarity index 100% rename from packages/typespec-python/test/azure/generated/response-status-code-range/response/statuscoderange/_model_base.py rename to packages/typespec-python/test/azure/generated/resiliency-srv-driven2/resiliency/srv/driven2/_utils/model_base.py diff --git a/packages/typespec-python/test/azure/generated/response-status-code-range/response/statuscoderange/_serialization.py b/packages/typespec-python/test/azure/generated/resiliency-srv-driven2/resiliency/srv/driven2/_utils/serialization.py similarity index 100% rename from packages/typespec-python/test/azure/generated/response-status-code-range/response/statuscoderange/_serialization.py rename to packages/typespec-python/test/azure/generated/resiliency-srv-driven2/resiliency/srv/driven2/_utils/serialization.py diff --git a/packages/typespec-python/test/azure/generated/resiliency-srv-driven2/resiliency/srv/driven2/_utils/utils.py b/packages/typespec-python/test/azure/generated/resiliency-srv-driven2/resiliency/srv/driven2/_utils/utils.py new file mode 100644 index 00000000000..35c9c836f85 --- /dev/null +++ b/packages/typespec-python/test/azure/generated/resiliency-srv-driven2/resiliency/srv/driven2/_utils/utils.py @@ -0,0 +1,25 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) Python Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from abc import ABC +from typing import Generic, TYPE_CHECKING, TypeVar + +if TYPE_CHECKING: + from .serialization import Deserializer, Serializer + + +TClient = TypeVar("TClient") +TConfig = TypeVar("TConfig") + + +class ClientMixinABC(ABC, Generic[TClient, TConfig]): + """DO NOT use this class. It is for internal typing use only.""" + + _client: TClient + _config: TConfig + _serialize: "Serializer" + _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/azure/generated/resiliency-srv-driven2/resiliency/srv/driven2/_vendor.py b/packages/typespec-python/test/azure/generated/resiliency-srv-driven2/resiliency/srv/driven2/_vendor.py deleted file mode 100644 index 7bcc56a09c5..00000000000 --- a/packages/typespec-python/test/azure/generated/resiliency-srv-driven2/resiliency/srv/driven2/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) Python Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import ResiliencyServiceDrivenClientConfiguration - -if TYPE_CHECKING: - from azure.core import PipelineClient - - from ._serialization import Deserializer, Serializer - - -class ResiliencyServiceDrivenClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "PipelineClient" - _config: ResiliencyServiceDrivenClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/azure/generated/resiliency-srv-driven2/resiliency/srv/driven2/aio/_client.py b/packages/typespec-python/test/azure/generated/resiliency-srv-driven2/resiliency/srv/driven2/aio/_client.py index 2e01ffdc3b6..2bb061ef64f 100644 --- a/packages/typespec-python/test/azure/generated/resiliency-srv-driven2/resiliency/srv/driven2/aio/_client.py +++ b/packages/typespec-python/test/azure/generated/resiliency-srv-driven2/resiliency/srv/driven2/aio/_client.py @@ -14,7 +14,7 @@ from azure.core.pipeline import policies from azure.core.rest import AsyncHttpResponse, HttpRequest -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import ResiliencyServiceDrivenClientConfiguration from ._operations import ResiliencyServiceDrivenClientOperationsMixin diff --git a/packages/typespec-python/test/azure/generated/resiliency-srv-driven2/resiliency/srv/driven2/aio/_operations/_operations.py b/packages/typespec-python/test/azure/generated/resiliency-srv-driven2/resiliency/srv/driven2/aio/_operations/_operations.py index 3e04fbb02eb..5effd1ed86c 100644 --- a/packages/typespec-python/test/azure/generated/resiliency-srv-driven2/resiliency/srv/driven2/aio/_operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/resiliency-srv-driven2/resiliency/srv/driven2/aio/_operations/_operations.py @@ -9,6 +9,7 @@ from collections.abc import MutableMapping from typing import Any, Callable, Dict, Optional, TypeVar +from azure.core import AsyncPipelineClient from azure.core.exceptions import ( ClientAuthenticationError, HttpResponseError, @@ -27,15 +28,16 @@ build_resiliency_service_driven_from_one_optional_request, build_resiliency_service_driven_from_one_required_request, ) +from ..._utils.utils import ClientMixinABC from ..._validation import api_version_validation -from .._vendor import ResiliencyServiceDrivenClientMixinABC +from .._configuration import ResiliencyServiceDrivenClientConfiguration T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, AsyncHttpResponse], T, Dict[str, Any]], Any]] class ResiliencyServiceDrivenClientOperationsMixin( # pylint: disable=name-too-long - ResiliencyServiceDrivenClientMixinABC + ClientMixinABC[AsyncPipelineClient, ResiliencyServiceDrivenClientConfiguration] ): @distributed_trace_async diff --git a/packages/typespec-python/test/azure/generated/resiliency-srv-driven2/resiliency/srv/driven2/aio/_vendor.py b/packages/typespec-python/test/azure/generated/resiliency-srv-driven2/resiliency/srv/driven2/aio/_vendor.py deleted file mode 100644 index f673ada5d49..00000000000 --- a/packages/typespec-python/test/azure/generated/resiliency-srv-driven2/resiliency/srv/driven2/aio/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) Python Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import ResiliencyServiceDrivenClientConfiguration - -if TYPE_CHECKING: - from azure.core import AsyncPipelineClient - - from .._serialization import Deserializer, Serializer - - -class ResiliencyServiceDrivenClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "AsyncPipelineClient" - _config: ResiliencyServiceDrivenClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/azure/generated/response-status-code-range/response/statuscoderange/_client.py b/packages/typespec-python/test/azure/generated/response-status-code-range/response/statuscoderange/_client.py index c8bb54ee91a..627f543d1bd 100644 --- a/packages/typespec-python/test/azure/generated/response-status-code-range/response/statuscoderange/_client.py +++ b/packages/typespec-python/test/azure/generated/response-status-code-range/response/statuscoderange/_client.py @@ -16,7 +16,7 @@ from ._configuration import StatusCodeRangeClientConfiguration from ._operations import StatusCodeRangeClientOperationsMixin -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer class StatusCodeRangeClient(StatusCodeRangeClientOperationsMixin): # pylint: disable=client-accepts-api-version-keyword diff --git a/packages/typespec-python/test/azure/generated/response-status-code-range/response/statuscoderange/_operations/_operations.py b/packages/typespec-python/test/azure/generated/response-status-code-range/response/statuscoderange/_operations/_operations.py index 409b576558e..3d0fae2beab 100644 --- a/packages/typespec-python/test/azure/generated/response-status-code-range/response/statuscoderange/_operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/response-status-code-range/response/statuscoderange/_operations/_operations.py @@ -8,6 +8,7 @@ from collections.abc import MutableMapping from typing import Any, Callable, Dict, Optional, TypeVar +from azure.core import PipelineClient from azure.core.exceptions import ( ClientAuthenticationError, HttpResponseError, @@ -22,9 +23,10 @@ from azure.core.utils import case_insensitive_dict from .. import models as _models -from .._model_base import _failsafe_deserialize -from .._serialization import Serializer -from .._vendor import StatusCodeRangeClientMixinABC +from .._configuration import StatusCodeRangeClientConfiguration +from .._utils.model_base import _failsafe_deserialize +from .._utils.serialization import Serializer +from .._utils.utils import ClientMixinABC T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] @@ -65,7 +67,7 @@ def build_status_code_range_error_response_status_code404_request( # pylint: di return HttpRequest(method="GET", url=_url, headers=_headers, **kwargs) -class StatusCodeRangeClientOperationsMixin(StatusCodeRangeClientMixinABC): +class StatusCodeRangeClientOperationsMixin(ClientMixinABC[PipelineClient, StatusCodeRangeClientConfiguration]): @distributed_trace def error_response_status_code_in_range( # pylint: disable=inconsistent-return-statements diff --git a/packages/typespec-python/test/azure/generated/response-status-code-range/response/statuscoderange/_utils/__init__.py b/packages/typespec-python/test/azure/generated/response-status-code-range/response/statuscoderange/_utils/__init__.py new file mode 100644 index 00000000000..8026245c2ab --- /dev/null +++ b/packages/typespec-python/test/azure/generated/response-status-code-range/response/statuscoderange/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) Python Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/typespec-python/test/azure/generated/routes/routes/_model_base.py b/packages/typespec-python/test/azure/generated/response-status-code-range/response/statuscoderange/_utils/model_base.py similarity index 100% rename from packages/typespec-python/test/azure/generated/routes/routes/_model_base.py rename to packages/typespec-python/test/azure/generated/response-status-code-range/response/statuscoderange/_utils/model_base.py diff --git a/packages/typespec-python/test/azure/generated/routes/routes/_serialization.py b/packages/typespec-python/test/azure/generated/response-status-code-range/response/statuscoderange/_utils/serialization.py similarity index 100% rename from packages/typespec-python/test/azure/generated/routes/routes/_serialization.py rename to packages/typespec-python/test/azure/generated/response-status-code-range/response/statuscoderange/_utils/serialization.py diff --git a/packages/typespec-python/test/azure/generated/response-status-code-range/response/statuscoderange/_utils/utils.py b/packages/typespec-python/test/azure/generated/response-status-code-range/response/statuscoderange/_utils/utils.py new file mode 100644 index 00000000000..35c9c836f85 --- /dev/null +++ b/packages/typespec-python/test/azure/generated/response-status-code-range/response/statuscoderange/_utils/utils.py @@ -0,0 +1,25 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) Python Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from abc import ABC +from typing import Generic, TYPE_CHECKING, TypeVar + +if TYPE_CHECKING: + from .serialization import Deserializer, Serializer + + +TClient = TypeVar("TClient") +TConfig = TypeVar("TConfig") + + +class ClientMixinABC(ABC, Generic[TClient, TConfig]): + """DO NOT use this class. It is for internal typing use only.""" + + _client: TClient + _config: TConfig + _serialize: "Serializer" + _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/azure/generated/response-status-code-range/response/statuscoderange/_vendor.py b/packages/typespec-python/test/azure/generated/response-status-code-range/response/statuscoderange/_vendor.py deleted file mode 100644 index 41dc5fa69db..00000000000 --- a/packages/typespec-python/test/azure/generated/response-status-code-range/response/statuscoderange/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) Python Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import StatusCodeRangeClientConfiguration - -if TYPE_CHECKING: - from azure.core import PipelineClient - - from ._serialization import Deserializer, Serializer - - -class StatusCodeRangeClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "PipelineClient" - _config: StatusCodeRangeClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/azure/generated/response-status-code-range/response/statuscoderange/aio/_client.py b/packages/typespec-python/test/azure/generated/response-status-code-range/response/statuscoderange/aio/_client.py index 45f2b390a0a..9204c9baaca 100644 --- a/packages/typespec-python/test/azure/generated/response-status-code-range/response/statuscoderange/aio/_client.py +++ b/packages/typespec-python/test/azure/generated/response-status-code-range/response/statuscoderange/aio/_client.py @@ -14,7 +14,7 @@ from azure.core.pipeline import policies from azure.core.rest import AsyncHttpResponse, HttpRequest -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import StatusCodeRangeClientConfiguration from ._operations import StatusCodeRangeClientOperationsMixin diff --git a/packages/typespec-python/test/azure/generated/response-status-code-range/response/statuscoderange/aio/_operations/_operations.py b/packages/typespec-python/test/azure/generated/response-status-code-range/response/statuscoderange/aio/_operations/_operations.py index 7b7427cf8a9..c72aeec500b 100644 --- a/packages/typespec-python/test/azure/generated/response-status-code-range/response/statuscoderange/aio/_operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/response-status-code-range/response/statuscoderange/aio/_operations/_operations.py @@ -9,6 +9,7 @@ from collections.abc import MutableMapping from typing import Any, Callable, Dict, Optional, TypeVar +from azure.core import AsyncPipelineClient from azure.core.exceptions import ( ClientAuthenticationError, HttpResponseError, @@ -22,18 +23,19 @@ from azure.core.tracing.decorator_async import distributed_trace_async from ... import models as _models -from ..._model_base import _failsafe_deserialize from ..._operations._operations import ( build_status_code_range_error_response_status_code404_request, build_status_code_range_error_response_status_code_in_range_request, ) -from .._vendor import StatusCodeRangeClientMixinABC +from ..._utils.model_base import _failsafe_deserialize +from ..._utils.utils import ClientMixinABC +from .._configuration import StatusCodeRangeClientConfiguration T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, AsyncHttpResponse], T, Dict[str, Any]], Any]] -class StatusCodeRangeClientOperationsMixin(StatusCodeRangeClientMixinABC): +class StatusCodeRangeClientOperationsMixin(ClientMixinABC[AsyncPipelineClient, StatusCodeRangeClientConfiguration]): @distributed_trace_async async def error_response_status_code_in_range(self, **kwargs: Any) -> None: diff --git a/packages/typespec-python/test/azure/generated/response-status-code-range/response/statuscoderange/aio/_vendor.py b/packages/typespec-python/test/azure/generated/response-status-code-range/response/statuscoderange/aio/_vendor.py deleted file mode 100644 index 263cd4a4f72..00000000000 --- a/packages/typespec-python/test/azure/generated/response-status-code-range/response/statuscoderange/aio/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) Python Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import StatusCodeRangeClientConfiguration - -if TYPE_CHECKING: - from azure.core import AsyncPipelineClient - - from .._serialization import Deserializer, Serializer - - -class StatusCodeRangeClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "AsyncPipelineClient" - _config: StatusCodeRangeClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/azure/generated/response-status-code-range/response/statuscoderange/models/_models.py b/packages/typespec-python/test/azure/generated/response-status-code-range/response/statuscoderange/models/_models.py index e113572d890..74ca64d8057 100644 --- a/packages/typespec-python/test/azure/generated/response-status-code-range/response/statuscoderange/models/_models.py +++ b/packages/typespec-python/test/azure/generated/response-status-code-range/response/statuscoderange/models/_models.py @@ -9,11 +9,10 @@ from typing import Any, Mapping, overload -from .. import _model_base -from .._model_base import rest_field +from .._utils.model_base import Model as _Model, rest_field -class DefaultError(_model_base.Model): +class DefaultError(_Model): """DefaultError. :ivar code: Required. @@ -41,7 +40,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class ErrorInRange(_model_base.Model): +class ErrorInRange(_Model): """ErrorInRange. :ivar code: Required. @@ -74,7 +73,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class NotFoundError(_model_base.Model): +class NotFoundError(_Model): """NotFoundError. :ivar code: Required. @@ -107,7 +106,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class Standard4XXError(_model_base.Model): +class Standard4XXError(_Model): """Standard4XXError. :ivar code: Required. diff --git a/packages/typespec-python/test/azure/generated/routes/routes/_client.py b/packages/typespec-python/test/azure/generated/routes/routes/_client.py index da429a05339..a7dbef56588 100644 --- a/packages/typespec-python/test/azure/generated/routes/routes/_client.py +++ b/packages/typespec-python/test/azure/generated/routes/routes/_client.py @@ -15,7 +15,7 @@ from azure.core.rest import HttpRequest, HttpResponse from ._configuration import RoutesClientConfiguration -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer from .operations import InInterfaceOperations, RoutesClientOperationsMixin from .pathparameters.operations import PathParametersOperations from .queryparameters.operations import QueryParametersOperations diff --git a/packages/typespec-python/test/azure/generated/routes/routes/_utils/__init__.py b/packages/typespec-python/test/azure/generated/routes/routes/_utils/__init__.py new file mode 100644 index 00000000000..8026245c2ab --- /dev/null +++ b/packages/typespec-python/test/azure/generated/routes/routes/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) Python Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/typespec-python/test/azure/generated/serialization-encoded-name-json/serialization/encodedname/json/_model_base.py b/packages/typespec-python/test/azure/generated/routes/routes/_utils/model_base.py similarity index 100% rename from packages/typespec-python/test/azure/generated/serialization-encoded-name-json/serialization/encodedname/json/_model_base.py rename to packages/typespec-python/test/azure/generated/routes/routes/_utils/model_base.py diff --git a/packages/typespec-python/test/azure/generated/serialization-encoded-name-json/serialization/encodedname/json/_serialization.py b/packages/typespec-python/test/azure/generated/routes/routes/_utils/serialization.py similarity index 100% rename from packages/typespec-python/test/azure/generated/serialization-encoded-name-json/serialization/encodedname/json/_serialization.py rename to packages/typespec-python/test/azure/generated/routes/routes/_utils/serialization.py diff --git a/packages/typespec-python/test/azure/generated/routes/routes/_utils/utils.py b/packages/typespec-python/test/azure/generated/routes/routes/_utils/utils.py new file mode 100644 index 00000000000..35c9c836f85 --- /dev/null +++ b/packages/typespec-python/test/azure/generated/routes/routes/_utils/utils.py @@ -0,0 +1,25 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) Python Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from abc import ABC +from typing import Generic, TYPE_CHECKING, TypeVar + +if TYPE_CHECKING: + from .serialization import Deserializer, Serializer + + +TClient = TypeVar("TClient") +TConfig = TypeVar("TConfig") + + +class ClientMixinABC(ABC, Generic[TClient, TConfig]): + """DO NOT use this class. It is for internal typing use only.""" + + _client: TClient + _config: TConfig + _serialize: "Serializer" + _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/azure/generated/routes/routes/_vendor.py b/packages/typespec-python/test/azure/generated/routes/routes/_vendor.py deleted file mode 100644 index c3e13092d70..00000000000 --- a/packages/typespec-python/test/azure/generated/routes/routes/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) Python Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import RoutesClientConfiguration - -if TYPE_CHECKING: - from azure.core import PipelineClient - - from ._serialization import Deserializer, Serializer - - -class RoutesClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "PipelineClient" - _config: RoutesClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/azure/generated/routes/routes/aio/_client.py b/packages/typespec-python/test/azure/generated/routes/routes/aio/_client.py index ab04bf06600..11dc1b6d639 100644 --- a/packages/typespec-python/test/azure/generated/routes/routes/aio/_client.py +++ b/packages/typespec-python/test/azure/generated/routes/routes/aio/_client.py @@ -14,7 +14,7 @@ from azure.core.pipeline import policies from azure.core.rest import AsyncHttpResponse, HttpRequest -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ..pathparameters.aio.operations import PathParametersOperations from ..queryparameters.aio.operations import QueryParametersOperations from ._configuration import RoutesClientConfiguration diff --git a/packages/typespec-python/test/azure/generated/routes/routes/aio/_vendor.py b/packages/typespec-python/test/azure/generated/routes/routes/aio/_vendor.py deleted file mode 100644 index 8c4c586c7b5..00000000000 --- a/packages/typespec-python/test/azure/generated/routes/routes/aio/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) Python Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import RoutesClientConfiguration - -if TYPE_CHECKING: - from azure.core import AsyncPipelineClient - - from .._serialization import Deserializer, Serializer - - -class RoutesClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "AsyncPipelineClient" - _config: RoutesClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/azure/generated/routes/routes/aio/operations/_operations.py b/packages/typespec-python/test/azure/generated/routes/routes/aio/operations/_operations.py index 456d60119b2..ee96017800a 100644 --- a/packages/typespec-python/test/azure/generated/routes/routes/aio/operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/routes/routes/aio/operations/_operations.py @@ -22,10 +22,10 @@ from azure.core.rest import AsyncHttpResponse, HttpRequest from azure.core.tracing.decorator_async import distributed_trace_async -from ..._serialization import Deserializer, Serializer +from ..._utils.serialization import Deserializer, Serializer +from ..._utils.utils import ClientMixinABC from ...operations._operations import build_in_interface_fixed_request, build_routes_fixed_request from .._configuration import RoutesClientConfiguration -from .._vendor import RoutesClientMixinABC T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, AsyncHttpResponse], T, Dict[str, Any]], Any]] @@ -93,7 +93,7 @@ async def fixed(self, **kwargs: Any) -> None: return cls(pipeline_response, None, {}) # type: ignore -class RoutesClientOperationsMixin(RoutesClientMixinABC): +class RoutesClientOperationsMixin(ClientMixinABC[AsyncPipelineClient, RoutesClientConfiguration]): @distributed_trace_async async def fixed(self, **kwargs: Any) -> None: diff --git a/packages/typespec-python/test/azure/generated/routes/routes/operations/_operations.py b/packages/typespec-python/test/azure/generated/routes/routes/operations/_operations.py index 97c7493d184..2f90c3a5c89 100644 --- a/packages/typespec-python/test/azure/generated/routes/routes/operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/routes/routes/operations/_operations.py @@ -22,8 +22,8 @@ from azure.core.tracing.decorator import distributed_trace from .._configuration import RoutesClientConfiguration -from .._serialization import Deserializer, Serializer -from .._vendor import RoutesClientMixinABC +from .._utils.serialization import Deserializer, Serializer +from .._utils.utils import ClientMixinABC T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] @@ -108,7 +108,7 @@ def fixed(self, **kwargs: Any) -> None: # pylint: disable=inconsistent-return-s return cls(pipeline_response, None, {}) # type: ignore -class RoutesClientOperationsMixin(RoutesClientMixinABC): +class RoutesClientOperationsMixin(ClientMixinABC[PipelineClient, RoutesClientConfiguration]): @distributed_trace def fixed(self, **kwargs: Any) -> None: # pylint: disable=inconsistent-return-statements diff --git a/packages/typespec-python/test/azure/generated/routes/routes/pathparameters/aio/operations/_operations.py b/packages/typespec-python/test/azure/generated/routes/routes/pathparameters/aio/operations/_operations.py index b10353f0cb0..3d88a0f3c4b 100644 --- a/packages/typespec-python/test/azure/generated/routes/routes/pathparameters/aio/operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/routes/routes/pathparameters/aio/operations/_operations.py @@ -21,7 +21,7 @@ from azure.core.rest import AsyncHttpResponse, HttpRequest from azure.core.tracing.decorator_async import distributed_trace_async -from ...._serialization import Deserializer, Serializer +from ...._utils.serialization import Deserializer, Serializer from ....aio._configuration import RoutesClientConfiguration from ...labelexpansion.aio.operations._operations import PathParametersLabelExpansionOperations from ...matrixexpansion.aio.operations._operations import PathParametersMatrixExpansionOperations diff --git a/packages/typespec-python/test/azure/generated/routes/routes/pathparameters/labelexpansion/aio/operations/_operations.py b/packages/typespec-python/test/azure/generated/routes/routes/pathparameters/labelexpansion/aio/operations/_operations.py index 04e02bd6daa..6811b57dede 100644 --- a/packages/typespec-python/test/azure/generated/routes/routes/pathparameters/labelexpansion/aio/operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/routes/routes/pathparameters/labelexpansion/aio/operations/_operations.py @@ -7,7 +7,7 @@ # -------------------------------------------------------------------------- from azure.core import AsyncPipelineClient -from ....._serialization import Deserializer, Serializer +from ....._utils.serialization import Deserializer, Serializer from .....aio._configuration import RoutesClientConfiguration from ...explode.aio.operations._operations import PathParametersLabelExpansionExplodeOperations from ...standard.aio.operations._operations import PathParametersLabelExpansionStandardOperations diff --git a/packages/typespec-python/test/azure/generated/routes/routes/pathparameters/labelexpansion/explode/aio/operations/_operations.py b/packages/typespec-python/test/azure/generated/routes/routes/pathparameters/labelexpansion/explode/aio/operations/_operations.py index d0b2d609f33..c7fc2c6913f 100644 --- a/packages/typespec-python/test/azure/generated/routes/routes/pathparameters/labelexpansion/explode/aio/operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/routes/routes/pathparameters/labelexpansion/explode/aio/operations/_operations.py @@ -21,7 +21,7 @@ from azure.core.rest import AsyncHttpResponse, HttpRequest from azure.core.tracing.decorator_async import distributed_trace_async -from ......_serialization import Deserializer, Serializer +from ......_utils.serialization import Deserializer, Serializer from ......aio._configuration import RoutesClientConfiguration from ...operations._operations import ( build_path_parameters_label_expansion_explode_array_request, diff --git a/packages/typespec-python/test/azure/generated/routes/routes/pathparameters/labelexpansion/explode/operations/_operations.py b/packages/typespec-python/test/azure/generated/routes/routes/pathparameters/labelexpansion/explode/operations/_operations.py index cd366211bf5..6eb3dcafea0 100644 --- a/packages/typespec-python/test/azure/generated/routes/routes/pathparameters/labelexpansion/explode/operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/routes/routes/pathparameters/labelexpansion/explode/operations/_operations.py @@ -22,7 +22,7 @@ from azure.core.tracing.decorator import distributed_trace from ....._configuration import RoutesClientConfiguration -from ....._serialization import Deserializer, Serializer +from ....._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/typespec-python/test/azure/generated/routes/routes/pathparameters/labelexpansion/operations/_operations.py b/packages/typespec-python/test/azure/generated/routes/routes/pathparameters/labelexpansion/operations/_operations.py index f714b5a0a4f..562a6a6331b 100644 --- a/packages/typespec-python/test/azure/generated/routes/routes/pathparameters/labelexpansion/operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/routes/routes/pathparameters/labelexpansion/operations/_operations.py @@ -8,7 +8,7 @@ from azure.core import PipelineClient from ...._configuration import RoutesClientConfiguration -from ...._serialization import Deserializer, Serializer +from ...._utils.serialization import Deserializer, Serializer from ..explode.operations._operations import PathParametersLabelExpansionExplodeOperations from ..standard.operations._operations import PathParametersLabelExpansionStandardOperations diff --git a/packages/typespec-python/test/azure/generated/routes/routes/pathparameters/labelexpansion/standard/aio/operations/_operations.py b/packages/typespec-python/test/azure/generated/routes/routes/pathparameters/labelexpansion/standard/aio/operations/_operations.py index 97cd1488ebb..74b7c1e76ff 100644 --- a/packages/typespec-python/test/azure/generated/routes/routes/pathparameters/labelexpansion/standard/aio/operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/routes/routes/pathparameters/labelexpansion/standard/aio/operations/_operations.py @@ -21,7 +21,7 @@ from azure.core.rest import AsyncHttpResponse, HttpRequest from azure.core.tracing.decorator_async import distributed_trace_async -from ......_serialization import Deserializer, Serializer +from ......_utils.serialization import Deserializer, Serializer from ......aio._configuration import RoutesClientConfiguration from ...operations._operations import ( build_path_parameters_label_expansion_standard_array_request, diff --git a/packages/typespec-python/test/azure/generated/routes/routes/pathparameters/labelexpansion/standard/operations/_operations.py b/packages/typespec-python/test/azure/generated/routes/routes/pathparameters/labelexpansion/standard/operations/_operations.py index 396a5eb0a9e..87768cdc139 100644 --- a/packages/typespec-python/test/azure/generated/routes/routes/pathparameters/labelexpansion/standard/operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/routes/routes/pathparameters/labelexpansion/standard/operations/_operations.py @@ -22,7 +22,7 @@ from azure.core.tracing.decorator import distributed_trace from ....._configuration import RoutesClientConfiguration -from ....._serialization import Deserializer, Serializer +from ....._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/typespec-python/test/azure/generated/routes/routes/pathparameters/matrixexpansion/aio/operations/_operations.py b/packages/typespec-python/test/azure/generated/routes/routes/pathparameters/matrixexpansion/aio/operations/_operations.py index 5b747f1cca1..f5ffc5e9498 100644 --- a/packages/typespec-python/test/azure/generated/routes/routes/pathparameters/matrixexpansion/aio/operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/routes/routes/pathparameters/matrixexpansion/aio/operations/_operations.py @@ -7,7 +7,7 @@ # -------------------------------------------------------------------------- from azure.core import AsyncPipelineClient -from ....._serialization import Deserializer, Serializer +from ....._utils.serialization import Deserializer, Serializer from .....aio._configuration import RoutesClientConfiguration from ...explode.aio.operations._operations import PathParametersMatrixExpansionExplodeOperations from ...standard.aio.operations._operations import PathParametersMatrixExpansionStandardOperations diff --git a/packages/typespec-python/test/azure/generated/routes/routes/pathparameters/matrixexpansion/explode/aio/operations/_operations.py b/packages/typespec-python/test/azure/generated/routes/routes/pathparameters/matrixexpansion/explode/aio/operations/_operations.py index 52ee8a5143b..0173ae6cf87 100644 --- a/packages/typespec-python/test/azure/generated/routes/routes/pathparameters/matrixexpansion/explode/aio/operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/routes/routes/pathparameters/matrixexpansion/explode/aio/operations/_operations.py @@ -21,7 +21,7 @@ from azure.core.rest import AsyncHttpResponse, HttpRequest from azure.core.tracing.decorator_async import distributed_trace_async -from ......_serialization import Deserializer, Serializer +from ......_utils.serialization import Deserializer, Serializer from ......aio._configuration import RoutesClientConfiguration from ...operations._operations import ( build_path_parameters_matrix_expansion_explode_array_request, diff --git a/packages/typespec-python/test/azure/generated/routes/routes/pathparameters/matrixexpansion/explode/operations/_operations.py b/packages/typespec-python/test/azure/generated/routes/routes/pathparameters/matrixexpansion/explode/operations/_operations.py index b2b35e67885..b0e8b7bc085 100644 --- a/packages/typespec-python/test/azure/generated/routes/routes/pathparameters/matrixexpansion/explode/operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/routes/routes/pathparameters/matrixexpansion/explode/operations/_operations.py @@ -22,7 +22,7 @@ from azure.core.tracing.decorator import distributed_trace from ....._configuration import RoutesClientConfiguration -from ....._serialization import Deserializer, Serializer +from ....._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/typespec-python/test/azure/generated/routes/routes/pathparameters/matrixexpansion/operations/_operations.py b/packages/typespec-python/test/azure/generated/routes/routes/pathparameters/matrixexpansion/operations/_operations.py index bcbe3d09bd5..c037168a2f7 100644 --- a/packages/typespec-python/test/azure/generated/routes/routes/pathparameters/matrixexpansion/operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/routes/routes/pathparameters/matrixexpansion/operations/_operations.py @@ -8,7 +8,7 @@ from azure.core import PipelineClient from ...._configuration import RoutesClientConfiguration -from ...._serialization import Deserializer, Serializer +from ...._utils.serialization import Deserializer, Serializer from ..explode.operations._operations import PathParametersMatrixExpansionExplodeOperations from ..standard.operations._operations import PathParametersMatrixExpansionStandardOperations diff --git a/packages/typespec-python/test/azure/generated/routes/routes/pathparameters/matrixexpansion/standard/aio/operations/_operations.py b/packages/typespec-python/test/azure/generated/routes/routes/pathparameters/matrixexpansion/standard/aio/operations/_operations.py index 486719916a4..5a700848e8e 100644 --- a/packages/typespec-python/test/azure/generated/routes/routes/pathparameters/matrixexpansion/standard/aio/operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/routes/routes/pathparameters/matrixexpansion/standard/aio/operations/_operations.py @@ -21,7 +21,7 @@ from azure.core.rest import AsyncHttpResponse, HttpRequest from azure.core.tracing.decorator_async import distributed_trace_async -from ......_serialization import Deserializer, Serializer +from ......_utils.serialization import Deserializer, Serializer from ......aio._configuration import RoutesClientConfiguration from ...operations._operations import ( build_path_parameters_matrix_expansion_standard_array_request, diff --git a/packages/typespec-python/test/azure/generated/routes/routes/pathparameters/matrixexpansion/standard/operations/_operations.py b/packages/typespec-python/test/azure/generated/routes/routes/pathparameters/matrixexpansion/standard/operations/_operations.py index 7b909aaebfc..dfca0c0c6a4 100644 --- a/packages/typespec-python/test/azure/generated/routes/routes/pathparameters/matrixexpansion/standard/operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/routes/routes/pathparameters/matrixexpansion/standard/operations/_operations.py @@ -22,7 +22,7 @@ from azure.core.tracing.decorator import distributed_trace from ....._configuration import RoutesClientConfiguration -from ....._serialization import Deserializer, Serializer +from ....._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/typespec-python/test/azure/generated/routes/routes/pathparameters/operations/_operations.py b/packages/typespec-python/test/azure/generated/routes/routes/pathparameters/operations/_operations.py index a5ada4988ca..b407416cc86 100644 --- a/packages/typespec-python/test/azure/generated/routes/routes/pathparameters/operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/routes/routes/pathparameters/operations/_operations.py @@ -22,7 +22,7 @@ from azure.core.tracing.decorator import distributed_trace from ..._configuration import RoutesClientConfiguration -from ..._serialization import Deserializer, Serializer +from ..._utils.serialization import Deserializer, Serializer from ..labelexpansion.operations._operations import PathParametersLabelExpansionOperations from ..matrixexpansion.operations._operations import PathParametersMatrixExpansionOperations from ..pathexpansion.operations._operations import PathParametersPathExpansionOperations diff --git a/packages/typespec-python/test/azure/generated/routes/routes/pathparameters/pathexpansion/aio/operations/_operations.py b/packages/typespec-python/test/azure/generated/routes/routes/pathparameters/pathexpansion/aio/operations/_operations.py index 9e37a7bc57e..6ff52ca99ce 100644 --- a/packages/typespec-python/test/azure/generated/routes/routes/pathparameters/pathexpansion/aio/operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/routes/routes/pathparameters/pathexpansion/aio/operations/_operations.py @@ -7,7 +7,7 @@ # -------------------------------------------------------------------------- from azure.core import AsyncPipelineClient -from ....._serialization import Deserializer, Serializer +from ....._utils.serialization import Deserializer, Serializer from .....aio._configuration import RoutesClientConfiguration from ...explode.aio.operations._operations import PathParametersPathExpansionExplodeOperations from ...standard.aio.operations._operations import PathParametersPathExpansionStandardOperations diff --git a/packages/typespec-python/test/azure/generated/routes/routes/pathparameters/pathexpansion/explode/aio/operations/_operations.py b/packages/typespec-python/test/azure/generated/routes/routes/pathparameters/pathexpansion/explode/aio/operations/_operations.py index 3772bb9ac59..212b20fb9e6 100644 --- a/packages/typespec-python/test/azure/generated/routes/routes/pathparameters/pathexpansion/explode/aio/operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/routes/routes/pathparameters/pathexpansion/explode/aio/operations/_operations.py @@ -21,7 +21,7 @@ from azure.core.rest import AsyncHttpResponse, HttpRequest from azure.core.tracing.decorator_async import distributed_trace_async -from ......_serialization import Deserializer, Serializer +from ......_utils.serialization import Deserializer, Serializer from ......aio._configuration import RoutesClientConfiguration from ...operations._operations import ( build_path_parameters_path_expansion_explode_array_request, diff --git a/packages/typespec-python/test/azure/generated/routes/routes/pathparameters/pathexpansion/explode/operations/_operations.py b/packages/typespec-python/test/azure/generated/routes/routes/pathparameters/pathexpansion/explode/operations/_operations.py index 8ad044b0df2..7cd08376b8b 100644 --- a/packages/typespec-python/test/azure/generated/routes/routes/pathparameters/pathexpansion/explode/operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/routes/routes/pathparameters/pathexpansion/explode/operations/_operations.py @@ -22,7 +22,7 @@ from azure.core.tracing.decorator import distributed_trace from ....._configuration import RoutesClientConfiguration -from ....._serialization import Deserializer, Serializer +from ....._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/typespec-python/test/azure/generated/routes/routes/pathparameters/pathexpansion/operations/_operations.py b/packages/typespec-python/test/azure/generated/routes/routes/pathparameters/pathexpansion/operations/_operations.py index bfc9d1b6cf4..691d4e0a2bd 100644 --- a/packages/typespec-python/test/azure/generated/routes/routes/pathparameters/pathexpansion/operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/routes/routes/pathparameters/pathexpansion/operations/_operations.py @@ -8,7 +8,7 @@ from azure.core import PipelineClient from ...._configuration import RoutesClientConfiguration -from ...._serialization import Deserializer, Serializer +from ...._utils.serialization import Deserializer, Serializer from ..explode.operations._operations import PathParametersPathExpansionExplodeOperations from ..standard.operations._operations import PathParametersPathExpansionStandardOperations diff --git a/packages/typespec-python/test/azure/generated/routes/routes/pathparameters/pathexpansion/standard/aio/operations/_operations.py b/packages/typespec-python/test/azure/generated/routes/routes/pathparameters/pathexpansion/standard/aio/operations/_operations.py index 9f914ab16f3..b034d7ab6c1 100644 --- a/packages/typespec-python/test/azure/generated/routes/routes/pathparameters/pathexpansion/standard/aio/operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/routes/routes/pathparameters/pathexpansion/standard/aio/operations/_operations.py @@ -21,7 +21,7 @@ from azure.core.rest import AsyncHttpResponse, HttpRequest from azure.core.tracing.decorator_async import distributed_trace_async -from ......_serialization import Deserializer, Serializer +from ......_utils.serialization import Deserializer, Serializer from ......aio._configuration import RoutesClientConfiguration from ...operations._operations import ( build_path_parameters_path_expansion_standard_array_request, diff --git a/packages/typespec-python/test/azure/generated/routes/routes/pathparameters/pathexpansion/standard/operations/_operations.py b/packages/typespec-python/test/azure/generated/routes/routes/pathparameters/pathexpansion/standard/operations/_operations.py index 631a00f6024..ac66ee43b67 100644 --- a/packages/typespec-python/test/azure/generated/routes/routes/pathparameters/pathexpansion/standard/operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/routes/routes/pathparameters/pathexpansion/standard/operations/_operations.py @@ -22,7 +22,7 @@ from azure.core.tracing.decorator import distributed_trace from ....._configuration import RoutesClientConfiguration -from ....._serialization import Deserializer, Serializer +from ....._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/typespec-python/test/azure/generated/routes/routes/pathparameters/reservedexpansion/aio/operations/_operations.py b/packages/typespec-python/test/azure/generated/routes/routes/pathparameters/reservedexpansion/aio/operations/_operations.py index 9b8e4014347..5558493713a 100644 --- a/packages/typespec-python/test/azure/generated/routes/routes/pathparameters/reservedexpansion/aio/operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/routes/routes/pathparameters/reservedexpansion/aio/operations/_operations.py @@ -21,7 +21,7 @@ from azure.core.rest import AsyncHttpResponse, HttpRequest from azure.core.tracing.decorator_async import distributed_trace_async -from ....._serialization import Deserializer, Serializer +from ....._utils.serialization import Deserializer, Serializer from .....aio._configuration import RoutesClientConfiguration from ...operations._operations import ( build_path_parameters_reserved_expansion_annotation_request, diff --git a/packages/typespec-python/test/azure/generated/routes/routes/pathparameters/reservedexpansion/operations/_operations.py b/packages/typespec-python/test/azure/generated/routes/routes/pathparameters/reservedexpansion/operations/_operations.py index ecb806c8247..f9d1dad18b6 100644 --- a/packages/typespec-python/test/azure/generated/routes/routes/pathparameters/reservedexpansion/operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/routes/routes/pathparameters/reservedexpansion/operations/_operations.py @@ -22,7 +22,7 @@ from azure.core.tracing.decorator import distributed_trace from ...._configuration import RoutesClientConfiguration -from ...._serialization import Deserializer, Serializer +from ...._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/typespec-python/test/azure/generated/routes/routes/pathparameters/simpleexpansion/aio/operations/_operations.py b/packages/typespec-python/test/azure/generated/routes/routes/pathparameters/simpleexpansion/aio/operations/_operations.py index 415fb2ee17a..fbd5793bed9 100644 --- a/packages/typespec-python/test/azure/generated/routes/routes/pathparameters/simpleexpansion/aio/operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/routes/routes/pathparameters/simpleexpansion/aio/operations/_operations.py @@ -7,7 +7,7 @@ # -------------------------------------------------------------------------- from azure.core import AsyncPipelineClient -from ....._serialization import Deserializer, Serializer +from ....._utils.serialization import Deserializer, Serializer from .....aio._configuration import RoutesClientConfiguration from ...explode.aio.operations._operations import PathParametersSimpleExpansionExplodeOperations from ...standard.aio.operations._operations import PathParametersSimpleExpansionStandardOperations diff --git a/packages/typespec-python/test/azure/generated/routes/routes/pathparameters/simpleexpansion/explode/aio/operations/_operations.py b/packages/typespec-python/test/azure/generated/routes/routes/pathparameters/simpleexpansion/explode/aio/operations/_operations.py index d1c7f5a32d5..21f0c50040b 100644 --- a/packages/typespec-python/test/azure/generated/routes/routes/pathparameters/simpleexpansion/explode/aio/operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/routes/routes/pathparameters/simpleexpansion/explode/aio/operations/_operations.py @@ -21,7 +21,7 @@ from azure.core.rest import AsyncHttpResponse, HttpRequest from azure.core.tracing.decorator_async import distributed_trace_async -from ......_serialization import Deserializer, Serializer +from ......_utils.serialization import Deserializer, Serializer from ......aio._configuration import RoutesClientConfiguration from ...operations._operations import ( build_path_parameters_simple_expansion_explode_array_request, diff --git a/packages/typespec-python/test/azure/generated/routes/routes/pathparameters/simpleexpansion/explode/operations/_operations.py b/packages/typespec-python/test/azure/generated/routes/routes/pathparameters/simpleexpansion/explode/operations/_operations.py index 8626e52c5d5..4237c91d67d 100644 --- a/packages/typespec-python/test/azure/generated/routes/routes/pathparameters/simpleexpansion/explode/operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/routes/routes/pathparameters/simpleexpansion/explode/operations/_operations.py @@ -22,7 +22,7 @@ from azure.core.tracing.decorator import distributed_trace from ....._configuration import RoutesClientConfiguration -from ....._serialization import Deserializer, Serializer +from ....._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/typespec-python/test/azure/generated/routes/routes/pathparameters/simpleexpansion/operations/_operations.py b/packages/typespec-python/test/azure/generated/routes/routes/pathparameters/simpleexpansion/operations/_operations.py index 6ecc41d56f4..d02c660c7a7 100644 --- a/packages/typespec-python/test/azure/generated/routes/routes/pathparameters/simpleexpansion/operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/routes/routes/pathparameters/simpleexpansion/operations/_operations.py @@ -8,7 +8,7 @@ from azure.core import PipelineClient from ...._configuration import RoutesClientConfiguration -from ...._serialization import Deserializer, Serializer +from ...._utils.serialization import Deserializer, Serializer from ..explode.operations._operations import PathParametersSimpleExpansionExplodeOperations from ..standard.operations._operations import PathParametersSimpleExpansionStandardOperations diff --git a/packages/typespec-python/test/azure/generated/routes/routes/pathparameters/simpleexpansion/standard/aio/operations/_operations.py b/packages/typespec-python/test/azure/generated/routes/routes/pathparameters/simpleexpansion/standard/aio/operations/_operations.py index a67bfdd1a24..04ee961c41e 100644 --- a/packages/typespec-python/test/azure/generated/routes/routes/pathparameters/simpleexpansion/standard/aio/operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/routes/routes/pathparameters/simpleexpansion/standard/aio/operations/_operations.py @@ -21,7 +21,7 @@ from azure.core.rest import AsyncHttpResponse, HttpRequest from azure.core.tracing.decorator_async import distributed_trace_async -from ......_serialization import Deserializer, Serializer +from ......_utils.serialization import Deserializer, Serializer from ......aio._configuration import RoutesClientConfiguration from ...operations._operations import ( build_path_parameters_simple_expansion_standard_array_request, diff --git a/packages/typespec-python/test/azure/generated/routes/routes/pathparameters/simpleexpansion/standard/operations/_operations.py b/packages/typespec-python/test/azure/generated/routes/routes/pathparameters/simpleexpansion/standard/operations/_operations.py index 9525e9b9edd..134b7bcf63f 100644 --- a/packages/typespec-python/test/azure/generated/routes/routes/pathparameters/simpleexpansion/standard/operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/routes/routes/pathparameters/simpleexpansion/standard/operations/_operations.py @@ -22,7 +22,7 @@ from azure.core.tracing.decorator import distributed_trace from ....._configuration import RoutesClientConfiguration -from ....._serialization import Deserializer, Serializer +from ....._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/typespec-python/test/azure/generated/routes/routes/queryparameters/aio/operations/_operations.py b/packages/typespec-python/test/azure/generated/routes/routes/queryparameters/aio/operations/_operations.py index cbac90d3c3c..5a25ed42ac7 100644 --- a/packages/typespec-python/test/azure/generated/routes/routes/queryparameters/aio/operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/routes/routes/queryparameters/aio/operations/_operations.py @@ -21,7 +21,7 @@ from azure.core.rest import AsyncHttpResponse, HttpRequest from azure.core.tracing.decorator_async import distributed_trace_async -from ...._serialization import Deserializer, Serializer +from ...._utils.serialization import Deserializer, Serializer from ....aio._configuration import RoutesClientConfiguration from ...operations._operations import ( build_query_parameters_annotation_only_request, diff --git a/packages/typespec-python/test/azure/generated/routes/routes/queryparameters/operations/_operations.py b/packages/typespec-python/test/azure/generated/routes/routes/queryparameters/operations/_operations.py index 79c21c61b15..4842d982397 100644 --- a/packages/typespec-python/test/azure/generated/routes/routes/queryparameters/operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/routes/routes/queryparameters/operations/_operations.py @@ -23,7 +23,7 @@ from azure.core.utils import case_insensitive_dict from ..._configuration import RoutesClientConfiguration -from ..._serialization import Deserializer, Serializer +from ..._utils.serialization import Deserializer, Serializer from ..querycontinuation.operations._operations import QueryParametersQueryContinuationOperations from ..queryexpansion.operations._operations import QueryParametersQueryExpansionOperations diff --git a/packages/typespec-python/test/azure/generated/routes/routes/queryparameters/querycontinuation/aio/operations/_operations.py b/packages/typespec-python/test/azure/generated/routes/routes/queryparameters/querycontinuation/aio/operations/_operations.py index 5cfd81ed40f..7f8c24efccb 100644 --- a/packages/typespec-python/test/azure/generated/routes/routes/queryparameters/querycontinuation/aio/operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/routes/routes/queryparameters/querycontinuation/aio/operations/_operations.py @@ -7,7 +7,7 @@ # -------------------------------------------------------------------------- from azure.core import AsyncPipelineClient -from ....._serialization import Deserializer, Serializer +from ....._utils.serialization import Deserializer, Serializer from .....aio._configuration import RoutesClientConfiguration from ...explode.aio.operations._operations import QueryParametersQueryContinuationExplodeOperations from ...standard.aio.operations._operations import QueryParametersQueryContinuationStandardOperations diff --git a/packages/typespec-python/test/azure/generated/routes/routes/queryparameters/querycontinuation/explode/aio/operations/_operations.py b/packages/typespec-python/test/azure/generated/routes/routes/queryparameters/querycontinuation/explode/aio/operations/_operations.py index ff072dca1a0..b520f39db99 100644 --- a/packages/typespec-python/test/azure/generated/routes/routes/queryparameters/querycontinuation/explode/aio/operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/routes/routes/queryparameters/querycontinuation/explode/aio/operations/_operations.py @@ -21,7 +21,7 @@ from azure.core.rest import AsyncHttpResponse, HttpRequest from azure.core.tracing.decorator_async import distributed_trace_async -from ......_serialization import Deserializer, Serializer +from ......_utils.serialization import Deserializer, Serializer from ......aio._configuration import RoutesClientConfiguration from ...operations._operations import ( build_query_parameters_query_continuation_explode_array_request, diff --git a/packages/typespec-python/test/azure/generated/routes/routes/queryparameters/querycontinuation/explode/operations/_operations.py b/packages/typespec-python/test/azure/generated/routes/routes/queryparameters/querycontinuation/explode/operations/_operations.py index 37470cdccaf..065d4dce5e6 100644 --- a/packages/typespec-python/test/azure/generated/routes/routes/queryparameters/querycontinuation/explode/operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/routes/routes/queryparameters/querycontinuation/explode/operations/_operations.py @@ -23,7 +23,7 @@ from azure.core.utils import case_insensitive_dict from ....._configuration import RoutesClientConfiguration -from ....._serialization import Deserializer, Serializer +from ....._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/typespec-python/test/azure/generated/routes/routes/queryparameters/querycontinuation/operations/_operations.py b/packages/typespec-python/test/azure/generated/routes/routes/queryparameters/querycontinuation/operations/_operations.py index 1be220a2d55..4f7d447dda4 100644 --- a/packages/typespec-python/test/azure/generated/routes/routes/queryparameters/querycontinuation/operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/routes/routes/queryparameters/querycontinuation/operations/_operations.py @@ -8,7 +8,7 @@ from azure.core import PipelineClient from ...._configuration import RoutesClientConfiguration -from ...._serialization import Deserializer, Serializer +from ...._utils.serialization import Deserializer, Serializer from ..explode.operations._operations import QueryParametersQueryContinuationExplodeOperations from ..standard.operations._operations import QueryParametersQueryContinuationStandardOperations diff --git a/packages/typespec-python/test/azure/generated/routes/routes/queryparameters/querycontinuation/standard/aio/operations/_operations.py b/packages/typespec-python/test/azure/generated/routes/routes/queryparameters/querycontinuation/standard/aio/operations/_operations.py index dc9d757a120..bab0bd63f71 100644 --- a/packages/typespec-python/test/azure/generated/routes/routes/queryparameters/querycontinuation/standard/aio/operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/routes/routes/queryparameters/querycontinuation/standard/aio/operations/_operations.py @@ -21,7 +21,7 @@ from azure.core.rest import AsyncHttpResponse, HttpRequest from azure.core.tracing.decorator_async import distributed_trace_async -from ......_serialization import Deserializer, Serializer +from ......_utils.serialization import Deserializer, Serializer from ......aio._configuration import RoutesClientConfiguration from ...operations._operations import ( build_query_parameters_query_continuation_standard_array_request, diff --git a/packages/typespec-python/test/azure/generated/routes/routes/queryparameters/querycontinuation/standard/operations/_operations.py b/packages/typespec-python/test/azure/generated/routes/routes/queryparameters/querycontinuation/standard/operations/_operations.py index 53d051bc5a9..3a98a6029cf 100644 --- a/packages/typespec-python/test/azure/generated/routes/routes/queryparameters/querycontinuation/standard/operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/routes/routes/queryparameters/querycontinuation/standard/operations/_operations.py @@ -23,7 +23,7 @@ from azure.core.utils import case_insensitive_dict from ....._configuration import RoutesClientConfiguration -from ....._serialization import Deserializer, Serializer +from ....._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/typespec-python/test/azure/generated/routes/routes/queryparameters/queryexpansion/aio/operations/_operations.py b/packages/typespec-python/test/azure/generated/routes/routes/queryparameters/queryexpansion/aio/operations/_operations.py index fc3aba35f11..db7fc2c3f9f 100644 --- a/packages/typespec-python/test/azure/generated/routes/routes/queryparameters/queryexpansion/aio/operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/routes/routes/queryparameters/queryexpansion/aio/operations/_operations.py @@ -7,7 +7,7 @@ # -------------------------------------------------------------------------- from azure.core import AsyncPipelineClient -from ....._serialization import Deserializer, Serializer +from ....._utils.serialization import Deserializer, Serializer from .....aio._configuration import RoutesClientConfiguration from ...explode.aio.operations._operations import QueryParametersQueryExpansionExplodeOperations from ...standard.aio.operations._operations import QueryParametersQueryExpansionStandardOperations diff --git a/packages/typespec-python/test/azure/generated/routes/routes/queryparameters/queryexpansion/explode/aio/operations/_operations.py b/packages/typespec-python/test/azure/generated/routes/routes/queryparameters/queryexpansion/explode/aio/operations/_operations.py index 30fe888a1b8..b141c4d611f 100644 --- a/packages/typespec-python/test/azure/generated/routes/routes/queryparameters/queryexpansion/explode/aio/operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/routes/routes/queryparameters/queryexpansion/explode/aio/operations/_operations.py @@ -21,7 +21,7 @@ from azure.core.rest import AsyncHttpResponse, HttpRequest from azure.core.tracing.decorator_async import distributed_trace_async -from ......_serialization import Deserializer, Serializer +from ......_utils.serialization import Deserializer, Serializer from ......aio._configuration import RoutesClientConfiguration from ...operations._operations import ( build_query_parameters_query_expansion_explode_array_request, diff --git a/packages/typespec-python/test/azure/generated/routes/routes/queryparameters/queryexpansion/explode/operations/_operations.py b/packages/typespec-python/test/azure/generated/routes/routes/queryparameters/queryexpansion/explode/operations/_operations.py index 944a9b72ab9..854d564ed68 100644 --- a/packages/typespec-python/test/azure/generated/routes/routes/queryparameters/queryexpansion/explode/operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/routes/routes/queryparameters/queryexpansion/explode/operations/_operations.py @@ -23,7 +23,7 @@ from azure.core.utils import case_insensitive_dict from ....._configuration import RoutesClientConfiguration -from ....._serialization import Deserializer, Serializer +from ....._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/typespec-python/test/azure/generated/routes/routes/queryparameters/queryexpansion/operations/_operations.py b/packages/typespec-python/test/azure/generated/routes/routes/queryparameters/queryexpansion/operations/_operations.py index 1b07e28ec71..1a65400787f 100644 --- a/packages/typespec-python/test/azure/generated/routes/routes/queryparameters/queryexpansion/operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/routes/routes/queryparameters/queryexpansion/operations/_operations.py @@ -8,7 +8,7 @@ from azure.core import PipelineClient from ...._configuration import RoutesClientConfiguration -from ...._serialization import Deserializer, Serializer +from ...._utils.serialization import Deserializer, Serializer from ..explode.operations._operations import QueryParametersQueryExpansionExplodeOperations from ..standard.operations._operations import QueryParametersQueryExpansionStandardOperations diff --git a/packages/typespec-python/test/azure/generated/routes/routes/queryparameters/queryexpansion/standard/aio/operations/_operations.py b/packages/typespec-python/test/azure/generated/routes/routes/queryparameters/queryexpansion/standard/aio/operations/_operations.py index 20388b534e5..644bae07996 100644 --- a/packages/typespec-python/test/azure/generated/routes/routes/queryparameters/queryexpansion/standard/aio/operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/routes/routes/queryparameters/queryexpansion/standard/aio/operations/_operations.py @@ -21,7 +21,7 @@ from azure.core.rest import AsyncHttpResponse, HttpRequest from azure.core.tracing.decorator_async import distributed_trace_async -from ......_serialization import Deserializer, Serializer +from ......_utils.serialization import Deserializer, Serializer from ......aio._configuration import RoutesClientConfiguration from ...operations._operations import ( build_query_parameters_query_expansion_standard_array_request, diff --git a/packages/typespec-python/test/azure/generated/routes/routes/queryparameters/queryexpansion/standard/operations/_operations.py b/packages/typespec-python/test/azure/generated/routes/routes/queryparameters/queryexpansion/standard/operations/_operations.py index a5152bc0a47..2346e2c9ce8 100644 --- a/packages/typespec-python/test/azure/generated/routes/routes/queryparameters/queryexpansion/standard/operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/routes/routes/queryparameters/queryexpansion/standard/operations/_operations.py @@ -23,7 +23,7 @@ from azure.core.utils import case_insensitive_dict from ....._configuration import RoutesClientConfiguration -from ....._serialization import Deserializer, Serializer +from ....._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/typespec-python/test/azure/generated/serialization-encoded-name-json/serialization/encodedname/json/_client.py b/packages/typespec-python/test/azure/generated/serialization-encoded-name-json/serialization/encodedname/json/_client.py index 4f2658a5560..f64752e55ef 100644 --- a/packages/typespec-python/test/azure/generated/serialization-encoded-name-json/serialization/encodedname/json/_client.py +++ b/packages/typespec-python/test/azure/generated/serialization-encoded-name-json/serialization/encodedname/json/_client.py @@ -15,7 +15,7 @@ from azure.core.rest import HttpRequest, HttpResponse from ._configuration import JsonClientConfiguration -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer from .operations import PropertyOperations diff --git a/packages/typespec-python/test/azure/generated/serialization-encoded-name-json/serialization/encodedname/json/_utils/__init__.py b/packages/typespec-python/test/azure/generated/serialization-encoded-name-json/serialization/encodedname/json/_utils/__init__.py new file mode 100644 index 00000000000..8026245c2ab --- /dev/null +++ b/packages/typespec-python/test/azure/generated/serialization-encoded-name-json/serialization/encodedname/json/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) Python Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/typespec-python/test/azure/generated/server-endpoint-not-defined/server/endpoint/notdefined/_model_base.py b/packages/typespec-python/test/azure/generated/serialization-encoded-name-json/serialization/encodedname/json/_utils/model_base.py similarity index 100% rename from packages/typespec-python/test/azure/generated/server-endpoint-not-defined/server/endpoint/notdefined/_model_base.py rename to packages/typespec-python/test/azure/generated/serialization-encoded-name-json/serialization/encodedname/json/_utils/model_base.py diff --git a/packages/typespec-python/test/azure/generated/server-endpoint-not-defined/server/endpoint/notdefined/_serialization.py b/packages/typespec-python/test/azure/generated/serialization-encoded-name-json/serialization/encodedname/json/_utils/serialization.py similarity index 100% rename from packages/typespec-python/test/azure/generated/server-endpoint-not-defined/server/endpoint/notdefined/_serialization.py rename to packages/typespec-python/test/azure/generated/serialization-encoded-name-json/serialization/encodedname/json/_utils/serialization.py diff --git a/packages/typespec-python/test/azure/generated/serialization-encoded-name-json/serialization/encodedname/json/aio/_client.py b/packages/typespec-python/test/azure/generated/serialization-encoded-name-json/serialization/encodedname/json/aio/_client.py index 1ed6033fd0a..2501049d665 100644 --- a/packages/typespec-python/test/azure/generated/serialization-encoded-name-json/serialization/encodedname/json/aio/_client.py +++ b/packages/typespec-python/test/azure/generated/serialization-encoded-name-json/serialization/encodedname/json/aio/_client.py @@ -14,7 +14,7 @@ from azure.core.pipeline import policies from azure.core.rest import AsyncHttpResponse, HttpRequest -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import JsonClientConfiguration from .operations import PropertyOperations diff --git a/packages/typespec-python/test/azure/generated/serialization-encoded-name-json/serialization/encodedname/json/aio/operations/_operations.py b/packages/typespec-python/test/azure/generated/serialization-encoded-name-json/serialization/encodedname/json/aio/operations/_operations.py index 55c3153d952..778f3a397dc 100644 --- a/packages/typespec-python/test/azure/generated/serialization-encoded-name-json/serialization/encodedname/json/aio/operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/serialization-encoded-name-json/serialization/encodedname/json/aio/operations/_operations.py @@ -27,8 +27,8 @@ from azure.core.utils import case_insensitive_dict from ... import models as _models -from ..._model_base import SdkJSONEncoder, _deserialize -from ..._serialization import Deserializer, Serializer +from ..._utils.model_base import SdkJSONEncoder, _deserialize +from ..._utils.serialization import Deserializer, Serializer from ...operations._operations import build_property_get_request, build_property_send_request from .._configuration import JsonClientConfiguration diff --git a/packages/typespec-python/test/azure/generated/serialization-encoded-name-json/serialization/encodedname/json/models/_models.py b/packages/typespec-python/test/azure/generated/serialization-encoded-name-json/serialization/encodedname/json/models/_models.py index ee9a4c7d00a..0cab838a628 100644 --- a/packages/typespec-python/test/azure/generated/serialization-encoded-name-json/serialization/encodedname/json/models/_models.py +++ b/packages/typespec-python/test/azure/generated/serialization-encoded-name-json/serialization/encodedname/json/models/_models.py @@ -9,11 +9,10 @@ from typing import Any, Mapping, overload -from .. import _model_base -from .._model_base import rest_field +from .._utils.model_base import Model as _Model, rest_field -class JsonEncodedNameModel(_model_base.Model): +class JsonEncodedNameModel(_Model): """JsonEncodedNameModel. :ivar default_name: Pass in true. Required. diff --git a/packages/typespec-python/test/azure/generated/serialization-encoded-name-json/serialization/encodedname/json/operations/_operations.py b/packages/typespec-python/test/azure/generated/serialization-encoded-name-json/serialization/encodedname/json/operations/_operations.py index f8b4c24b9b9..63d1fe5dfb9 100644 --- a/packages/typespec-python/test/azure/generated/serialization-encoded-name-json/serialization/encodedname/json/operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/serialization-encoded-name-json/serialization/encodedname/json/operations/_operations.py @@ -28,8 +28,8 @@ from .. import models as _models from .._configuration import JsonClientConfiguration -from .._model_base import SdkJSONEncoder, _deserialize -from .._serialization import Deserializer, Serializer +from .._utils.model_base import SdkJSONEncoder, _deserialize +from .._utils.serialization import Deserializer, Serializer JSON = MutableMapping[str, Any] T = TypeVar("T") diff --git a/packages/typespec-python/test/azure/generated/server-endpoint-not-defined/server/endpoint/notdefined/_client.py b/packages/typespec-python/test/azure/generated/server-endpoint-not-defined/server/endpoint/notdefined/_client.py index a87b07dc829..ad7833095f5 100644 --- a/packages/typespec-python/test/azure/generated/server-endpoint-not-defined/server/endpoint/notdefined/_client.py +++ b/packages/typespec-python/test/azure/generated/server-endpoint-not-defined/server/endpoint/notdefined/_client.py @@ -16,7 +16,7 @@ from ._configuration import NotDefinedClientConfiguration from ._operations import NotDefinedClientOperationsMixin -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer class NotDefinedClient(NotDefinedClientOperationsMixin): # pylint: disable=client-accepts-api-version-keyword diff --git a/packages/typespec-python/test/azure/generated/server-endpoint-not-defined/server/endpoint/notdefined/_operations/_operations.py b/packages/typespec-python/test/azure/generated/server-endpoint-not-defined/server/endpoint/notdefined/_operations/_operations.py index ffcba25439b..3c2f25f6f3c 100644 --- a/packages/typespec-python/test/azure/generated/server-endpoint-not-defined/server/endpoint/notdefined/_operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/server-endpoint-not-defined/server/endpoint/notdefined/_operations/_operations.py @@ -8,6 +8,7 @@ from collections.abc import MutableMapping from typing import Any, Callable, Dict, Optional, TypeVar +from azure.core import PipelineClient from azure.core.exceptions import ( ClientAuthenticationError, HttpResponseError, @@ -20,8 +21,9 @@ from azure.core.rest import HttpRequest, HttpResponse from azure.core.tracing.decorator import distributed_trace -from .._serialization import Serializer -from .._vendor import NotDefinedClientMixinABC +from .._configuration import NotDefinedClientConfiguration +from .._utils.serialization import Serializer +from .._utils.utils import ClientMixinABC T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] @@ -37,7 +39,7 @@ def build_not_defined_valid_request(**kwargs: Any) -> HttpRequest: return HttpRequest(method="HEAD", url=_url, **kwargs) -class NotDefinedClientOperationsMixin(NotDefinedClientMixinABC): +class NotDefinedClientOperationsMixin(ClientMixinABC[PipelineClient, NotDefinedClientConfiguration]): @distributed_trace def valid(self, **kwargs: Any) -> bool: diff --git a/packages/typespec-python/test/azure/generated/server-endpoint-not-defined/server/endpoint/notdefined/_utils/__init__.py b/packages/typespec-python/test/azure/generated/server-endpoint-not-defined/server/endpoint/notdefined/_utils/__init__.py new file mode 100644 index 00000000000..8026245c2ab --- /dev/null +++ b/packages/typespec-python/test/azure/generated/server-endpoint-not-defined/server/endpoint/notdefined/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) Python Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/typespec-python/test/azure/generated/server-path-multiple/server/path/multiple/_model_base.py b/packages/typespec-python/test/azure/generated/server-endpoint-not-defined/server/endpoint/notdefined/_utils/model_base.py similarity index 100% rename from packages/typespec-python/test/azure/generated/server-path-multiple/server/path/multiple/_model_base.py rename to packages/typespec-python/test/azure/generated/server-endpoint-not-defined/server/endpoint/notdefined/_utils/model_base.py diff --git a/packages/typespec-python/test/azure/generated/server-path-multiple/server/path/multiple/_serialization.py b/packages/typespec-python/test/azure/generated/server-endpoint-not-defined/server/endpoint/notdefined/_utils/serialization.py similarity index 100% rename from packages/typespec-python/test/azure/generated/server-path-multiple/server/path/multiple/_serialization.py rename to packages/typespec-python/test/azure/generated/server-endpoint-not-defined/server/endpoint/notdefined/_utils/serialization.py diff --git a/packages/typespec-python/test/azure/generated/server-endpoint-not-defined/server/endpoint/notdefined/_utils/utils.py b/packages/typespec-python/test/azure/generated/server-endpoint-not-defined/server/endpoint/notdefined/_utils/utils.py new file mode 100644 index 00000000000..35c9c836f85 --- /dev/null +++ b/packages/typespec-python/test/azure/generated/server-endpoint-not-defined/server/endpoint/notdefined/_utils/utils.py @@ -0,0 +1,25 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) Python Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from abc import ABC +from typing import Generic, TYPE_CHECKING, TypeVar + +if TYPE_CHECKING: + from .serialization import Deserializer, Serializer + + +TClient = TypeVar("TClient") +TConfig = TypeVar("TConfig") + + +class ClientMixinABC(ABC, Generic[TClient, TConfig]): + """DO NOT use this class. It is for internal typing use only.""" + + _client: TClient + _config: TConfig + _serialize: "Serializer" + _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/azure/generated/server-endpoint-not-defined/server/endpoint/notdefined/_vendor.py b/packages/typespec-python/test/azure/generated/server-endpoint-not-defined/server/endpoint/notdefined/_vendor.py deleted file mode 100644 index 09fb220b63e..00000000000 --- a/packages/typespec-python/test/azure/generated/server-endpoint-not-defined/server/endpoint/notdefined/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) Python Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import NotDefinedClientConfiguration - -if TYPE_CHECKING: - from azure.core import PipelineClient - - from ._serialization import Deserializer, Serializer - - -class NotDefinedClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "PipelineClient" - _config: NotDefinedClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/azure/generated/server-endpoint-not-defined/server/endpoint/notdefined/aio/_client.py b/packages/typespec-python/test/azure/generated/server-endpoint-not-defined/server/endpoint/notdefined/aio/_client.py index 33735ca9a65..b718cbb77ea 100644 --- a/packages/typespec-python/test/azure/generated/server-endpoint-not-defined/server/endpoint/notdefined/aio/_client.py +++ b/packages/typespec-python/test/azure/generated/server-endpoint-not-defined/server/endpoint/notdefined/aio/_client.py @@ -14,7 +14,7 @@ from azure.core.pipeline import policies from azure.core.rest import AsyncHttpResponse, HttpRequest -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import NotDefinedClientConfiguration from ._operations import NotDefinedClientOperationsMixin diff --git a/packages/typespec-python/test/azure/generated/server-endpoint-not-defined/server/endpoint/notdefined/aio/_operations/_operations.py b/packages/typespec-python/test/azure/generated/server-endpoint-not-defined/server/endpoint/notdefined/aio/_operations/_operations.py index 6d8202082ea..c2bcfc08cee 100644 --- a/packages/typespec-python/test/azure/generated/server-endpoint-not-defined/server/endpoint/notdefined/aio/_operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/server-endpoint-not-defined/server/endpoint/notdefined/aio/_operations/_operations.py @@ -9,6 +9,7 @@ from collections.abc import MutableMapping from typing import Any, Callable, Dict, Optional, TypeVar +from azure.core import AsyncPipelineClient from azure.core.exceptions import ( ClientAuthenticationError, HttpResponseError, @@ -22,13 +23,14 @@ from azure.core.tracing.decorator_async import distributed_trace_async from ..._operations._operations import build_not_defined_valid_request -from .._vendor import NotDefinedClientMixinABC +from ..._utils.utils import ClientMixinABC +from .._configuration import NotDefinedClientConfiguration T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, AsyncHttpResponse], T, Dict[str, Any]], Any]] -class NotDefinedClientOperationsMixin(NotDefinedClientMixinABC): +class NotDefinedClientOperationsMixin(ClientMixinABC[AsyncPipelineClient, NotDefinedClientConfiguration]): @distributed_trace_async async def valid(self, **kwargs: Any) -> bool: diff --git a/packages/typespec-python/test/azure/generated/server-endpoint-not-defined/server/endpoint/notdefined/aio/_vendor.py b/packages/typespec-python/test/azure/generated/server-endpoint-not-defined/server/endpoint/notdefined/aio/_vendor.py deleted file mode 100644 index 19564973a65..00000000000 --- a/packages/typespec-python/test/azure/generated/server-endpoint-not-defined/server/endpoint/notdefined/aio/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) Python Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import NotDefinedClientConfiguration - -if TYPE_CHECKING: - from azure.core import AsyncPipelineClient - - from .._serialization import Deserializer, Serializer - - -class NotDefinedClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "AsyncPipelineClient" - _config: NotDefinedClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/azure/generated/server-path-multiple/server/path/multiple/_client.py b/packages/typespec-python/test/azure/generated/server-path-multiple/server/path/multiple/_client.py index c54f1df6813..b36bcf409c9 100644 --- a/packages/typespec-python/test/azure/generated/server-path-multiple/server/path/multiple/_client.py +++ b/packages/typespec-python/test/azure/generated/server-path-multiple/server/path/multiple/_client.py @@ -16,7 +16,7 @@ from ._configuration import MultipleClientConfiguration from ._operations import MultipleClientOperationsMixin -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer class MultipleClient(MultipleClientOperationsMixin): diff --git a/packages/typespec-python/test/azure/generated/server-path-multiple/server/path/multiple/_operations/_operations.py b/packages/typespec-python/test/azure/generated/server-path-multiple/server/path/multiple/_operations/_operations.py index 0db508a8a40..238039dbbf4 100644 --- a/packages/typespec-python/test/azure/generated/server-path-multiple/server/path/multiple/_operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/server-path-multiple/server/path/multiple/_operations/_operations.py @@ -8,6 +8,7 @@ from collections.abc import MutableMapping from typing import Any, Callable, Dict, Optional, TypeVar +from azure.core import PipelineClient from azure.core.exceptions import ( ClientAuthenticationError, HttpResponseError, @@ -20,8 +21,9 @@ from azure.core.rest import HttpRequest, HttpResponse from azure.core.tracing.decorator import distributed_trace -from .._serialization import Serializer -from .._vendor import MultipleClientMixinABC +from .._configuration import MultipleClientConfiguration +from .._utils.serialization import Serializer +from .._utils.utils import ClientMixinABC T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] @@ -51,7 +53,7 @@ def build_multiple_with_operation_path_param_request( # pylint: disable=name-to return HttpRequest(method="GET", url=_url, **kwargs) -class MultipleClientOperationsMixin(MultipleClientMixinABC): +class MultipleClientOperationsMixin(ClientMixinABC[PipelineClient, MultipleClientConfiguration]): @distributed_trace def no_operation_params(self, **kwargs: Any) -> None: # pylint: disable=inconsistent-return-statements diff --git a/packages/typespec-python/test/azure/generated/server-path-multiple/server/path/multiple/_utils/__init__.py b/packages/typespec-python/test/azure/generated/server-path-multiple/server/path/multiple/_utils/__init__.py new file mode 100644 index 00000000000..8026245c2ab --- /dev/null +++ b/packages/typespec-python/test/azure/generated/server-path-multiple/server/path/multiple/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) Python Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/typespec-python/test/azure/generated/server-path-single/server/path/single/_model_base.py b/packages/typespec-python/test/azure/generated/server-path-multiple/server/path/multiple/_utils/model_base.py similarity index 100% rename from packages/typespec-python/test/azure/generated/server-path-single/server/path/single/_model_base.py rename to packages/typespec-python/test/azure/generated/server-path-multiple/server/path/multiple/_utils/model_base.py diff --git a/packages/typespec-python/test/azure/generated/server-path-single/server/path/single/_serialization.py b/packages/typespec-python/test/azure/generated/server-path-multiple/server/path/multiple/_utils/serialization.py similarity index 100% rename from packages/typespec-python/test/azure/generated/server-path-single/server/path/single/_serialization.py rename to packages/typespec-python/test/azure/generated/server-path-multiple/server/path/multiple/_utils/serialization.py diff --git a/packages/typespec-python/test/azure/generated/server-path-multiple/server/path/multiple/_utils/utils.py b/packages/typespec-python/test/azure/generated/server-path-multiple/server/path/multiple/_utils/utils.py new file mode 100644 index 00000000000..35c9c836f85 --- /dev/null +++ b/packages/typespec-python/test/azure/generated/server-path-multiple/server/path/multiple/_utils/utils.py @@ -0,0 +1,25 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) Python Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from abc import ABC +from typing import Generic, TYPE_CHECKING, TypeVar + +if TYPE_CHECKING: + from .serialization import Deserializer, Serializer + + +TClient = TypeVar("TClient") +TConfig = TypeVar("TConfig") + + +class ClientMixinABC(ABC, Generic[TClient, TConfig]): + """DO NOT use this class. It is for internal typing use only.""" + + _client: TClient + _config: TConfig + _serialize: "Serializer" + _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/azure/generated/server-path-multiple/server/path/multiple/_vendor.py b/packages/typespec-python/test/azure/generated/server-path-multiple/server/path/multiple/_vendor.py deleted file mode 100644 index 1fc0062beca..00000000000 --- a/packages/typespec-python/test/azure/generated/server-path-multiple/server/path/multiple/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) Python Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import MultipleClientConfiguration - -if TYPE_CHECKING: - from azure.core import PipelineClient - - from ._serialization import Deserializer, Serializer - - -class MultipleClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "PipelineClient" - _config: MultipleClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/azure/generated/server-path-multiple/server/path/multiple/aio/_client.py b/packages/typespec-python/test/azure/generated/server-path-multiple/server/path/multiple/aio/_client.py index a9923f2faca..dfb746a93d6 100644 --- a/packages/typespec-python/test/azure/generated/server-path-multiple/server/path/multiple/aio/_client.py +++ b/packages/typespec-python/test/azure/generated/server-path-multiple/server/path/multiple/aio/_client.py @@ -14,7 +14,7 @@ from azure.core.pipeline import policies from azure.core.rest import AsyncHttpResponse, HttpRequest -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import MultipleClientConfiguration from ._operations import MultipleClientOperationsMixin diff --git a/packages/typespec-python/test/azure/generated/server-path-multiple/server/path/multiple/aio/_operations/_operations.py b/packages/typespec-python/test/azure/generated/server-path-multiple/server/path/multiple/aio/_operations/_operations.py index 5a187d2212d..d1ebd16ce46 100644 --- a/packages/typespec-python/test/azure/generated/server-path-multiple/server/path/multiple/aio/_operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/server-path-multiple/server/path/multiple/aio/_operations/_operations.py @@ -9,6 +9,7 @@ from collections.abc import MutableMapping from typing import Any, Callable, Dict, Optional, TypeVar +from azure.core import AsyncPipelineClient from azure.core.exceptions import ( ClientAuthenticationError, HttpResponseError, @@ -25,13 +26,14 @@ build_multiple_no_operation_params_request, build_multiple_with_operation_path_param_request, ) -from .._vendor import MultipleClientMixinABC +from ..._utils.utils import ClientMixinABC +from .._configuration import MultipleClientConfiguration T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, AsyncHttpResponse], T, Dict[str, Any]], Any]] -class MultipleClientOperationsMixin(MultipleClientMixinABC): +class MultipleClientOperationsMixin(ClientMixinABC[AsyncPipelineClient, MultipleClientConfiguration]): @distributed_trace_async async def no_operation_params(self, **kwargs: Any) -> None: diff --git a/packages/typespec-python/test/azure/generated/server-path-multiple/server/path/multiple/aio/_vendor.py b/packages/typespec-python/test/azure/generated/server-path-multiple/server/path/multiple/aio/_vendor.py deleted file mode 100644 index 4396d4e7625..00000000000 --- a/packages/typespec-python/test/azure/generated/server-path-multiple/server/path/multiple/aio/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) Python Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import MultipleClientConfiguration - -if TYPE_CHECKING: - from azure.core import AsyncPipelineClient - - from .._serialization import Deserializer, Serializer - - -class MultipleClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "AsyncPipelineClient" - _config: MultipleClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/azure/generated/server-path-single/server/path/single/_client.py b/packages/typespec-python/test/azure/generated/server-path-single/server/path/single/_client.py index 3fe450e840a..2a6874b8ac2 100644 --- a/packages/typespec-python/test/azure/generated/server-path-single/server/path/single/_client.py +++ b/packages/typespec-python/test/azure/generated/server-path-single/server/path/single/_client.py @@ -16,7 +16,7 @@ from ._configuration import SingleClientConfiguration from ._operations import SingleClientOperationsMixin -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer class SingleClient(SingleClientOperationsMixin): # pylint: disable=client-accepts-api-version-keyword diff --git a/packages/typespec-python/test/azure/generated/server-path-single/server/path/single/_operations/_operations.py b/packages/typespec-python/test/azure/generated/server-path-single/server/path/single/_operations/_operations.py index f0ade74a7b5..173f9b67176 100644 --- a/packages/typespec-python/test/azure/generated/server-path-single/server/path/single/_operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/server-path-single/server/path/single/_operations/_operations.py @@ -8,6 +8,7 @@ from collections.abc import MutableMapping from typing import Any, Callable, Dict, Optional, TypeVar +from azure.core import PipelineClient from azure.core.exceptions import ( ClientAuthenticationError, HttpResponseError, @@ -20,8 +21,9 @@ from azure.core.rest import HttpRequest, HttpResponse from azure.core.tracing.decorator import distributed_trace -from .._serialization import Serializer -from .._vendor import SingleClientMixinABC +from .._configuration import SingleClientConfiguration +from .._utils.serialization import Serializer +from .._utils.utils import ClientMixinABC T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] @@ -37,7 +39,7 @@ def build_single_my_op_request(**kwargs: Any) -> HttpRequest: return HttpRequest(method="HEAD", url=_url, **kwargs) -class SingleClientOperationsMixin(SingleClientMixinABC): +class SingleClientOperationsMixin(ClientMixinABC[PipelineClient, SingleClientConfiguration]): @distributed_trace def my_op(self, **kwargs: Any) -> bool: diff --git a/packages/typespec-python/test/azure/generated/server-path-single/server/path/single/_utils/__init__.py b/packages/typespec-python/test/azure/generated/server-path-single/server/path/single/_utils/__init__.py new file mode 100644 index 00000000000..8026245c2ab --- /dev/null +++ b/packages/typespec-python/test/azure/generated/server-path-single/server/path/single/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) Python Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/typespec-python/test/azure/generated/server-versions-not-versioned/server/versions/notversioned/_model_base.py b/packages/typespec-python/test/azure/generated/server-path-single/server/path/single/_utils/model_base.py similarity index 100% rename from packages/typespec-python/test/azure/generated/server-versions-not-versioned/server/versions/notversioned/_model_base.py rename to packages/typespec-python/test/azure/generated/server-path-single/server/path/single/_utils/model_base.py diff --git a/packages/typespec-python/test/azure/generated/server-versions-not-versioned/server/versions/notversioned/_serialization.py b/packages/typespec-python/test/azure/generated/server-path-single/server/path/single/_utils/serialization.py similarity index 100% rename from packages/typespec-python/test/azure/generated/server-versions-not-versioned/server/versions/notversioned/_serialization.py rename to packages/typespec-python/test/azure/generated/server-path-single/server/path/single/_utils/serialization.py diff --git a/packages/typespec-python/test/azure/generated/server-path-single/server/path/single/_utils/utils.py b/packages/typespec-python/test/azure/generated/server-path-single/server/path/single/_utils/utils.py new file mode 100644 index 00000000000..35c9c836f85 --- /dev/null +++ b/packages/typespec-python/test/azure/generated/server-path-single/server/path/single/_utils/utils.py @@ -0,0 +1,25 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) Python Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from abc import ABC +from typing import Generic, TYPE_CHECKING, TypeVar + +if TYPE_CHECKING: + from .serialization import Deserializer, Serializer + + +TClient = TypeVar("TClient") +TConfig = TypeVar("TConfig") + + +class ClientMixinABC(ABC, Generic[TClient, TConfig]): + """DO NOT use this class. It is for internal typing use only.""" + + _client: TClient + _config: TConfig + _serialize: "Serializer" + _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/azure/generated/server-path-single/server/path/single/_vendor.py b/packages/typespec-python/test/azure/generated/server-path-single/server/path/single/_vendor.py deleted file mode 100644 index 35434b3b12e..00000000000 --- a/packages/typespec-python/test/azure/generated/server-path-single/server/path/single/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) Python Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import SingleClientConfiguration - -if TYPE_CHECKING: - from azure.core import PipelineClient - - from ._serialization import Deserializer, Serializer - - -class SingleClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "PipelineClient" - _config: SingleClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/azure/generated/server-path-single/server/path/single/aio/_client.py b/packages/typespec-python/test/azure/generated/server-path-single/server/path/single/aio/_client.py index 9d1bc1ea470..bf7588c81b6 100644 --- a/packages/typespec-python/test/azure/generated/server-path-single/server/path/single/aio/_client.py +++ b/packages/typespec-python/test/azure/generated/server-path-single/server/path/single/aio/_client.py @@ -14,7 +14,7 @@ from azure.core.pipeline import policies from azure.core.rest import AsyncHttpResponse, HttpRequest -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import SingleClientConfiguration from ._operations import SingleClientOperationsMixin diff --git a/packages/typespec-python/test/azure/generated/server-path-single/server/path/single/aio/_operations/_operations.py b/packages/typespec-python/test/azure/generated/server-path-single/server/path/single/aio/_operations/_operations.py index a86f3afe037..f4826ec0425 100644 --- a/packages/typespec-python/test/azure/generated/server-path-single/server/path/single/aio/_operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/server-path-single/server/path/single/aio/_operations/_operations.py @@ -9,6 +9,7 @@ from collections.abc import MutableMapping from typing import Any, Callable, Dict, Optional, TypeVar +from azure.core import AsyncPipelineClient from azure.core.exceptions import ( ClientAuthenticationError, HttpResponseError, @@ -22,13 +23,14 @@ from azure.core.tracing.decorator_async import distributed_trace_async from ..._operations._operations import build_single_my_op_request -from .._vendor import SingleClientMixinABC +from ..._utils.utils import ClientMixinABC +from .._configuration import SingleClientConfiguration T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, AsyncHttpResponse], T, Dict[str, Any]], Any]] -class SingleClientOperationsMixin(SingleClientMixinABC): +class SingleClientOperationsMixin(ClientMixinABC[AsyncPipelineClient, SingleClientConfiguration]): @distributed_trace_async async def my_op(self, **kwargs: Any) -> bool: diff --git a/packages/typespec-python/test/azure/generated/server-path-single/server/path/single/aio/_vendor.py b/packages/typespec-python/test/azure/generated/server-path-single/server/path/single/aio/_vendor.py deleted file mode 100644 index ffa3fe62028..00000000000 --- a/packages/typespec-python/test/azure/generated/server-path-single/server/path/single/aio/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) Python Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import SingleClientConfiguration - -if TYPE_CHECKING: - from azure.core import AsyncPipelineClient - - from .._serialization import Deserializer, Serializer - - -class SingleClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "AsyncPipelineClient" - _config: SingleClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/azure/generated/server-versions-not-versioned/server/versions/notversioned/_client.py b/packages/typespec-python/test/azure/generated/server-versions-not-versioned/server/versions/notversioned/_client.py index 9c5efda7204..0f2b7bf7235 100644 --- a/packages/typespec-python/test/azure/generated/server-versions-not-versioned/server/versions/notversioned/_client.py +++ b/packages/typespec-python/test/azure/generated/server-versions-not-versioned/server/versions/notversioned/_client.py @@ -16,7 +16,7 @@ from ._configuration import NotVersionedClientConfiguration from ._operations import NotVersionedClientOperationsMixin -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer class NotVersionedClient(NotVersionedClientOperationsMixin): # pylint: disable=client-accepts-api-version-keyword diff --git a/packages/typespec-python/test/azure/generated/server-versions-not-versioned/server/versions/notversioned/_operations/_operations.py b/packages/typespec-python/test/azure/generated/server-versions-not-versioned/server/versions/notversioned/_operations/_operations.py index 25a72451bb1..6643de479cd 100644 --- a/packages/typespec-python/test/azure/generated/server-versions-not-versioned/server/versions/notversioned/_operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/server-versions-not-versioned/server/versions/notversioned/_operations/_operations.py @@ -8,6 +8,7 @@ from collections.abc import MutableMapping from typing import Any, Callable, Dict, Optional, TypeVar +from azure.core import PipelineClient from azure.core.exceptions import ( ClientAuthenticationError, HttpResponseError, @@ -21,8 +22,9 @@ from azure.core.tracing.decorator import distributed_trace from azure.core.utils import case_insensitive_dict -from .._serialization import Serializer -from .._vendor import NotVersionedClientMixinABC +from .._configuration import NotVersionedClientConfiguration +from .._utils.serialization import Serializer +from .._utils.utils import ClientMixinABC T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] @@ -66,7 +68,7 @@ def build_not_versioned_with_path_api_version_request( # pylint: disable=name-t return HttpRequest(method="HEAD", url=_url, **kwargs) -class NotVersionedClientOperationsMixin(NotVersionedClientMixinABC): +class NotVersionedClientOperationsMixin(ClientMixinABC[PipelineClient, NotVersionedClientConfiguration]): @distributed_trace def without_api_version(self, **kwargs: Any) -> bool: diff --git a/packages/typespec-python/test/azure/generated/server-versions-not-versioned/server/versions/notversioned/_utils/__init__.py b/packages/typespec-python/test/azure/generated/server-versions-not-versioned/server/versions/notversioned/_utils/__init__.py new file mode 100644 index 00000000000..8026245c2ab --- /dev/null +++ b/packages/typespec-python/test/azure/generated/server-versions-not-versioned/server/versions/notversioned/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) Python Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/typespec-python/test/azure/generated/server-versions-versioned/server/versions/versioned/_model_base.py b/packages/typespec-python/test/azure/generated/server-versions-not-versioned/server/versions/notversioned/_utils/model_base.py similarity index 100% rename from packages/typespec-python/test/azure/generated/server-versions-versioned/server/versions/versioned/_model_base.py rename to packages/typespec-python/test/azure/generated/server-versions-not-versioned/server/versions/notversioned/_utils/model_base.py diff --git a/packages/typespec-python/test/azure/generated/server-versions-versioned/server/versions/versioned/_serialization.py b/packages/typespec-python/test/azure/generated/server-versions-not-versioned/server/versions/notversioned/_utils/serialization.py similarity index 100% rename from packages/typespec-python/test/azure/generated/server-versions-versioned/server/versions/versioned/_serialization.py rename to packages/typespec-python/test/azure/generated/server-versions-not-versioned/server/versions/notversioned/_utils/serialization.py diff --git a/packages/typespec-python/test/azure/generated/server-versions-not-versioned/server/versions/notversioned/_utils/utils.py b/packages/typespec-python/test/azure/generated/server-versions-not-versioned/server/versions/notversioned/_utils/utils.py new file mode 100644 index 00000000000..35c9c836f85 --- /dev/null +++ b/packages/typespec-python/test/azure/generated/server-versions-not-versioned/server/versions/notversioned/_utils/utils.py @@ -0,0 +1,25 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) Python Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from abc import ABC +from typing import Generic, TYPE_CHECKING, TypeVar + +if TYPE_CHECKING: + from .serialization import Deserializer, Serializer + + +TClient = TypeVar("TClient") +TConfig = TypeVar("TConfig") + + +class ClientMixinABC(ABC, Generic[TClient, TConfig]): + """DO NOT use this class. It is for internal typing use only.""" + + _client: TClient + _config: TConfig + _serialize: "Serializer" + _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/azure/generated/server-versions-not-versioned/server/versions/notversioned/_vendor.py b/packages/typespec-python/test/azure/generated/server-versions-not-versioned/server/versions/notversioned/_vendor.py deleted file mode 100644 index 224bf8d1e3a..00000000000 --- a/packages/typespec-python/test/azure/generated/server-versions-not-versioned/server/versions/notversioned/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) Python Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import NotVersionedClientConfiguration - -if TYPE_CHECKING: - from azure.core import PipelineClient - - from ._serialization import Deserializer, Serializer - - -class NotVersionedClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "PipelineClient" - _config: NotVersionedClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/azure/generated/server-versions-not-versioned/server/versions/notversioned/aio/_client.py b/packages/typespec-python/test/azure/generated/server-versions-not-versioned/server/versions/notversioned/aio/_client.py index a602a17098e..cd0e4c86017 100644 --- a/packages/typespec-python/test/azure/generated/server-versions-not-versioned/server/versions/notversioned/aio/_client.py +++ b/packages/typespec-python/test/azure/generated/server-versions-not-versioned/server/versions/notversioned/aio/_client.py @@ -14,7 +14,7 @@ from azure.core.pipeline import policies from azure.core.rest import AsyncHttpResponse, HttpRequest -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import NotVersionedClientConfiguration from ._operations import NotVersionedClientOperationsMixin diff --git a/packages/typespec-python/test/azure/generated/server-versions-not-versioned/server/versions/notversioned/aio/_operations/_operations.py b/packages/typespec-python/test/azure/generated/server-versions-not-versioned/server/versions/notversioned/aio/_operations/_operations.py index 8ce03616a06..3c67d42d69d 100644 --- a/packages/typespec-python/test/azure/generated/server-versions-not-versioned/server/versions/notversioned/aio/_operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/server-versions-not-versioned/server/versions/notversioned/aio/_operations/_operations.py @@ -9,6 +9,7 @@ from collections.abc import MutableMapping from typing import Any, Callable, Dict, Optional, TypeVar +from azure.core import AsyncPipelineClient from azure.core.exceptions import ( ClientAuthenticationError, HttpResponseError, @@ -26,13 +27,14 @@ build_not_versioned_with_query_api_version_request, build_not_versioned_without_api_version_request, ) -from .._vendor import NotVersionedClientMixinABC +from ..._utils.utils import ClientMixinABC +from .._configuration import NotVersionedClientConfiguration T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, AsyncHttpResponse], T, Dict[str, Any]], Any]] -class NotVersionedClientOperationsMixin(NotVersionedClientMixinABC): +class NotVersionedClientOperationsMixin(ClientMixinABC[AsyncPipelineClient, NotVersionedClientConfiguration]): @distributed_trace_async async def without_api_version(self, **kwargs: Any) -> bool: diff --git a/packages/typespec-python/test/azure/generated/server-versions-not-versioned/server/versions/notversioned/aio/_vendor.py b/packages/typespec-python/test/azure/generated/server-versions-not-versioned/server/versions/notversioned/aio/_vendor.py deleted file mode 100644 index 6c85bf15bcd..00000000000 --- a/packages/typespec-python/test/azure/generated/server-versions-not-versioned/server/versions/notversioned/aio/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) Python Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import NotVersionedClientConfiguration - -if TYPE_CHECKING: - from azure.core import AsyncPipelineClient - - from .._serialization import Deserializer, Serializer - - -class NotVersionedClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "AsyncPipelineClient" - _config: NotVersionedClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/azure/generated/server-versions-versioned/server/versions/versioned/_client.py b/packages/typespec-python/test/azure/generated/server-versions-versioned/server/versions/versioned/_client.py index 37b9c1307dd..39b36d17318 100644 --- a/packages/typespec-python/test/azure/generated/server-versions-versioned/server/versions/versioned/_client.py +++ b/packages/typespec-python/test/azure/generated/server-versions-versioned/server/versions/versioned/_client.py @@ -16,7 +16,7 @@ from ._configuration import VersionedClientConfiguration from ._operations import VersionedClientOperationsMixin -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer class VersionedClient(VersionedClientOperationsMixin): diff --git a/packages/typespec-python/test/azure/generated/server-versions-versioned/server/versions/versioned/_operations/_operations.py b/packages/typespec-python/test/azure/generated/server-versions-versioned/server/versions/versioned/_operations/_operations.py index 03b0469763c..ebd3653f1f7 100644 --- a/packages/typespec-python/test/azure/generated/server-versions-versioned/server/versions/versioned/_operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/server-versions-versioned/server/versions/versioned/_operations/_operations.py @@ -8,6 +8,7 @@ from collections.abc import MutableMapping from typing import Any, Callable, Dict, Optional, TypeVar +from azure.core import PipelineClient from azure.core.exceptions import ( ClientAuthenticationError, HttpResponseError, @@ -21,8 +22,9 @@ from azure.core.tracing.decorator import distributed_trace from azure.core.utils import case_insensitive_dict -from .._serialization import Serializer -from .._vendor import VersionedClientMixinABC +from .._configuration import VersionedClientConfiguration +from .._utils.serialization import Serializer +from .._utils.utils import ClientMixinABC T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] @@ -77,7 +79,7 @@ def build_versioned_with_query_old_api_version_request(**kwargs: Any) -> HttpReq return HttpRequest(method="HEAD", url=_url, params=_params, **kwargs) -class VersionedClientOperationsMixin(VersionedClientMixinABC): +class VersionedClientOperationsMixin(ClientMixinABC[PipelineClient, VersionedClientConfiguration]): @distributed_trace def without_api_version(self, **kwargs: Any) -> bool: diff --git a/packages/typespec-python/test/azure/generated/server-versions-versioned/server/versions/versioned/_utils/__init__.py b/packages/typespec-python/test/azure/generated/server-versions-versioned/server/versions/versioned/_utils/__init__.py new file mode 100644 index 00000000000..8026245c2ab --- /dev/null +++ b/packages/typespec-python/test/azure/generated/server-versions-versioned/server/versions/versioned/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) Python Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/typespec-python/test/azure/generated/special-headers-conditional-request/specialheaders/conditionalrequest/_model_base.py b/packages/typespec-python/test/azure/generated/server-versions-versioned/server/versions/versioned/_utils/model_base.py similarity index 100% rename from packages/typespec-python/test/azure/generated/special-headers-conditional-request/specialheaders/conditionalrequest/_model_base.py rename to packages/typespec-python/test/azure/generated/server-versions-versioned/server/versions/versioned/_utils/model_base.py diff --git a/packages/typespec-python/test/azure/generated/special-headers-conditional-request/specialheaders/conditionalrequest/_serialization.py b/packages/typespec-python/test/azure/generated/server-versions-versioned/server/versions/versioned/_utils/serialization.py similarity index 100% rename from packages/typespec-python/test/azure/generated/special-headers-conditional-request/specialheaders/conditionalrequest/_serialization.py rename to packages/typespec-python/test/azure/generated/server-versions-versioned/server/versions/versioned/_utils/serialization.py diff --git a/packages/typespec-python/test/azure/generated/server-versions-versioned/server/versions/versioned/_utils/utils.py b/packages/typespec-python/test/azure/generated/server-versions-versioned/server/versions/versioned/_utils/utils.py new file mode 100644 index 00000000000..35c9c836f85 --- /dev/null +++ b/packages/typespec-python/test/azure/generated/server-versions-versioned/server/versions/versioned/_utils/utils.py @@ -0,0 +1,25 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) Python Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from abc import ABC +from typing import Generic, TYPE_CHECKING, TypeVar + +if TYPE_CHECKING: + from .serialization import Deserializer, Serializer + + +TClient = TypeVar("TClient") +TConfig = TypeVar("TConfig") + + +class ClientMixinABC(ABC, Generic[TClient, TConfig]): + """DO NOT use this class. It is for internal typing use only.""" + + _client: TClient + _config: TConfig + _serialize: "Serializer" + _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/azure/generated/server-versions-versioned/server/versions/versioned/_vendor.py b/packages/typespec-python/test/azure/generated/server-versions-versioned/server/versions/versioned/_vendor.py deleted file mode 100644 index 851b7e6cfb4..00000000000 --- a/packages/typespec-python/test/azure/generated/server-versions-versioned/server/versions/versioned/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) Python Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import VersionedClientConfiguration - -if TYPE_CHECKING: - from azure.core import PipelineClient - - from ._serialization import Deserializer, Serializer - - -class VersionedClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "PipelineClient" - _config: VersionedClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/azure/generated/server-versions-versioned/server/versions/versioned/aio/_client.py b/packages/typespec-python/test/azure/generated/server-versions-versioned/server/versions/versioned/aio/_client.py index ecdfdd4817b..6d449ae351a 100644 --- a/packages/typespec-python/test/azure/generated/server-versions-versioned/server/versions/versioned/aio/_client.py +++ b/packages/typespec-python/test/azure/generated/server-versions-versioned/server/versions/versioned/aio/_client.py @@ -14,7 +14,7 @@ from azure.core.pipeline import policies from azure.core.rest import AsyncHttpResponse, HttpRequest -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import VersionedClientConfiguration from ._operations import VersionedClientOperationsMixin diff --git a/packages/typespec-python/test/azure/generated/server-versions-versioned/server/versions/versioned/aio/_operations/_operations.py b/packages/typespec-python/test/azure/generated/server-versions-versioned/server/versions/versioned/aio/_operations/_operations.py index bfbdf771dcf..4bf35cecf72 100644 --- a/packages/typespec-python/test/azure/generated/server-versions-versioned/server/versions/versioned/aio/_operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/server-versions-versioned/server/versions/versioned/aio/_operations/_operations.py @@ -9,6 +9,7 @@ from collections.abc import MutableMapping from typing import Any, Callable, Dict, Optional, TypeVar +from azure.core import AsyncPipelineClient from azure.core.exceptions import ( ClientAuthenticationError, HttpResponseError, @@ -27,13 +28,14 @@ build_versioned_with_query_old_api_version_request, build_versioned_without_api_version_request, ) -from .._vendor import VersionedClientMixinABC +from ..._utils.utils import ClientMixinABC +from .._configuration import VersionedClientConfiguration T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, AsyncHttpResponse], T, Dict[str, Any]], Any]] -class VersionedClientOperationsMixin(VersionedClientMixinABC): +class VersionedClientOperationsMixin(ClientMixinABC[AsyncPipelineClient, VersionedClientConfiguration]): @distributed_trace_async async def without_api_version(self, **kwargs: Any) -> bool: diff --git a/packages/typespec-python/test/azure/generated/server-versions-versioned/server/versions/versioned/aio/_vendor.py b/packages/typespec-python/test/azure/generated/server-versions-versioned/server/versions/versioned/aio/_vendor.py deleted file mode 100644 index e6d60001282..00000000000 --- a/packages/typespec-python/test/azure/generated/server-versions-versioned/server/versions/versioned/aio/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) Python Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import VersionedClientConfiguration - -if TYPE_CHECKING: - from azure.core import AsyncPipelineClient - - from .._serialization import Deserializer, Serializer - - -class VersionedClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "AsyncPipelineClient" - _config: VersionedClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/azure/generated/special-headers-conditional-request/specialheaders/conditionalrequest/_client.py b/packages/typespec-python/test/azure/generated/special-headers-conditional-request/specialheaders/conditionalrequest/_client.py index afd1d1e5198..3b7f8988cfa 100644 --- a/packages/typespec-python/test/azure/generated/special-headers-conditional-request/specialheaders/conditionalrequest/_client.py +++ b/packages/typespec-python/test/azure/generated/special-headers-conditional-request/specialheaders/conditionalrequest/_client.py @@ -16,7 +16,7 @@ from ._configuration import ConditionalRequestClientConfiguration from ._operations import ConditionalRequestClientOperationsMixin -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer class ConditionalRequestClient( diff --git a/packages/typespec-python/test/azure/generated/special-headers-conditional-request/specialheaders/conditionalrequest/_operations/_operations.py b/packages/typespec-python/test/azure/generated/special-headers-conditional-request/specialheaders/conditionalrequest/_operations/_operations.py index 3429852fc38..2505f4b414b 100644 --- a/packages/typespec-python/test/azure/generated/special-headers-conditional-request/specialheaders/conditionalrequest/_operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/special-headers-conditional-request/specialheaders/conditionalrequest/_operations/_operations.py @@ -9,7 +9,7 @@ import datetime from typing import Any, Callable, Dict, Optional, TypeVar -from azure.core import MatchConditions +from azure.core import MatchConditions, PipelineClient from azure.core.exceptions import ( ClientAuthenticationError, HttpResponseError, @@ -24,8 +24,9 @@ from azure.core.tracing.decorator import distributed_trace from azure.core.utils import case_insensitive_dict -from .._serialization import Serializer -from .._vendor import ConditionalRequestClientMixinABC, prep_if_match, prep_if_none_match +from .._configuration import ConditionalRequestClientConfiguration +from .._utils.serialization import Serializer +from .._utils.utils import ClientMixinABC, prep_if_match, prep_if_none_match T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] @@ -102,7 +103,7 @@ def build_conditional_request_post_if_unmodified_since_request( # pylint: disab return HttpRequest(method="POST", url=_url, headers=_headers, **kwargs) -class ConditionalRequestClientOperationsMixin(ConditionalRequestClientMixinABC): +class ConditionalRequestClientOperationsMixin(ClientMixinABC[PipelineClient, ConditionalRequestClientConfiguration]): @distributed_trace def post_if_match( # pylint: disable=inconsistent-return-statements diff --git a/packages/typespec-python/test/azure/generated/special-headers-conditional-request/specialheaders/conditionalrequest/_utils/__init__.py b/packages/typespec-python/test/azure/generated/special-headers-conditional-request/specialheaders/conditionalrequest/_utils/__init__.py new file mode 100644 index 00000000000..8026245c2ab --- /dev/null +++ b/packages/typespec-python/test/azure/generated/special-headers-conditional-request/specialheaders/conditionalrequest/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) Python Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/typespec-python/test/azure/generated/special-headers-repeatability/specialheaders/repeatability/_model_base.py b/packages/typespec-python/test/azure/generated/special-headers-conditional-request/specialheaders/conditionalrequest/_utils/model_base.py similarity index 100% rename from packages/typespec-python/test/azure/generated/special-headers-repeatability/specialheaders/repeatability/_model_base.py rename to packages/typespec-python/test/azure/generated/special-headers-conditional-request/specialheaders/conditionalrequest/_utils/model_base.py diff --git a/packages/typespec-python/test/azure/generated/special-headers-repeatability/specialheaders/repeatability/_serialization.py b/packages/typespec-python/test/azure/generated/special-headers-conditional-request/specialheaders/conditionalrequest/_utils/serialization.py similarity index 100% rename from packages/typespec-python/test/azure/generated/special-headers-repeatability/specialheaders/repeatability/_serialization.py rename to packages/typespec-python/test/azure/generated/special-headers-conditional-request/specialheaders/conditionalrequest/_utils/serialization.py diff --git a/packages/typespec-python/test/azure/generated/special-headers-conditional-request/specialheaders/conditionalrequest/_utils/utils.py b/packages/typespec-python/test/azure/generated/special-headers-conditional-request/specialheaders/conditionalrequest/_utils/utils.py new file mode 100644 index 00000000000..927adb7c8ae --- /dev/null +++ b/packages/typespec-python/test/azure/generated/special-headers-conditional-request/specialheaders/conditionalrequest/_utils/utils.py @@ -0,0 +1,57 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) Python Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from abc import ABC +from typing import Generic, Optional, TYPE_CHECKING, TypeVar + +from azure.core import MatchConditions + +if TYPE_CHECKING: + from .serialization import Deserializer, Serializer + + +TClient = TypeVar("TClient") +TConfig = TypeVar("TConfig") + + +class ClientMixinABC(ABC, Generic[TClient, TConfig]): + """DO NOT use this class. It is for internal typing use only.""" + + _client: TClient + _config: TConfig + _serialize: "Serializer" + _deserialize: "Deserializer" + + +def quote_etag(etag: Optional[str]) -> Optional[str]: + if not etag or etag == "*": + return etag + if etag.startswith("W/"): + return etag + if etag.startswith('"') and etag.endswith('"'): + return etag + if etag.startswith("'") and etag.endswith("'"): + return etag + return '"' + etag + '"' + + +def prep_if_match(etag: Optional[str], match_condition: Optional[MatchConditions]) -> Optional[str]: + if match_condition == MatchConditions.IfNotModified: + if_match = quote_etag(etag) if etag else None + return if_match + if match_condition == MatchConditions.IfPresent: + return "*" + return None + + +def prep_if_none_match(etag: Optional[str], match_condition: Optional[MatchConditions]) -> Optional[str]: + if match_condition == MatchConditions.IfModified: + if_none_match = quote_etag(etag) if etag else None + return if_none_match + if match_condition == MatchConditions.IfMissing: + return "*" + return None diff --git a/packages/typespec-python/test/azure/generated/special-headers-conditional-request/specialheaders/conditionalrequest/_vendor.py b/packages/typespec-python/test/azure/generated/special-headers-conditional-request/specialheaders/conditionalrequest/_vendor.py deleted file mode 100644 index bf469e2b080..00000000000 --- a/packages/typespec-python/test/azure/generated/special-headers-conditional-request/specialheaders/conditionalrequest/_vendor.py +++ /dev/null @@ -1,57 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) Python Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import Optional, TYPE_CHECKING - -from azure.core import MatchConditions - -from ._configuration import ConditionalRequestClientConfiguration - -if TYPE_CHECKING: - from azure.core import PipelineClient - - from ._serialization import Deserializer, Serializer - - -class ConditionalRequestClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "PipelineClient" - _config: ConditionalRequestClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" - - -def quote_etag(etag: Optional[str]) -> Optional[str]: - if not etag or etag == "*": - return etag - if etag.startswith("W/"): - return etag - if etag.startswith('"') and etag.endswith('"'): - return etag - if etag.startswith("'") and etag.endswith("'"): - return etag - return '"' + etag + '"' - - -def prep_if_match(etag: Optional[str], match_condition: Optional[MatchConditions]) -> Optional[str]: - if match_condition == MatchConditions.IfNotModified: - if_match = quote_etag(etag) if etag else None - return if_match - if match_condition == MatchConditions.IfPresent: - return "*" - return None - - -def prep_if_none_match(etag: Optional[str], match_condition: Optional[MatchConditions]) -> Optional[str]: - if match_condition == MatchConditions.IfModified: - if_none_match = quote_etag(etag) if etag else None - return if_none_match - if match_condition == MatchConditions.IfMissing: - return "*" - return None diff --git a/packages/typespec-python/test/azure/generated/special-headers-conditional-request/specialheaders/conditionalrequest/aio/_client.py b/packages/typespec-python/test/azure/generated/special-headers-conditional-request/specialheaders/conditionalrequest/aio/_client.py index 5e26d81adbd..e4c129e8897 100644 --- a/packages/typespec-python/test/azure/generated/special-headers-conditional-request/specialheaders/conditionalrequest/aio/_client.py +++ b/packages/typespec-python/test/azure/generated/special-headers-conditional-request/specialheaders/conditionalrequest/aio/_client.py @@ -14,7 +14,7 @@ from azure.core.pipeline import policies from azure.core.rest import AsyncHttpResponse, HttpRequest -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import ConditionalRequestClientConfiguration from ._operations import ConditionalRequestClientOperationsMixin diff --git a/packages/typespec-python/test/azure/generated/special-headers-conditional-request/specialheaders/conditionalrequest/aio/_operations/_operations.py b/packages/typespec-python/test/azure/generated/special-headers-conditional-request/specialheaders/conditionalrequest/aio/_operations/_operations.py index 8275238b7b4..7757f1fcca5 100644 --- a/packages/typespec-python/test/azure/generated/special-headers-conditional-request/specialheaders/conditionalrequest/aio/_operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/special-headers-conditional-request/specialheaders/conditionalrequest/aio/_operations/_operations.py @@ -10,7 +10,7 @@ import datetime from typing import Any, Callable, Dict, Optional, TypeVar -from azure.core import MatchConditions +from azure.core import AsyncPipelineClient, MatchConditions from azure.core.exceptions import ( ClientAuthenticationError, HttpResponseError, @@ -30,13 +30,16 @@ build_conditional_request_post_if_none_match_request, build_conditional_request_post_if_unmodified_since_request, ) -from .._vendor import ConditionalRequestClientMixinABC +from ..._utils.utils import ClientMixinABC +from .._configuration import ConditionalRequestClientConfiguration T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, AsyncHttpResponse], T, Dict[str, Any]], Any]] -class ConditionalRequestClientOperationsMixin(ConditionalRequestClientMixinABC): +class ConditionalRequestClientOperationsMixin( + ClientMixinABC[AsyncPipelineClient, ConditionalRequestClientConfiguration] +): @distributed_trace_async async def post_if_match( diff --git a/packages/typespec-python/test/azure/generated/special-headers-conditional-request/specialheaders/conditionalrequest/aio/_vendor.py b/packages/typespec-python/test/azure/generated/special-headers-conditional-request/specialheaders/conditionalrequest/aio/_vendor.py deleted file mode 100644 index 6009e9c327e..00000000000 --- a/packages/typespec-python/test/azure/generated/special-headers-conditional-request/specialheaders/conditionalrequest/aio/_vendor.py +++ /dev/null @@ -1,57 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) Python Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import Optional, TYPE_CHECKING - -from azure.core import MatchConditions - -from ._configuration import ConditionalRequestClientConfiguration - -if TYPE_CHECKING: - from azure.core import AsyncPipelineClient - - from .._serialization import Deserializer, Serializer - - -class ConditionalRequestClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "AsyncPipelineClient" - _config: ConditionalRequestClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" - - -def quote_etag(etag: Optional[str]) -> Optional[str]: - if not etag or etag == "*": - return etag - if etag.startswith("W/"): - return etag - if etag.startswith('"') and etag.endswith('"'): - return etag - if etag.startswith("'") and etag.endswith("'"): - return etag - return '"' + etag + '"' - - -def prep_if_match(etag: Optional[str], match_condition: Optional[MatchConditions]) -> Optional[str]: - if match_condition == MatchConditions.IfNotModified: - if_match = quote_etag(etag) if etag else None - return if_match - if match_condition == MatchConditions.IfPresent: - return "*" - return None - - -def prep_if_none_match(etag: Optional[str], match_condition: Optional[MatchConditions]) -> Optional[str]: - if match_condition == MatchConditions.IfModified: - if_none_match = quote_etag(etag) if etag else None - return if_none_match - if match_condition == MatchConditions.IfMissing: - return "*" - return None diff --git a/packages/typespec-python/test/azure/generated/special-headers-repeatability/specialheaders/repeatability/_client.py b/packages/typespec-python/test/azure/generated/special-headers-repeatability/specialheaders/repeatability/_client.py index 4b9cd7963ef..0fc9eb3410b 100644 --- a/packages/typespec-python/test/azure/generated/special-headers-repeatability/specialheaders/repeatability/_client.py +++ b/packages/typespec-python/test/azure/generated/special-headers-repeatability/specialheaders/repeatability/_client.py @@ -16,7 +16,7 @@ from ._configuration import RepeatabilityClientConfiguration from ._operations import RepeatabilityClientOperationsMixin -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer class RepeatabilityClient(RepeatabilityClientOperationsMixin): # pylint: disable=client-accepts-api-version-keyword diff --git a/packages/typespec-python/test/azure/generated/special-headers-repeatability/specialheaders/repeatability/_operations/_operations.py b/packages/typespec-python/test/azure/generated/special-headers-repeatability/specialheaders/repeatability/_operations/_operations.py index 71cc822f8f3..35c4999d8ff 100644 --- a/packages/typespec-python/test/azure/generated/special-headers-repeatability/specialheaders/repeatability/_operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/special-headers-repeatability/specialheaders/repeatability/_operations/_operations.py @@ -10,6 +10,7 @@ from typing import Any, Callable, Dict, Optional, TypeVar import uuid +from azure.core import PipelineClient from azure.core.exceptions import ( ClientAuthenticationError, HttpResponseError, @@ -23,8 +24,9 @@ from azure.core.tracing.decorator import distributed_trace from azure.core.utils import case_insensitive_dict -from .._serialization import Serializer -from .._vendor import RepeatabilityClientMixinABC +from .._configuration import RepeatabilityClientConfiguration +from .._utils.serialization import Serializer +from .._utils.utils import ClientMixinABC T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] @@ -50,7 +52,7 @@ def build_repeatability_immediate_success_request(**kwargs: Any) -> HttpRequest: return HttpRequest(method="POST", url=_url, headers=_headers, **kwargs) -class RepeatabilityClientOperationsMixin(RepeatabilityClientMixinABC): +class RepeatabilityClientOperationsMixin(ClientMixinABC[PipelineClient, RepeatabilityClientConfiguration]): @distributed_trace def immediate_success(self, **kwargs: Any) -> None: # pylint: disable=inconsistent-return-statements diff --git a/packages/typespec-python/test/azure/generated/special-headers-repeatability/specialheaders/repeatability/_utils/__init__.py b/packages/typespec-python/test/azure/generated/special-headers-repeatability/specialheaders/repeatability/_utils/__init__.py new file mode 100644 index 00000000000..8026245c2ab --- /dev/null +++ b/packages/typespec-python/test/azure/generated/special-headers-repeatability/specialheaders/repeatability/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) Python Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/typespec-python/test/azure/generated/special-words/specialwords/_model_base.py b/packages/typespec-python/test/azure/generated/special-headers-repeatability/specialheaders/repeatability/_utils/model_base.py similarity index 100% rename from packages/typespec-python/test/azure/generated/special-words/specialwords/_model_base.py rename to packages/typespec-python/test/azure/generated/special-headers-repeatability/specialheaders/repeatability/_utils/model_base.py diff --git a/packages/typespec-python/test/azure/generated/special-words/specialwords/_serialization.py b/packages/typespec-python/test/azure/generated/special-headers-repeatability/specialheaders/repeatability/_utils/serialization.py similarity index 100% rename from packages/typespec-python/test/azure/generated/special-words/specialwords/_serialization.py rename to packages/typespec-python/test/azure/generated/special-headers-repeatability/specialheaders/repeatability/_utils/serialization.py diff --git a/packages/typespec-python/test/azure/generated/special-headers-repeatability/specialheaders/repeatability/_utils/utils.py b/packages/typespec-python/test/azure/generated/special-headers-repeatability/specialheaders/repeatability/_utils/utils.py new file mode 100644 index 00000000000..35c9c836f85 --- /dev/null +++ b/packages/typespec-python/test/azure/generated/special-headers-repeatability/specialheaders/repeatability/_utils/utils.py @@ -0,0 +1,25 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) Python Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from abc import ABC +from typing import Generic, TYPE_CHECKING, TypeVar + +if TYPE_CHECKING: + from .serialization import Deserializer, Serializer + + +TClient = TypeVar("TClient") +TConfig = TypeVar("TConfig") + + +class ClientMixinABC(ABC, Generic[TClient, TConfig]): + """DO NOT use this class. It is for internal typing use only.""" + + _client: TClient + _config: TConfig + _serialize: "Serializer" + _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/azure/generated/special-headers-repeatability/specialheaders/repeatability/_vendor.py b/packages/typespec-python/test/azure/generated/special-headers-repeatability/specialheaders/repeatability/_vendor.py deleted file mode 100644 index 9cc3504bf35..00000000000 --- a/packages/typespec-python/test/azure/generated/special-headers-repeatability/specialheaders/repeatability/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) Python Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import RepeatabilityClientConfiguration - -if TYPE_CHECKING: - from azure.core import PipelineClient - - from ._serialization import Deserializer, Serializer - - -class RepeatabilityClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "PipelineClient" - _config: RepeatabilityClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/azure/generated/special-headers-repeatability/specialheaders/repeatability/aio/_client.py b/packages/typespec-python/test/azure/generated/special-headers-repeatability/specialheaders/repeatability/aio/_client.py index 15a1f859f64..83ae5e478b6 100644 --- a/packages/typespec-python/test/azure/generated/special-headers-repeatability/specialheaders/repeatability/aio/_client.py +++ b/packages/typespec-python/test/azure/generated/special-headers-repeatability/specialheaders/repeatability/aio/_client.py @@ -14,7 +14,7 @@ from azure.core.pipeline import policies from azure.core.rest import AsyncHttpResponse, HttpRequest -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import RepeatabilityClientConfiguration from ._operations import RepeatabilityClientOperationsMixin diff --git a/packages/typespec-python/test/azure/generated/special-headers-repeatability/specialheaders/repeatability/aio/_operations/_operations.py b/packages/typespec-python/test/azure/generated/special-headers-repeatability/specialheaders/repeatability/aio/_operations/_operations.py index 1fe30cb5582..ccba4a79e95 100644 --- a/packages/typespec-python/test/azure/generated/special-headers-repeatability/specialheaders/repeatability/aio/_operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/special-headers-repeatability/specialheaders/repeatability/aio/_operations/_operations.py @@ -9,6 +9,7 @@ from collections.abc import MutableMapping from typing import Any, Callable, Dict, Optional, TypeVar +from azure.core import AsyncPipelineClient from azure.core.exceptions import ( ClientAuthenticationError, HttpResponseError, @@ -22,13 +23,14 @@ from azure.core.tracing.decorator_async import distributed_trace_async from ..._operations._operations import build_repeatability_immediate_success_request -from .._vendor import RepeatabilityClientMixinABC +from ..._utils.utils import ClientMixinABC +from .._configuration import RepeatabilityClientConfiguration T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, AsyncHttpResponse], T, Dict[str, Any]], Any]] -class RepeatabilityClientOperationsMixin(RepeatabilityClientMixinABC): +class RepeatabilityClientOperationsMixin(ClientMixinABC[AsyncPipelineClient, RepeatabilityClientConfiguration]): @distributed_trace_async async def immediate_success(self, **kwargs: Any) -> None: diff --git a/packages/typespec-python/test/azure/generated/special-headers-repeatability/specialheaders/repeatability/aio/_vendor.py b/packages/typespec-python/test/azure/generated/special-headers-repeatability/specialheaders/repeatability/aio/_vendor.py deleted file mode 100644 index 096b77265ed..00000000000 --- a/packages/typespec-python/test/azure/generated/special-headers-repeatability/specialheaders/repeatability/aio/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) Python Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import RepeatabilityClientConfiguration - -if TYPE_CHECKING: - from azure.core import AsyncPipelineClient - - from .._serialization import Deserializer, Serializer - - -class RepeatabilityClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "AsyncPipelineClient" - _config: RepeatabilityClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/azure/generated/special-words/specialwords/_client.py b/packages/typespec-python/test/azure/generated/special-words/specialwords/_client.py index de94df7beb9..02159cb48ea 100644 --- a/packages/typespec-python/test/azure/generated/special-words/specialwords/_client.py +++ b/packages/typespec-python/test/azure/generated/special-words/specialwords/_client.py @@ -15,7 +15,7 @@ from azure.core.rest import HttpRequest, HttpResponse from ._configuration import SpecialWordsClientConfiguration -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer from .operations import ModelPropertiesOperations, ModelsOperations, Operations, ParametersOperations diff --git a/packages/typespec-python/test/azure/generated/special-words/specialwords/_utils/__init__.py b/packages/typespec-python/test/azure/generated/special-words/specialwords/_utils/__init__.py new file mode 100644 index 00000000000..8026245c2ab --- /dev/null +++ b/packages/typespec-python/test/azure/generated/special-words/specialwords/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) Python Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/typespec-python/test/azure/generated/streaming-jsonl/streaming/jsonl/_model_base.py b/packages/typespec-python/test/azure/generated/special-words/specialwords/_utils/model_base.py similarity index 100% rename from packages/typespec-python/test/azure/generated/streaming-jsonl/streaming/jsonl/_model_base.py rename to packages/typespec-python/test/azure/generated/special-words/specialwords/_utils/model_base.py diff --git a/packages/typespec-python/test/azure/generated/streaming-jsonl/streaming/jsonl/_serialization.py b/packages/typespec-python/test/azure/generated/special-words/specialwords/_utils/serialization.py similarity index 100% rename from packages/typespec-python/test/azure/generated/streaming-jsonl/streaming/jsonl/_serialization.py rename to packages/typespec-python/test/azure/generated/special-words/specialwords/_utils/serialization.py diff --git a/packages/typespec-python/test/azure/generated/special-words/specialwords/aio/_client.py b/packages/typespec-python/test/azure/generated/special-words/specialwords/aio/_client.py index d29bb897d9f..575b9d8ebc8 100644 --- a/packages/typespec-python/test/azure/generated/special-words/specialwords/aio/_client.py +++ b/packages/typespec-python/test/azure/generated/special-words/specialwords/aio/_client.py @@ -14,7 +14,7 @@ from azure.core.pipeline import policies from azure.core.rest import AsyncHttpResponse, HttpRequest -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import SpecialWordsClientConfiguration from .operations import ModelPropertiesOperations, ModelsOperations, Operations, ParametersOperations diff --git a/packages/typespec-python/test/azure/generated/special-words/specialwords/aio/operations/_operations.py b/packages/typespec-python/test/azure/generated/special-words/specialwords/aio/operations/_operations.py index a5765edcae7..a84ad15f3a2 100644 --- a/packages/typespec-python/test/azure/generated/special-words/specialwords/aio/operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/special-words/specialwords/aio/operations/_operations.py @@ -26,8 +26,8 @@ from azure.core.utils import case_insensitive_dict from ... import models as _models -from ..._model_base import SdkJSONEncoder -from ..._serialization import Deserializer, Serializer +from ..._utils.model_base import SdkJSONEncoder +from ..._utils.serialization import Deserializer, Serializer from ...operations._operations import ( build_model_properties_same_as_model_request, build_models_with_and_request, diff --git a/packages/typespec-python/test/azure/generated/special-words/specialwords/models/_models.py b/packages/typespec-python/test/azure/generated/special-words/specialwords/models/_models.py index 57c90b789f4..955d94be713 100644 --- a/packages/typespec-python/test/azure/generated/special-words/specialwords/models/_models.py +++ b/packages/typespec-python/test/azure/generated/special-words/specialwords/models/_models.py @@ -9,11 +9,10 @@ from typing import Any, Mapping, overload -from .. import _model_base -from .._model_base import rest_field +from .._utils.model_base import Model as _Model, rest_field -class AndModel(_model_base.Model): +class AndModel(_Model): """AndModel. :ivar name: Required. @@ -41,7 +40,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class AsModel(_model_base.Model): +class AsModel(_Model): """AsModel. :ivar name: Required. @@ -69,7 +68,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class AssertModel(_model_base.Model): +class AssertModel(_Model): """AssertModel. :ivar name: Required. @@ -97,7 +96,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class AsyncModel(_model_base.Model): +class AsyncModel(_Model): """AsyncModel. :ivar name: Required. @@ -125,7 +124,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class AwaitModel(_model_base.Model): +class AwaitModel(_Model): """AwaitModel. :ivar name: Required. @@ -153,7 +152,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class BreakModel(_model_base.Model): +class BreakModel(_Model): """BreakModel. :ivar name: Required. @@ -181,7 +180,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class ClassModel(_model_base.Model): +class ClassModel(_Model): """ClassModel. :ivar name: Required. @@ -209,7 +208,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class Constructor(_model_base.Model): +class Constructor(_Model): """Constructor. :ivar name: Required. @@ -237,7 +236,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class ContinueModel(_model_base.Model): +class ContinueModel(_Model): """ContinueModel. :ivar name: Required. @@ -265,7 +264,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class DefModel(_model_base.Model): +class DefModel(_Model): """DefModel. :ivar name: Required. @@ -293,7 +292,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class DelModel(_model_base.Model): +class DelModel(_Model): """DelModel. :ivar name: Required. @@ -321,7 +320,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class ElifModel(_model_base.Model): +class ElifModel(_Model): """ElifModel. :ivar name: Required. @@ -349,7 +348,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class ElseModel(_model_base.Model): +class ElseModel(_Model): """ElseModel. :ivar name: Required. @@ -377,7 +376,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class ExceptModel(_model_base.Model): +class ExceptModel(_Model): """ExceptModel. :ivar name: Required. @@ -405,7 +404,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class ExecModel(_model_base.Model): +class ExecModel(_Model): """ExecModel. :ivar name: Required. @@ -433,7 +432,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class FinallyModel(_model_base.Model): +class FinallyModel(_Model): """FinallyModel. :ivar name: Required. @@ -461,7 +460,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class ForModel(_model_base.Model): +class ForModel(_Model): """ForModel. :ivar name: Required. @@ -489,7 +488,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class FromModel(_model_base.Model): +class FromModel(_Model): """FromModel. :ivar name: Required. @@ -517,7 +516,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class GlobalModel(_model_base.Model): +class GlobalModel(_Model): """GlobalModel. :ivar name: Required. @@ -545,7 +544,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class IfModel(_model_base.Model): +class IfModel(_Model): """IfModel. :ivar name: Required. @@ -573,7 +572,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class ImportModel(_model_base.Model): +class ImportModel(_Model): """ImportModel. :ivar name: Required. @@ -601,7 +600,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class InModel(_model_base.Model): +class InModel(_Model): """InModel. :ivar name: Required. @@ -629,7 +628,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class IsModel(_model_base.Model): +class IsModel(_Model): """IsModel. :ivar name: Required. @@ -657,7 +656,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class LambdaModel(_model_base.Model): +class LambdaModel(_Model): """LambdaModel. :ivar name: Required. @@ -685,7 +684,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class NotModel(_model_base.Model): +class NotModel(_Model): """NotModel. :ivar name: Required. @@ -713,7 +712,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class OrModel(_model_base.Model): +class OrModel(_Model): """OrModel. :ivar name: Required. @@ -741,7 +740,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class PassModel(_model_base.Model): +class PassModel(_Model): """PassModel. :ivar name: Required. @@ -769,7 +768,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class RaiseModel(_model_base.Model): +class RaiseModel(_Model): """RaiseModel. :ivar name: Required. @@ -797,7 +796,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class ReturnModel(_model_base.Model): +class ReturnModel(_Model): """ReturnModel. :ivar name: Required. @@ -825,7 +824,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class SameAsModel(_model_base.Model): +class SameAsModel(_Model): """SameAsModel. :ivar same_as_model: Required. @@ -853,7 +852,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class TryModel(_model_base.Model): +class TryModel(_Model): """TryModel. :ivar name: Required. @@ -881,7 +880,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class WhileModel(_model_base.Model): +class WhileModel(_Model): """WhileModel. :ivar name: Required. @@ -909,7 +908,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class WithModel(_model_base.Model): +class WithModel(_Model): """WithModel. :ivar name: Required. @@ -937,7 +936,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class YieldModel(_model_base.Model): +class YieldModel(_Model): """YieldModel. :ivar name: Required. diff --git a/packages/typespec-python/test/azure/generated/special-words/specialwords/operations/_operations.py b/packages/typespec-python/test/azure/generated/special-words/specialwords/operations/_operations.py index 10dd5521da2..196d89ebc1b 100644 --- a/packages/typespec-python/test/azure/generated/special-words/specialwords/operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/special-words/specialwords/operations/_operations.py @@ -27,8 +27,8 @@ from .. import models as _models from .._configuration import SpecialWordsClientConfiguration -from .._model_base import SdkJSONEncoder -from .._serialization import Deserializer, Serializer +from .._utils.model_base import SdkJSONEncoder +from .._utils.serialization import Deserializer, Serializer JSON = MutableMapping[str, Any] T = TypeVar("T") diff --git a/packages/typespec-python/test/azure/generated/streaming-jsonl/streaming/jsonl/_client.py b/packages/typespec-python/test/azure/generated/streaming-jsonl/streaming/jsonl/_client.py index 851b96a2809..ebb26214dd8 100644 --- a/packages/typespec-python/test/azure/generated/streaming-jsonl/streaming/jsonl/_client.py +++ b/packages/typespec-python/test/azure/generated/streaming-jsonl/streaming/jsonl/_client.py @@ -15,7 +15,7 @@ from azure.core.rest import HttpRequest, HttpResponse from ._configuration import JsonlClientConfiguration -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer from .basic.operations import BasicOperations diff --git a/packages/typespec-python/test/azure/generated/streaming-jsonl/streaming/jsonl/_utils/__init__.py b/packages/typespec-python/test/azure/generated/streaming-jsonl/streaming/jsonl/_utils/__init__.py new file mode 100644 index 00000000000..8026245c2ab --- /dev/null +++ b/packages/typespec-python/test/azure/generated/streaming-jsonl/streaming/jsonl/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) Python Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/typespec-python/test/azure/generated/typetest-array/typetest/array/_model_base.py b/packages/typespec-python/test/azure/generated/streaming-jsonl/streaming/jsonl/_utils/model_base.py similarity index 100% rename from packages/typespec-python/test/azure/generated/typetest-array/typetest/array/_model_base.py rename to packages/typespec-python/test/azure/generated/streaming-jsonl/streaming/jsonl/_utils/model_base.py diff --git a/packages/typespec-python/test/azure/generated/typetest-array/typetest/array/_serialization.py b/packages/typespec-python/test/azure/generated/streaming-jsonl/streaming/jsonl/_utils/serialization.py similarity index 100% rename from packages/typespec-python/test/azure/generated/typetest-array/typetest/array/_serialization.py rename to packages/typespec-python/test/azure/generated/streaming-jsonl/streaming/jsonl/_utils/serialization.py diff --git a/packages/typespec-python/test/azure/generated/streaming-jsonl/streaming/jsonl/aio/_client.py b/packages/typespec-python/test/azure/generated/streaming-jsonl/streaming/jsonl/aio/_client.py index 93c66ba7862..481fc5aa1ea 100644 --- a/packages/typespec-python/test/azure/generated/streaming-jsonl/streaming/jsonl/aio/_client.py +++ b/packages/typespec-python/test/azure/generated/streaming-jsonl/streaming/jsonl/aio/_client.py @@ -14,7 +14,7 @@ from azure.core.pipeline import policies from azure.core.rest import AsyncHttpResponse, HttpRequest -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ..basic.aio.operations import BasicOperations from ._configuration import JsonlClientConfiguration diff --git a/packages/typespec-python/test/azure/generated/streaming-jsonl/streaming/jsonl/basic/aio/operations/_operations.py b/packages/typespec-python/test/azure/generated/streaming-jsonl/streaming/jsonl/basic/aio/operations/_operations.py index 062acb03bac..4a1dec7e64c 100644 --- a/packages/typespec-python/test/azure/generated/streaming-jsonl/streaming/jsonl/basic/aio/operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/streaming-jsonl/streaming/jsonl/basic/aio/operations/_operations.py @@ -24,7 +24,7 @@ from azure.core.tracing.decorator_async import distributed_trace_async from azure.core.utils import case_insensitive_dict -from ...._serialization import Deserializer, Serializer +from ...._utils.serialization import Deserializer, Serializer from ....aio._configuration import JsonlClientConfiguration from ...operations._operations import build_basic_receive_request, build_basic_send_request diff --git a/packages/typespec-python/test/azure/generated/streaming-jsonl/streaming/jsonl/basic/operations/_operations.py b/packages/typespec-python/test/azure/generated/streaming-jsonl/streaming/jsonl/basic/operations/_operations.py index 2a5ee3bf6bb..77cc8d19574 100644 --- a/packages/typespec-python/test/azure/generated/streaming-jsonl/streaming/jsonl/basic/operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/streaming-jsonl/streaming/jsonl/basic/operations/_operations.py @@ -25,7 +25,7 @@ from azure.core.utils import case_insensitive_dict from ..._configuration import JsonlClientConfiguration -from ..._serialization import Deserializer, Serializer +from ..._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/typespec-python/test/azure/generated/typetest-array/typetest/array/_client.py b/packages/typespec-python/test/azure/generated/typetest-array/typetest/array/_client.py index 7ba863cae65..030f534ce83 100644 --- a/packages/typespec-python/test/azure/generated/typetest-array/typetest/array/_client.py +++ b/packages/typespec-python/test/azure/generated/typetest-array/typetest/array/_client.py @@ -15,7 +15,7 @@ from azure.core.rest import HttpRequest, HttpResponse from ._configuration import ArrayClientConfiguration -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer from .operations import ( BooleanValueOperations, DatetimeValueOperations, diff --git a/packages/typespec-python/test/azure/generated/typetest-array/typetest/array/_utils/__init__.py b/packages/typespec-python/test/azure/generated/typetest-array/typetest/array/_utils/__init__.py new file mode 100644 index 00000000000..8026245c2ab --- /dev/null +++ b/packages/typespec-python/test/azure/generated/typetest-array/typetest/array/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) Python Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/typespec-python/test/azure/generated/typetest-dictionary/typetest/dictionary/_model_base.py b/packages/typespec-python/test/azure/generated/typetest-array/typetest/array/_utils/model_base.py similarity index 100% rename from packages/typespec-python/test/azure/generated/typetest-dictionary/typetest/dictionary/_model_base.py rename to packages/typespec-python/test/azure/generated/typetest-array/typetest/array/_utils/model_base.py diff --git a/packages/typespec-python/test/azure/generated/typetest-dictionary/typetest/dictionary/_serialization.py b/packages/typespec-python/test/azure/generated/typetest-array/typetest/array/_utils/serialization.py similarity index 100% rename from packages/typespec-python/test/azure/generated/typetest-dictionary/typetest/dictionary/_serialization.py rename to packages/typespec-python/test/azure/generated/typetest-array/typetest/array/_utils/serialization.py diff --git a/packages/typespec-python/test/azure/generated/typetest-array/typetest/array/aio/_client.py b/packages/typespec-python/test/azure/generated/typetest-array/typetest/array/aio/_client.py index fbccebfe181..2012baab7a6 100644 --- a/packages/typespec-python/test/azure/generated/typetest-array/typetest/array/aio/_client.py +++ b/packages/typespec-python/test/azure/generated/typetest-array/typetest/array/aio/_client.py @@ -14,7 +14,7 @@ from azure.core.pipeline import policies from azure.core.rest import AsyncHttpResponse, HttpRequest -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import ArrayClientConfiguration from .operations import ( BooleanValueOperations, diff --git a/packages/typespec-python/test/azure/generated/typetest-array/typetest/array/aio/operations/_operations.py b/packages/typespec-python/test/azure/generated/typetest-array/typetest/array/aio/operations/_operations.py index d2be9efad9b..183bd606b62 100644 --- a/packages/typespec-python/test/azure/generated/typetest-array/typetest/array/aio/operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/typetest-array/typetest/array/aio/operations/_operations.py @@ -29,8 +29,8 @@ from azure.core.utils import case_insensitive_dict from ... import models as _models -from ..._model_base import SdkJSONEncoder, _deserialize -from ..._serialization import Deserializer, Serializer +from ..._utils.model_base import SdkJSONEncoder, _deserialize +from ..._utils.serialization import Deserializer, Serializer from ...operations._operations import ( build_boolean_value_get_request, build_boolean_value_put_request, diff --git a/packages/typespec-python/test/azure/generated/typetest-array/typetest/array/models/_models.py b/packages/typespec-python/test/azure/generated/typetest-array/typetest/array/models/_models.py index 43c2e34c60c..11a7a61b6ab 100644 --- a/packages/typespec-python/test/azure/generated/typetest-array/typetest/array/models/_models.py +++ b/packages/typespec-python/test/azure/generated/typetest-array/typetest/array/models/_models.py @@ -9,14 +9,13 @@ from typing import Any, List, Mapping, Optional, TYPE_CHECKING, overload -from .. import _model_base -from .._model_base import rest_field +from .._utils.model_base import Model as _Model, rest_field if TYPE_CHECKING: from .. import models as _models -class InnerModel(_model_base.Model): +class InnerModel(_Model): """Array inner model. :ivar property: Required string property. Required. diff --git a/packages/typespec-python/test/azure/generated/typetest-array/typetest/array/operations/_operations.py b/packages/typespec-python/test/azure/generated/typetest-array/typetest/array/operations/_operations.py index 30d7d3ef7e3..93621ca98ac 100644 --- a/packages/typespec-python/test/azure/generated/typetest-array/typetest/array/operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/typetest-array/typetest/array/operations/_operations.py @@ -30,8 +30,8 @@ from .. import models as _models from .._configuration import ArrayClientConfiguration -from .._model_base import SdkJSONEncoder, _deserialize -from .._serialization import Deserializer, Serializer +from .._utils.model_base import SdkJSONEncoder, _deserialize +from .._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/typespec-python/test/azure/generated/typetest-dictionary/typetest/dictionary/_client.py b/packages/typespec-python/test/azure/generated/typetest-dictionary/typetest/dictionary/_client.py index f761dea9906..393c329d4ba 100644 --- a/packages/typespec-python/test/azure/generated/typetest-dictionary/typetest/dictionary/_client.py +++ b/packages/typespec-python/test/azure/generated/typetest-dictionary/typetest/dictionary/_client.py @@ -15,7 +15,7 @@ from azure.core.rest import HttpRequest, HttpResponse from ._configuration import DictionaryClientConfiguration -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer from .operations import ( BooleanValueOperations, DatetimeValueOperations, diff --git a/packages/typespec-python/test/azure/generated/typetest-dictionary/typetest/dictionary/_utils/__init__.py b/packages/typespec-python/test/azure/generated/typetest-dictionary/typetest/dictionary/_utils/__init__.py new file mode 100644 index 00000000000..8026245c2ab --- /dev/null +++ b/packages/typespec-python/test/azure/generated/typetest-dictionary/typetest/dictionary/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) Python Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/typespec-python/test/azure/generated/typetest-enum-extensible/typetest/enum/extensible/_model_base.py b/packages/typespec-python/test/azure/generated/typetest-dictionary/typetest/dictionary/_utils/model_base.py similarity index 100% rename from packages/typespec-python/test/azure/generated/typetest-enum-extensible/typetest/enum/extensible/_model_base.py rename to packages/typespec-python/test/azure/generated/typetest-dictionary/typetest/dictionary/_utils/model_base.py diff --git a/packages/typespec-python/test/azure/generated/typetest-enum-extensible/typetest/enum/extensible/_serialization.py b/packages/typespec-python/test/azure/generated/typetest-dictionary/typetest/dictionary/_utils/serialization.py similarity index 100% rename from packages/typespec-python/test/azure/generated/typetest-enum-extensible/typetest/enum/extensible/_serialization.py rename to packages/typespec-python/test/azure/generated/typetest-dictionary/typetest/dictionary/_utils/serialization.py diff --git a/packages/typespec-python/test/azure/generated/typetest-dictionary/typetest/dictionary/aio/_client.py b/packages/typespec-python/test/azure/generated/typetest-dictionary/typetest/dictionary/aio/_client.py index feb32cfeabe..f48f157063d 100644 --- a/packages/typespec-python/test/azure/generated/typetest-dictionary/typetest/dictionary/aio/_client.py +++ b/packages/typespec-python/test/azure/generated/typetest-dictionary/typetest/dictionary/aio/_client.py @@ -14,7 +14,7 @@ from azure.core.pipeline import policies from azure.core.rest import AsyncHttpResponse, HttpRequest -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import DictionaryClientConfiguration from .operations import ( BooleanValueOperations, diff --git a/packages/typespec-python/test/azure/generated/typetest-dictionary/typetest/dictionary/aio/operations/_operations.py b/packages/typespec-python/test/azure/generated/typetest-dictionary/typetest/dictionary/aio/operations/_operations.py index abe88418a7d..1807c80aa64 100644 --- a/packages/typespec-python/test/azure/generated/typetest-dictionary/typetest/dictionary/aio/operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/typetest-dictionary/typetest/dictionary/aio/operations/_operations.py @@ -29,8 +29,8 @@ from azure.core.utils import case_insensitive_dict from ... import models as _models -from ..._model_base import SdkJSONEncoder, _deserialize -from ..._serialization import Deserializer, Serializer +from ..._utils.model_base import SdkJSONEncoder, _deserialize +from ..._utils.serialization import Deserializer, Serializer from ...operations._operations import ( build_boolean_value_get_request, build_boolean_value_put_request, diff --git a/packages/typespec-python/test/azure/generated/typetest-dictionary/typetest/dictionary/models/_models.py b/packages/typespec-python/test/azure/generated/typetest-dictionary/typetest/dictionary/models/_models.py index 223e0f75708..f6891908fff 100644 --- a/packages/typespec-python/test/azure/generated/typetest-dictionary/typetest/dictionary/models/_models.py +++ b/packages/typespec-python/test/azure/generated/typetest-dictionary/typetest/dictionary/models/_models.py @@ -9,14 +9,13 @@ from typing import Any, Dict, Mapping, Optional, TYPE_CHECKING, overload -from .. import _model_base -from .._model_base import rest_field +from .._utils.model_base import Model as _Model, rest_field if TYPE_CHECKING: from .. import models as _models -class InnerModel(_model_base.Model): +class InnerModel(_Model): """Dictionary inner model. :ivar property: Required string property. Required. diff --git a/packages/typespec-python/test/azure/generated/typetest-dictionary/typetest/dictionary/operations/_operations.py b/packages/typespec-python/test/azure/generated/typetest-dictionary/typetest/dictionary/operations/_operations.py index 684736d910b..7ebc983dc76 100644 --- a/packages/typespec-python/test/azure/generated/typetest-dictionary/typetest/dictionary/operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/typetest-dictionary/typetest/dictionary/operations/_operations.py @@ -30,8 +30,8 @@ from .. import models as _models from .._configuration import DictionaryClientConfiguration -from .._model_base import SdkJSONEncoder, _deserialize -from .._serialization import Deserializer, Serializer +from .._utils.model_base import SdkJSONEncoder, _deserialize +from .._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/typespec-python/test/azure/generated/typetest-enum-extensible/typetest/enum/extensible/_client.py b/packages/typespec-python/test/azure/generated/typetest-enum-extensible/typetest/enum/extensible/_client.py index 93d2fb45830..19c0cf52485 100644 --- a/packages/typespec-python/test/azure/generated/typetest-enum-extensible/typetest/enum/extensible/_client.py +++ b/packages/typespec-python/test/azure/generated/typetest-enum-extensible/typetest/enum/extensible/_client.py @@ -15,7 +15,7 @@ from azure.core.rest import HttpRequest, HttpResponse from ._configuration import ExtensibleClientConfiguration -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer from .operations import StringOperations diff --git a/packages/typespec-python/test/azure/generated/typetest-enum-extensible/typetest/enum/extensible/_utils/__init__.py b/packages/typespec-python/test/azure/generated/typetest-enum-extensible/typetest/enum/extensible/_utils/__init__.py new file mode 100644 index 00000000000..8026245c2ab --- /dev/null +++ b/packages/typespec-python/test/azure/generated/typetest-enum-extensible/typetest/enum/extensible/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) Python Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/typespec-python/test/azure/generated/typetest-enum-fixed/typetest/enum/fixed/_model_base.py b/packages/typespec-python/test/azure/generated/typetest-enum-extensible/typetest/enum/extensible/_utils/model_base.py similarity index 100% rename from packages/typespec-python/test/azure/generated/typetest-enum-fixed/typetest/enum/fixed/_model_base.py rename to packages/typespec-python/test/azure/generated/typetest-enum-extensible/typetest/enum/extensible/_utils/model_base.py diff --git a/packages/typespec-python/test/azure/generated/typetest-enum-fixed/typetest/enum/fixed/_serialization.py b/packages/typespec-python/test/azure/generated/typetest-enum-extensible/typetest/enum/extensible/_utils/serialization.py similarity index 100% rename from packages/typespec-python/test/azure/generated/typetest-enum-fixed/typetest/enum/fixed/_serialization.py rename to packages/typespec-python/test/azure/generated/typetest-enum-extensible/typetest/enum/extensible/_utils/serialization.py diff --git a/packages/typespec-python/test/azure/generated/typetest-enum-extensible/typetest/enum/extensible/aio/_client.py b/packages/typespec-python/test/azure/generated/typetest-enum-extensible/typetest/enum/extensible/aio/_client.py index 81f2e4cf0d1..933280b471a 100644 --- a/packages/typespec-python/test/azure/generated/typetest-enum-extensible/typetest/enum/extensible/aio/_client.py +++ b/packages/typespec-python/test/azure/generated/typetest-enum-extensible/typetest/enum/extensible/aio/_client.py @@ -14,7 +14,7 @@ from azure.core.pipeline import policies from azure.core.rest import AsyncHttpResponse, HttpRequest -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import ExtensibleClientConfiguration from .operations import StringOperations diff --git a/packages/typespec-python/test/azure/generated/typetest-enum-extensible/typetest/enum/extensible/aio/operations/_operations.py b/packages/typespec-python/test/azure/generated/typetest-enum-extensible/typetest/enum/extensible/aio/operations/_operations.py index bca6d62d58f..15edb5d48ae 100644 --- a/packages/typespec-python/test/azure/generated/typetest-enum-extensible/typetest/enum/extensible/aio/operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/typetest-enum-extensible/typetest/enum/extensible/aio/operations/_operations.py @@ -26,8 +26,8 @@ from azure.core.utils import case_insensitive_dict from ... import models as _models -from ..._model_base import SdkJSONEncoder, _deserialize -from ..._serialization import Deserializer, Serializer +from ..._utils.model_base import SdkJSONEncoder, _deserialize +from ..._utils.serialization import Deserializer, Serializer from ...operations._operations import ( build_string_get_known_value_request, build_string_get_unknown_value_request, diff --git a/packages/typespec-python/test/azure/generated/typetest-enum-extensible/typetest/enum/extensible/operations/_operations.py b/packages/typespec-python/test/azure/generated/typetest-enum-extensible/typetest/enum/extensible/operations/_operations.py index 1bab3f02237..462a14b136e 100644 --- a/packages/typespec-python/test/azure/generated/typetest-enum-extensible/typetest/enum/extensible/operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/typetest-enum-extensible/typetest/enum/extensible/operations/_operations.py @@ -27,8 +27,8 @@ from .. import models as _models from .._configuration import ExtensibleClientConfiguration -from .._model_base import SdkJSONEncoder, _deserialize -from .._serialization import Deserializer, Serializer +from .._utils.model_base import SdkJSONEncoder, _deserialize +from .._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/typespec-python/test/azure/generated/typetest-enum-fixed/typetest/enum/fixed/_client.py b/packages/typespec-python/test/azure/generated/typetest-enum-fixed/typetest/enum/fixed/_client.py index cb49413c387..5d64b8956b6 100644 --- a/packages/typespec-python/test/azure/generated/typetest-enum-fixed/typetest/enum/fixed/_client.py +++ b/packages/typespec-python/test/azure/generated/typetest-enum-fixed/typetest/enum/fixed/_client.py @@ -15,7 +15,7 @@ from azure.core.rest import HttpRequest, HttpResponse from ._configuration import FixedClientConfiguration -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer from .operations import StringOperations diff --git a/packages/typespec-python/test/azure/generated/typetest-enum-fixed/typetest/enum/fixed/_utils/__init__.py b/packages/typespec-python/test/azure/generated/typetest-enum-fixed/typetest/enum/fixed/_utils/__init__.py new file mode 100644 index 00000000000..8026245c2ab --- /dev/null +++ b/packages/typespec-python/test/azure/generated/typetest-enum-fixed/typetest/enum/fixed/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) Python Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/typespec-python/test/azure/generated/typetest-model-empty/typetest/model/empty/_model_base.py b/packages/typespec-python/test/azure/generated/typetest-enum-fixed/typetest/enum/fixed/_utils/model_base.py similarity index 100% rename from packages/typespec-python/test/azure/generated/typetest-model-empty/typetest/model/empty/_model_base.py rename to packages/typespec-python/test/azure/generated/typetest-enum-fixed/typetest/enum/fixed/_utils/model_base.py diff --git a/packages/typespec-python/test/azure/generated/typetest-model-empty/typetest/model/empty/_serialization.py b/packages/typespec-python/test/azure/generated/typetest-enum-fixed/typetest/enum/fixed/_utils/serialization.py similarity index 100% rename from packages/typespec-python/test/azure/generated/typetest-model-empty/typetest/model/empty/_serialization.py rename to packages/typespec-python/test/azure/generated/typetest-enum-fixed/typetest/enum/fixed/_utils/serialization.py diff --git a/packages/typespec-python/test/azure/generated/typetest-enum-fixed/typetest/enum/fixed/aio/_client.py b/packages/typespec-python/test/azure/generated/typetest-enum-fixed/typetest/enum/fixed/aio/_client.py index 375d2f57d5c..dcca3ee6ef2 100644 --- a/packages/typespec-python/test/azure/generated/typetest-enum-fixed/typetest/enum/fixed/aio/_client.py +++ b/packages/typespec-python/test/azure/generated/typetest-enum-fixed/typetest/enum/fixed/aio/_client.py @@ -14,7 +14,7 @@ from azure.core.pipeline import policies from azure.core.rest import AsyncHttpResponse, HttpRequest -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import FixedClientConfiguration from .operations import StringOperations diff --git a/packages/typespec-python/test/azure/generated/typetest-enum-fixed/typetest/enum/fixed/aio/operations/_operations.py b/packages/typespec-python/test/azure/generated/typetest-enum-fixed/typetest/enum/fixed/aio/operations/_operations.py index 37c4f79f492..a19789a3336 100644 --- a/packages/typespec-python/test/azure/generated/typetest-enum-fixed/typetest/enum/fixed/aio/operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/typetest-enum-fixed/typetest/enum/fixed/aio/operations/_operations.py @@ -26,8 +26,8 @@ from azure.core.utils import case_insensitive_dict from ... import models as _models -from ..._model_base import SdkJSONEncoder, _deserialize -from ..._serialization import Deserializer, Serializer +from ..._utils.model_base import SdkJSONEncoder, _deserialize +from ..._utils.serialization import Deserializer, Serializer from ...operations._operations import ( build_string_get_known_value_request, build_string_put_known_value_request, diff --git a/packages/typespec-python/test/azure/generated/typetest-enum-fixed/typetest/enum/fixed/operations/_operations.py b/packages/typespec-python/test/azure/generated/typetest-enum-fixed/typetest/enum/fixed/operations/_operations.py index 3a53d425558..523ca008e61 100644 --- a/packages/typespec-python/test/azure/generated/typetest-enum-fixed/typetest/enum/fixed/operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/typetest-enum-fixed/typetest/enum/fixed/operations/_operations.py @@ -27,8 +27,8 @@ from .. import models as _models from .._configuration import FixedClientConfiguration -from .._model_base import SdkJSONEncoder, _deserialize -from .._serialization import Deserializer, Serializer +from .._utils.model_base import SdkJSONEncoder, _deserialize +from .._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/typespec-python/test/azure/generated/typetest-model-empty/typetest/model/empty/_client.py b/packages/typespec-python/test/azure/generated/typetest-model-empty/typetest/model/empty/_client.py index fe652c45c2a..172d3b99300 100644 --- a/packages/typespec-python/test/azure/generated/typetest-model-empty/typetest/model/empty/_client.py +++ b/packages/typespec-python/test/azure/generated/typetest-model-empty/typetest/model/empty/_client.py @@ -16,7 +16,7 @@ from ._configuration import EmptyClientConfiguration from ._operations import EmptyClientOperationsMixin -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer class EmptyClient(EmptyClientOperationsMixin): # pylint: disable=client-accepts-api-version-keyword diff --git a/packages/typespec-python/test/azure/generated/typetest-model-empty/typetest/model/empty/_operations/_operations.py b/packages/typespec-python/test/azure/generated/typetest-model-empty/typetest/model/empty/_operations/_operations.py index 4772764330b..c0b33578bb1 100644 --- a/packages/typespec-python/test/azure/generated/typetest-model-empty/typetest/model/empty/_operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/typetest-model-empty/typetest/model/empty/_operations/_operations.py @@ -10,6 +10,7 @@ import json from typing import Any, Callable, Dict, IO, Optional, TypeVar, Union, overload +from azure.core import PipelineClient from azure.core.exceptions import ( ClientAuthenticationError, HttpResponseError, @@ -26,9 +27,10 @@ from azure.core.utils import case_insensitive_dict from .. import models as _models -from .._model_base import SdkJSONEncoder, _deserialize -from .._serialization import Serializer -from .._vendor import EmptyClientMixinABC +from .._configuration import EmptyClientConfiguration +from .._utils.model_base import SdkJSONEncoder, _deserialize +from .._utils.serialization import Serializer +from .._utils.utils import ClientMixinABC JSON = MutableMapping[str, Any] T = TypeVar("T") @@ -83,7 +85,7 @@ def build_empty_post_round_trip_empty_request(**kwargs: Any) -> HttpRequest: # return HttpRequest(method="POST", url=_url, headers=_headers, **kwargs) -class EmptyClientOperationsMixin(EmptyClientMixinABC): +class EmptyClientOperationsMixin(ClientMixinABC[PipelineClient, EmptyClientConfiguration]): @overload def put_empty(self, input: _models.EmptyInput, *, content_type: str = "application/json", **kwargs: Any) -> None: diff --git a/packages/typespec-python/test/azure/generated/typetest-model-empty/typetest/model/empty/_utils/__init__.py b/packages/typespec-python/test/azure/generated/typetest-model-empty/typetest/model/empty/_utils/__init__.py new file mode 100644 index 00000000000..8026245c2ab --- /dev/null +++ b/packages/typespec-python/test/azure/generated/typetest-model-empty/typetest/model/empty/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) Python Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/typespec-python/test/azure/generated/typetest-model-enumdiscriminator/typetest/model/enumdiscriminator/_model_base.py b/packages/typespec-python/test/azure/generated/typetest-model-empty/typetest/model/empty/_utils/model_base.py similarity index 100% rename from packages/typespec-python/test/azure/generated/typetest-model-enumdiscriminator/typetest/model/enumdiscriminator/_model_base.py rename to packages/typespec-python/test/azure/generated/typetest-model-empty/typetest/model/empty/_utils/model_base.py diff --git a/packages/typespec-python/test/azure/generated/typetest-model-enumdiscriminator/typetest/model/enumdiscriminator/_serialization.py b/packages/typespec-python/test/azure/generated/typetest-model-empty/typetest/model/empty/_utils/serialization.py similarity index 100% rename from packages/typespec-python/test/azure/generated/typetest-model-enumdiscriminator/typetest/model/enumdiscriminator/_serialization.py rename to packages/typespec-python/test/azure/generated/typetest-model-empty/typetest/model/empty/_utils/serialization.py diff --git a/packages/typespec-python/test/azure/generated/typetest-model-empty/typetest/model/empty/_utils/utils.py b/packages/typespec-python/test/azure/generated/typetest-model-empty/typetest/model/empty/_utils/utils.py new file mode 100644 index 00000000000..35c9c836f85 --- /dev/null +++ b/packages/typespec-python/test/azure/generated/typetest-model-empty/typetest/model/empty/_utils/utils.py @@ -0,0 +1,25 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) Python Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from abc import ABC +from typing import Generic, TYPE_CHECKING, TypeVar + +if TYPE_CHECKING: + from .serialization import Deserializer, Serializer + + +TClient = TypeVar("TClient") +TConfig = TypeVar("TConfig") + + +class ClientMixinABC(ABC, Generic[TClient, TConfig]): + """DO NOT use this class. It is for internal typing use only.""" + + _client: TClient + _config: TConfig + _serialize: "Serializer" + _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/azure/generated/typetest-model-empty/typetest/model/empty/_vendor.py b/packages/typespec-python/test/azure/generated/typetest-model-empty/typetest/model/empty/_vendor.py deleted file mode 100644 index a426658d648..00000000000 --- a/packages/typespec-python/test/azure/generated/typetest-model-empty/typetest/model/empty/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) Python Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import EmptyClientConfiguration - -if TYPE_CHECKING: - from azure.core import PipelineClient - - from ._serialization import Deserializer, Serializer - - -class EmptyClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "PipelineClient" - _config: EmptyClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/azure/generated/typetest-model-empty/typetest/model/empty/aio/_client.py b/packages/typespec-python/test/azure/generated/typetest-model-empty/typetest/model/empty/aio/_client.py index d214dbe99f4..4f7d8db7473 100644 --- a/packages/typespec-python/test/azure/generated/typetest-model-empty/typetest/model/empty/aio/_client.py +++ b/packages/typespec-python/test/azure/generated/typetest-model-empty/typetest/model/empty/aio/_client.py @@ -14,7 +14,7 @@ from azure.core.pipeline import policies from azure.core.rest import AsyncHttpResponse, HttpRequest -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import EmptyClientConfiguration from ._operations import EmptyClientOperationsMixin diff --git a/packages/typespec-python/test/azure/generated/typetest-model-empty/typetest/model/empty/aio/_operations/_operations.py b/packages/typespec-python/test/azure/generated/typetest-model-empty/typetest/model/empty/aio/_operations/_operations.py index 352a0a21182..abb7a1389c3 100644 --- a/packages/typespec-python/test/azure/generated/typetest-model-empty/typetest/model/empty/aio/_operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/typetest-model-empty/typetest/model/empty/aio/_operations/_operations.py @@ -11,6 +11,7 @@ import json from typing import Any, Callable, Dict, IO, Optional, TypeVar, Union, overload +from azure.core import AsyncPipelineClient from azure.core.exceptions import ( ClientAuthenticationError, HttpResponseError, @@ -27,20 +28,21 @@ from azure.core.utils import case_insensitive_dict from ... import models as _models -from ..._model_base import SdkJSONEncoder, _deserialize from ..._operations._operations import ( build_empty_get_empty_request, build_empty_post_round_trip_empty_request, build_empty_put_empty_request, ) -from .._vendor import EmptyClientMixinABC +from ..._utils.model_base import SdkJSONEncoder, _deserialize +from ..._utils.utils import ClientMixinABC +from .._configuration import EmptyClientConfiguration JSON = MutableMapping[str, Any] T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, AsyncHttpResponse], T, Dict[str, Any]], Any]] -class EmptyClientOperationsMixin(EmptyClientMixinABC): +class EmptyClientOperationsMixin(ClientMixinABC[AsyncPipelineClient, EmptyClientConfiguration]): @overload async def put_empty( diff --git a/packages/typespec-python/test/azure/generated/typetest-model-empty/typetest/model/empty/aio/_vendor.py b/packages/typespec-python/test/azure/generated/typetest-model-empty/typetest/model/empty/aio/_vendor.py deleted file mode 100644 index 13fb010ecad..00000000000 --- a/packages/typespec-python/test/azure/generated/typetest-model-empty/typetest/model/empty/aio/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) Python Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import EmptyClientConfiguration - -if TYPE_CHECKING: - from azure.core import AsyncPipelineClient - - from .._serialization import Deserializer, Serializer - - -class EmptyClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "AsyncPipelineClient" - _config: EmptyClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/azure/generated/typetest-model-empty/typetest/model/empty/models/_models.py b/packages/typespec-python/test/azure/generated/typetest-model-empty/typetest/model/empty/models/_models.py index 9ecc9553e5c..5452cf11b8a 100644 --- a/packages/typespec-python/test/azure/generated/typetest-model-empty/typetest/model/empty/models/_models.py +++ b/packages/typespec-python/test/azure/generated/typetest-model-empty/typetest/model/empty/models/_models.py @@ -6,16 +6,16 @@ # Changes may cause incorrect behavior and will be lost if the code is regenerated. # -------------------------------------------------------------------------- -from .. import _model_base +from .._utils.model_base import Model as _Model -class EmptyInput(_model_base.Model): +class EmptyInput(_Model): """Empty model used in operation parameters.""" -class EmptyInputOutput(_model_base.Model): +class EmptyInputOutput(_Model): """Empty model used in both parameter and return type.""" -class EmptyOutput(_model_base.Model): +class EmptyOutput(_Model): """Empty model used in operation return type.""" diff --git a/packages/typespec-python/test/azure/generated/typetest-model-enumdiscriminator/typetest/model/enumdiscriminator/_client.py b/packages/typespec-python/test/azure/generated/typetest-model-enumdiscriminator/typetest/model/enumdiscriminator/_client.py index eeaa58d15a0..41eca39aa60 100644 --- a/packages/typespec-python/test/azure/generated/typetest-model-enumdiscriminator/typetest/model/enumdiscriminator/_client.py +++ b/packages/typespec-python/test/azure/generated/typetest-model-enumdiscriminator/typetest/model/enumdiscriminator/_client.py @@ -16,7 +16,7 @@ from ._configuration import EnumDiscriminatorClientConfiguration from ._operations import EnumDiscriminatorClientOperationsMixin -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer class EnumDiscriminatorClient( diff --git a/packages/typespec-python/test/azure/generated/typetest-model-enumdiscriminator/typetest/model/enumdiscriminator/_operations/_operations.py b/packages/typespec-python/test/azure/generated/typetest-model-enumdiscriminator/typetest/model/enumdiscriminator/_operations/_operations.py index dc9bda5794b..b0692e36e0f 100644 --- a/packages/typespec-python/test/azure/generated/typetest-model-enumdiscriminator/typetest/model/enumdiscriminator/_operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/typetest-model-enumdiscriminator/typetest/model/enumdiscriminator/_operations/_operations.py @@ -10,6 +10,7 @@ import json from typing import Any, Callable, Dict, IO, Optional, TypeVar, Union, overload +from azure.core import PipelineClient from azure.core.exceptions import ( ClientAuthenticationError, HttpResponseError, @@ -26,9 +27,10 @@ from azure.core.utils import case_insensitive_dict from .. import models as _models -from .._model_base import SdkJSONEncoder, _deserialize -from .._serialization import Serializer -from .._vendor import EnumDiscriminatorClientMixinABC +from .._configuration import EnumDiscriminatorClientConfiguration +from .._utils.model_base import SdkJSONEncoder, _deserialize +from .._utils.serialization import Serializer +from .._utils.utils import ClientMixinABC JSON = MutableMapping[str, Any] T = TypeVar("T") @@ -162,7 +164,7 @@ def build_enum_discriminator_get_fixed_model_wrong_discriminator_request( # pyl return HttpRequest(method="GET", url=_url, headers=_headers, **kwargs) -class EnumDiscriminatorClientOperationsMixin(EnumDiscriminatorClientMixinABC): +class EnumDiscriminatorClientOperationsMixin(ClientMixinABC[PipelineClient, EnumDiscriminatorClientConfiguration]): @distributed_trace def get_extensible_model(self, **kwargs: Any) -> _models.Dog: diff --git a/packages/typespec-python/test/azure/generated/typetest-model-enumdiscriminator/typetest/model/enumdiscriminator/_utils/__init__.py b/packages/typespec-python/test/azure/generated/typetest-model-enumdiscriminator/typetest/model/enumdiscriminator/_utils/__init__.py new file mode 100644 index 00000000000..8026245c2ab --- /dev/null +++ b/packages/typespec-python/test/azure/generated/typetest-model-enumdiscriminator/typetest/model/enumdiscriminator/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) Python Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/typespec-python/test/azure/generated/typetest-model-nesteddiscriminator/typetest/model/nesteddiscriminator/_model_base.py b/packages/typespec-python/test/azure/generated/typetest-model-enumdiscriminator/typetest/model/enumdiscriminator/_utils/model_base.py similarity index 100% rename from packages/typespec-python/test/azure/generated/typetest-model-nesteddiscriminator/typetest/model/nesteddiscriminator/_model_base.py rename to packages/typespec-python/test/azure/generated/typetest-model-enumdiscriminator/typetest/model/enumdiscriminator/_utils/model_base.py diff --git a/packages/typespec-python/test/azure/generated/typetest-model-nesteddiscriminator/typetest/model/nesteddiscriminator/_serialization.py b/packages/typespec-python/test/azure/generated/typetest-model-enumdiscriminator/typetest/model/enumdiscriminator/_utils/serialization.py similarity index 100% rename from packages/typespec-python/test/azure/generated/typetest-model-nesteddiscriminator/typetest/model/nesteddiscriminator/_serialization.py rename to packages/typespec-python/test/azure/generated/typetest-model-enumdiscriminator/typetest/model/enumdiscriminator/_utils/serialization.py diff --git a/packages/typespec-python/test/azure/generated/typetest-model-enumdiscriminator/typetest/model/enumdiscriminator/_utils/utils.py b/packages/typespec-python/test/azure/generated/typetest-model-enumdiscriminator/typetest/model/enumdiscriminator/_utils/utils.py new file mode 100644 index 00000000000..35c9c836f85 --- /dev/null +++ b/packages/typespec-python/test/azure/generated/typetest-model-enumdiscriminator/typetest/model/enumdiscriminator/_utils/utils.py @@ -0,0 +1,25 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) Python Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from abc import ABC +from typing import Generic, TYPE_CHECKING, TypeVar + +if TYPE_CHECKING: + from .serialization import Deserializer, Serializer + + +TClient = TypeVar("TClient") +TConfig = TypeVar("TConfig") + + +class ClientMixinABC(ABC, Generic[TClient, TConfig]): + """DO NOT use this class. It is for internal typing use only.""" + + _client: TClient + _config: TConfig + _serialize: "Serializer" + _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/azure/generated/typetest-model-enumdiscriminator/typetest/model/enumdiscriminator/_vendor.py b/packages/typespec-python/test/azure/generated/typetest-model-enumdiscriminator/typetest/model/enumdiscriminator/_vendor.py deleted file mode 100644 index 455e121338a..00000000000 --- a/packages/typespec-python/test/azure/generated/typetest-model-enumdiscriminator/typetest/model/enumdiscriminator/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) Python Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import EnumDiscriminatorClientConfiguration - -if TYPE_CHECKING: - from azure.core import PipelineClient - - from ._serialization import Deserializer, Serializer - - -class EnumDiscriminatorClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "PipelineClient" - _config: EnumDiscriminatorClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/azure/generated/typetest-model-enumdiscriminator/typetest/model/enumdiscriminator/aio/_client.py b/packages/typespec-python/test/azure/generated/typetest-model-enumdiscriminator/typetest/model/enumdiscriminator/aio/_client.py index d4152f401d3..f3b5659a8d0 100644 --- a/packages/typespec-python/test/azure/generated/typetest-model-enumdiscriminator/typetest/model/enumdiscriminator/aio/_client.py +++ b/packages/typespec-python/test/azure/generated/typetest-model-enumdiscriminator/typetest/model/enumdiscriminator/aio/_client.py @@ -14,7 +14,7 @@ from azure.core.pipeline import policies from azure.core.rest import AsyncHttpResponse, HttpRequest -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import EnumDiscriminatorClientConfiguration from ._operations import EnumDiscriminatorClientOperationsMixin diff --git a/packages/typespec-python/test/azure/generated/typetest-model-enumdiscriminator/typetest/model/enumdiscriminator/aio/_operations/_operations.py b/packages/typespec-python/test/azure/generated/typetest-model-enumdiscriminator/typetest/model/enumdiscriminator/aio/_operations/_operations.py index a0e9c4f58fb..90ae5c80c8b 100644 --- a/packages/typespec-python/test/azure/generated/typetest-model-enumdiscriminator/typetest/model/enumdiscriminator/aio/_operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/typetest-model-enumdiscriminator/typetest/model/enumdiscriminator/aio/_operations/_operations.py @@ -11,6 +11,7 @@ import json from typing import Any, Callable, Dict, IO, Optional, TypeVar, Union, overload +from azure.core import AsyncPipelineClient from azure.core.exceptions import ( ClientAuthenticationError, HttpResponseError, @@ -27,7 +28,6 @@ from azure.core.utils import case_insensitive_dict from ... import models as _models -from ..._model_base import SdkJSONEncoder, _deserialize from ..._operations._operations import ( build_enum_discriminator_get_extensible_model_missing_discriminator_request, build_enum_discriminator_get_extensible_model_request, @@ -38,14 +38,16 @@ build_enum_discriminator_put_extensible_model_request, build_enum_discriminator_put_fixed_model_request, ) -from .._vendor import EnumDiscriminatorClientMixinABC +from ..._utils.model_base import SdkJSONEncoder, _deserialize +from ..._utils.utils import ClientMixinABC +from .._configuration import EnumDiscriminatorClientConfiguration JSON = MutableMapping[str, Any] T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, AsyncHttpResponse], T, Dict[str, Any]], Any]] -class EnumDiscriminatorClientOperationsMixin(EnumDiscriminatorClientMixinABC): +class EnumDiscriminatorClientOperationsMixin(ClientMixinABC[AsyncPipelineClient, EnumDiscriminatorClientConfiguration]): @distributed_trace_async async def get_extensible_model(self, **kwargs: Any) -> _models.Dog: diff --git a/packages/typespec-python/test/azure/generated/typetest-model-enumdiscriminator/typetest/model/enumdiscriminator/aio/_vendor.py b/packages/typespec-python/test/azure/generated/typetest-model-enumdiscriminator/typetest/model/enumdiscriminator/aio/_vendor.py deleted file mode 100644 index c42b28f6bbe..00000000000 --- a/packages/typespec-python/test/azure/generated/typetest-model-enumdiscriminator/typetest/model/enumdiscriminator/aio/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) Python Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import EnumDiscriminatorClientConfiguration - -if TYPE_CHECKING: - from azure.core import AsyncPipelineClient - - from .._serialization import Deserializer, Serializer - - -class EnumDiscriminatorClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "AsyncPipelineClient" - _config: EnumDiscriminatorClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/azure/generated/typetest-model-enumdiscriminator/typetest/model/enumdiscriminator/models/_models.py b/packages/typespec-python/test/azure/generated/typetest-model-enumdiscriminator/typetest/model/enumdiscriminator/models/_models.py index 1fe05d3dc0c..609edc2fcce 100644 --- a/packages/typespec-python/test/azure/generated/typetest-model-enumdiscriminator/typetest/model/enumdiscriminator/models/_models.py +++ b/packages/typespec-python/test/azure/generated/typetest-model-enumdiscriminator/typetest/model/enumdiscriminator/models/_models.py @@ -10,12 +10,11 @@ from typing import Any, Dict, Literal, Mapping, overload -from .. import _model_base -from .._model_base import rest_discriminator, rest_field +from .._utils.model_base import Model as _Model, rest_discriminator, rest_field from ._enums import DogKind, SnakeKind -class Snake(_model_base.Model): +class Snake(_Model): """Test fixed enum type for discriminator. You probably want to use the sub-classes and not this class directly. Known sub-classes are: @@ -27,7 +26,7 @@ class Snake(_model_base.Model): :vartype length: int """ - __mapping__: Dict[str, _model_base.Model] = {} + __mapping__: Dict[str, _Model] = {} kind: str = rest_discriminator(name="kind", visibility=["read", "create", "update", "delete", "query"]) """discriminator property. Required. \"cobra\"""" length: int = rest_field(visibility=["read", "create", "update", "delete", "query"]) @@ -82,7 +81,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, kind=SnakeKind.COBRA, **kwargs) -class Dog(_model_base.Model): +class Dog(_Model): """Test extensible enum type for discriminator. You probably want to use the sub-classes and not this class directly. Known sub-classes are: @@ -94,7 +93,7 @@ class Dog(_model_base.Model): :vartype weight: int """ - __mapping__: Dict[str, _model_base.Model] = {} + __mapping__: Dict[str, _Model] = {} kind: str = rest_discriminator(name="kind", visibility=["read", "create", "update", "delete", "query"]) """discriminator property. Required. \"golden\"""" weight: int = rest_field(visibility=["read", "create", "update", "delete", "query"]) diff --git a/packages/typespec-python/test/azure/generated/typetest-model-nesteddiscriminator/typetest/model/nesteddiscriminator/_client.py b/packages/typespec-python/test/azure/generated/typetest-model-nesteddiscriminator/typetest/model/nesteddiscriminator/_client.py index 04b02c2986d..1ed32b7b9ed 100644 --- a/packages/typespec-python/test/azure/generated/typetest-model-nesteddiscriminator/typetest/model/nesteddiscriminator/_client.py +++ b/packages/typespec-python/test/azure/generated/typetest-model-nesteddiscriminator/typetest/model/nesteddiscriminator/_client.py @@ -16,7 +16,7 @@ from ._configuration import NestedDiscriminatorClientConfiguration from ._operations import NestedDiscriminatorClientOperationsMixin -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer class NestedDiscriminatorClient( diff --git a/packages/typespec-python/test/azure/generated/typetest-model-nesteddiscriminator/typetest/model/nesteddiscriminator/_operations/_operations.py b/packages/typespec-python/test/azure/generated/typetest-model-nesteddiscriminator/typetest/model/nesteddiscriminator/_operations/_operations.py index c04c2f003ce..f40babc5ad8 100644 --- a/packages/typespec-python/test/azure/generated/typetest-model-nesteddiscriminator/typetest/model/nesteddiscriminator/_operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/typetest-model-nesteddiscriminator/typetest/model/nesteddiscriminator/_operations/_operations.py @@ -10,6 +10,7 @@ import json from typing import Any, Callable, Dict, IO, Optional, TypeVar, Union, overload +from azure.core import PipelineClient from azure.core.exceptions import ( ClientAuthenticationError, HttpResponseError, @@ -26,9 +27,10 @@ from azure.core.utils import case_insensitive_dict from .. import models as _models -from .._model_base import SdkJSONEncoder, _deserialize -from .._serialization import Serializer -from .._vendor import NestedDiscriminatorClientMixinABC +from .._configuration import NestedDiscriminatorClientConfiguration +from .._utils.model_base import SdkJSONEncoder, _deserialize +from .._utils.serialization import Serializer +from .._utils.utils import ClientMixinABC JSON = MutableMapping[str, Any] T = TypeVar("T") @@ -130,7 +132,7 @@ def build_nested_discriminator_get_wrong_discriminator_request( # pylint: disab return HttpRequest(method="GET", url=_url, headers=_headers, **kwargs) -class NestedDiscriminatorClientOperationsMixin(NestedDiscriminatorClientMixinABC): +class NestedDiscriminatorClientOperationsMixin(ClientMixinABC[PipelineClient, NestedDiscriminatorClientConfiguration]): @distributed_trace def get_model(self, **kwargs: Any) -> _models.Fish: diff --git a/packages/typespec-python/test/azure/generated/typetest-model-nesteddiscriminator/typetest/model/nesteddiscriminator/_utils/__init__.py b/packages/typespec-python/test/azure/generated/typetest-model-nesteddiscriminator/typetest/model/nesteddiscriminator/_utils/__init__.py new file mode 100644 index 00000000000..8026245c2ab --- /dev/null +++ b/packages/typespec-python/test/azure/generated/typetest-model-nesteddiscriminator/typetest/model/nesteddiscriminator/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) Python Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/typespec-python/test/azure/generated/typetest-model-notdiscriminated/typetest/model/notdiscriminated/_model_base.py b/packages/typespec-python/test/azure/generated/typetest-model-nesteddiscriminator/typetest/model/nesteddiscriminator/_utils/model_base.py similarity index 100% rename from packages/typespec-python/test/azure/generated/typetest-model-notdiscriminated/typetest/model/notdiscriminated/_model_base.py rename to packages/typespec-python/test/azure/generated/typetest-model-nesteddiscriminator/typetest/model/nesteddiscriminator/_utils/model_base.py diff --git a/packages/typespec-python/test/azure/generated/typetest-model-notdiscriminated/typetest/model/notdiscriminated/_serialization.py b/packages/typespec-python/test/azure/generated/typetest-model-nesteddiscriminator/typetest/model/nesteddiscriminator/_utils/serialization.py similarity index 100% rename from packages/typespec-python/test/azure/generated/typetest-model-notdiscriminated/typetest/model/notdiscriminated/_serialization.py rename to packages/typespec-python/test/azure/generated/typetest-model-nesteddiscriminator/typetest/model/nesteddiscriminator/_utils/serialization.py diff --git a/packages/typespec-python/test/azure/generated/typetest-model-nesteddiscriminator/typetest/model/nesteddiscriminator/_utils/utils.py b/packages/typespec-python/test/azure/generated/typetest-model-nesteddiscriminator/typetest/model/nesteddiscriminator/_utils/utils.py new file mode 100644 index 00000000000..35c9c836f85 --- /dev/null +++ b/packages/typespec-python/test/azure/generated/typetest-model-nesteddiscriminator/typetest/model/nesteddiscriminator/_utils/utils.py @@ -0,0 +1,25 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) Python Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from abc import ABC +from typing import Generic, TYPE_CHECKING, TypeVar + +if TYPE_CHECKING: + from .serialization import Deserializer, Serializer + + +TClient = TypeVar("TClient") +TConfig = TypeVar("TConfig") + + +class ClientMixinABC(ABC, Generic[TClient, TConfig]): + """DO NOT use this class. It is for internal typing use only.""" + + _client: TClient + _config: TConfig + _serialize: "Serializer" + _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/azure/generated/typetest-model-nesteddiscriminator/typetest/model/nesteddiscriminator/_vendor.py b/packages/typespec-python/test/azure/generated/typetest-model-nesteddiscriminator/typetest/model/nesteddiscriminator/_vendor.py deleted file mode 100644 index 93171f5f439..00000000000 --- a/packages/typespec-python/test/azure/generated/typetest-model-nesteddiscriminator/typetest/model/nesteddiscriminator/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) Python Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import NestedDiscriminatorClientConfiguration - -if TYPE_CHECKING: - from azure.core import PipelineClient - - from ._serialization import Deserializer, Serializer - - -class NestedDiscriminatorClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "PipelineClient" - _config: NestedDiscriminatorClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/azure/generated/typetest-model-nesteddiscriminator/typetest/model/nesteddiscriminator/aio/_client.py b/packages/typespec-python/test/azure/generated/typetest-model-nesteddiscriminator/typetest/model/nesteddiscriminator/aio/_client.py index 752b1921d16..4c6a1af56b1 100644 --- a/packages/typespec-python/test/azure/generated/typetest-model-nesteddiscriminator/typetest/model/nesteddiscriminator/aio/_client.py +++ b/packages/typespec-python/test/azure/generated/typetest-model-nesteddiscriminator/typetest/model/nesteddiscriminator/aio/_client.py @@ -14,7 +14,7 @@ from azure.core.pipeline import policies from azure.core.rest import AsyncHttpResponse, HttpRequest -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import NestedDiscriminatorClientConfiguration from ._operations import NestedDiscriminatorClientOperationsMixin diff --git a/packages/typespec-python/test/azure/generated/typetest-model-nesteddiscriminator/typetest/model/nesteddiscriminator/aio/_operations/_operations.py b/packages/typespec-python/test/azure/generated/typetest-model-nesteddiscriminator/typetest/model/nesteddiscriminator/aio/_operations/_operations.py index 9a9da3fcff5..60978bdd6c9 100644 --- a/packages/typespec-python/test/azure/generated/typetest-model-nesteddiscriminator/typetest/model/nesteddiscriminator/aio/_operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/typetest-model-nesteddiscriminator/typetest/model/nesteddiscriminator/aio/_operations/_operations.py @@ -11,6 +11,7 @@ import json from typing import Any, Callable, Dict, IO, Optional, TypeVar, Union, overload +from azure.core import AsyncPipelineClient from azure.core.exceptions import ( ClientAuthenticationError, HttpResponseError, @@ -27,7 +28,6 @@ from azure.core.utils import case_insensitive_dict from ... import models as _models -from ..._model_base import SdkJSONEncoder, _deserialize from ..._operations._operations import ( build_nested_discriminator_get_missing_discriminator_request, build_nested_discriminator_get_model_request, @@ -36,14 +36,18 @@ build_nested_discriminator_put_model_request, build_nested_discriminator_put_recursive_model_request, ) -from .._vendor import NestedDiscriminatorClientMixinABC +from ..._utils.model_base import SdkJSONEncoder, _deserialize +from ..._utils.utils import ClientMixinABC +from .._configuration import NestedDiscriminatorClientConfiguration JSON = MutableMapping[str, Any] T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, AsyncHttpResponse], T, Dict[str, Any]], Any]] -class NestedDiscriminatorClientOperationsMixin(NestedDiscriminatorClientMixinABC): +class NestedDiscriminatorClientOperationsMixin( + ClientMixinABC[AsyncPipelineClient, NestedDiscriminatorClientConfiguration] +): @distributed_trace_async async def get_model(self, **kwargs: Any) -> _models.Fish: diff --git a/packages/typespec-python/test/azure/generated/typetest-model-nesteddiscriminator/typetest/model/nesteddiscriminator/aio/_vendor.py b/packages/typespec-python/test/azure/generated/typetest-model-nesteddiscriminator/typetest/model/nesteddiscriminator/aio/_vendor.py deleted file mode 100644 index a09ae7669a0..00000000000 --- a/packages/typespec-python/test/azure/generated/typetest-model-nesteddiscriminator/typetest/model/nesteddiscriminator/aio/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) Python Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import NestedDiscriminatorClientConfiguration - -if TYPE_CHECKING: - from azure.core import AsyncPipelineClient - - from .._serialization import Deserializer, Serializer - - -class NestedDiscriminatorClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "AsyncPipelineClient" - _config: NestedDiscriminatorClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/azure/generated/typetest-model-nesteddiscriminator/typetest/model/nesteddiscriminator/models/_models.py b/packages/typespec-python/test/azure/generated/typetest-model-nesteddiscriminator/typetest/model/nesteddiscriminator/models/_models.py index 28f21fdbba1..783273c6ebb 100644 --- a/packages/typespec-python/test/azure/generated/typetest-model-nesteddiscriminator/typetest/model/nesteddiscriminator/models/_models.py +++ b/packages/typespec-python/test/azure/generated/typetest-model-nesteddiscriminator/typetest/model/nesteddiscriminator/models/_models.py @@ -10,14 +10,13 @@ from typing import Any, Dict, List, Literal, Mapping, Optional, TYPE_CHECKING, overload -from .. import _model_base -from .._model_base import rest_discriminator, rest_field +from .._utils.model_base import Model as _Model, rest_discriminator, rest_field if TYPE_CHECKING: from .. import models as _models -class Fish(_model_base.Model): +class Fish(_Model): """This is base model for polymorphic multiple levels inheritance with a discriminator. You probably want to use the sub-classes and not this class directly. Known sub-classes are: @@ -29,7 +28,7 @@ class Fish(_model_base.Model): :vartype age: int """ - __mapping__: Dict[str, _model_base.Model] = {} + __mapping__: Dict[str, _Model] = {} kind: str = rest_discriminator(name="kind") """Discriminator property for Fish. Required. Default value is None.""" age: int = rest_field(visibility=["read", "create", "update", "delete", "query"]) @@ -69,7 +68,7 @@ class Shark(Fish, discriminator="shark"): :vartype sharktype: str """ - __mapping__: Dict[str, _model_base.Model] = {} + __mapping__: Dict[str, _Model] = {} kind: Literal["shark"] = rest_discriminator(name="kind", visibility=["read", "create", "update", "delete", "query"]) # type: ignore """Required. Default value is \"shark\".""" sharktype: str = rest_discriminator(name="sharktype", visibility=["read", "create", "update", "delete", "query"]) @@ -105,7 +104,7 @@ class GoblinShark(Shark, discriminator="goblin"): :vartype sharktype: str """ - __mapping__: Dict[str, _model_base.Model] = {} + __mapping__: Dict[str, _Model] = {} sharktype: Literal["goblin"] = rest_discriminator(name="sharktype", visibility=["read", "create", "update", "delete", "query"]) # type: ignore """Required. Default value is \"goblin\".""" @@ -181,7 +180,7 @@ class SawShark(Shark, discriminator="saw"): :vartype sharktype: str """ - __mapping__: Dict[str, _model_base.Model] = {} + __mapping__: Dict[str, _Model] = {} sharktype: Literal["saw"] = rest_discriminator(name="sharktype", visibility=["read", "create", "update", "delete", "query"]) # type: ignore """Required. Default value is \"saw\".""" diff --git a/packages/typespec-python/test/azure/generated/typetest-model-notdiscriminated/typetest/model/notdiscriminated/_client.py b/packages/typespec-python/test/azure/generated/typetest-model-notdiscriminated/typetest/model/notdiscriminated/_client.py index 289273a7e5d..9ca9d2235ac 100644 --- a/packages/typespec-python/test/azure/generated/typetest-model-notdiscriminated/typetest/model/notdiscriminated/_client.py +++ b/packages/typespec-python/test/azure/generated/typetest-model-notdiscriminated/typetest/model/notdiscriminated/_client.py @@ -16,7 +16,7 @@ from ._configuration import NotDiscriminatedClientConfiguration from ._operations import NotDiscriminatedClientOperationsMixin -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer class NotDiscriminatedClient( diff --git a/packages/typespec-python/test/azure/generated/typetest-model-notdiscriminated/typetest/model/notdiscriminated/_operations/_operations.py b/packages/typespec-python/test/azure/generated/typetest-model-notdiscriminated/typetest/model/notdiscriminated/_operations/_operations.py index 661fc783609..4c2f528e12a 100644 --- a/packages/typespec-python/test/azure/generated/typetest-model-notdiscriminated/typetest/model/notdiscriminated/_operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/typetest-model-notdiscriminated/typetest/model/notdiscriminated/_operations/_operations.py @@ -10,6 +10,7 @@ import json from typing import Any, Callable, Dict, IO, Optional, TypeVar, Union, overload +from azure.core import PipelineClient from azure.core.exceptions import ( ClientAuthenticationError, HttpResponseError, @@ -26,9 +27,10 @@ from azure.core.utils import case_insensitive_dict from .. import models as _models -from .._model_base import SdkJSONEncoder, _deserialize -from .._serialization import Serializer -from .._vendor import NotDiscriminatedClientMixinABC +from .._configuration import NotDiscriminatedClientConfiguration +from .._utils.model_base import SdkJSONEncoder, _deserialize +from .._utils.serialization import Serializer +from .._utils.utils import ClientMixinABC JSON = MutableMapping[str, Any] T = TypeVar("T") @@ -83,7 +85,7 @@ def build_not_discriminated_put_valid_request(**kwargs: Any) -> HttpRequest: # return HttpRequest(method="PUT", url=_url, headers=_headers, **kwargs) -class NotDiscriminatedClientOperationsMixin(NotDiscriminatedClientMixinABC): +class NotDiscriminatedClientOperationsMixin(ClientMixinABC[PipelineClient, NotDiscriminatedClientConfiguration]): @overload def post_valid(self, input: _models.Siamese, *, content_type: str = "application/json", **kwargs: Any) -> None: diff --git a/packages/typespec-python/test/azure/generated/typetest-model-notdiscriminated/typetest/model/notdiscriminated/_utils/__init__.py b/packages/typespec-python/test/azure/generated/typetest-model-notdiscriminated/typetest/model/notdiscriminated/_utils/__init__.py new file mode 100644 index 00000000000..8026245c2ab --- /dev/null +++ b/packages/typespec-python/test/azure/generated/typetest-model-notdiscriminated/typetest/model/notdiscriminated/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) Python Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/typespec-python/test/azure/generated/typetest-model-recursive/typetest/model/recursive/_model_base.py b/packages/typespec-python/test/azure/generated/typetest-model-notdiscriminated/typetest/model/notdiscriminated/_utils/model_base.py similarity index 100% rename from packages/typespec-python/test/azure/generated/typetest-model-recursive/typetest/model/recursive/_model_base.py rename to packages/typespec-python/test/azure/generated/typetest-model-notdiscriminated/typetest/model/notdiscriminated/_utils/model_base.py diff --git a/packages/typespec-python/test/azure/generated/typetest-model-recursive/typetest/model/recursive/_serialization.py b/packages/typespec-python/test/azure/generated/typetest-model-notdiscriminated/typetest/model/notdiscriminated/_utils/serialization.py similarity index 100% rename from packages/typespec-python/test/azure/generated/typetest-model-recursive/typetest/model/recursive/_serialization.py rename to packages/typespec-python/test/azure/generated/typetest-model-notdiscriminated/typetest/model/notdiscriminated/_utils/serialization.py diff --git a/packages/typespec-python/test/azure/generated/typetest-model-notdiscriminated/typetest/model/notdiscriminated/_utils/utils.py b/packages/typespec-python/test/azure/generated/typetest-model-notdiscriminated/typetest/model/notdiscriminated/_utils/utils.py new file mode 100644 index 00000000000..35c9c836f85 --- /dev/null +++ b/packages/typespec-python/test/azure/generated/typetest-model-notdiscriminated/typetest/model/notdiscriminated/_utils/utils.py @@ -0,0 +1,25 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) Python Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from abc import ABC +from typing import Generic, TYPE_CHECKING, TypeVar + +if TYPE_CHECKING: + from .serialization import Deserializer, Serializer + + +TClient = TypeVar("TClient") +TConfig = TypeVar("TConfig") + + +class ClientMixinABC(ABC, Generic[TClient, TConfig]): + """DO NOT use this class. It is for internal typing use only.""" + + _client: TClient + _config: TConfig + _serialize: "Serializer" + _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/azure/generated/typetest-model-notdiscriminated/typetest/model/notdiscriminated/_vendor.py b/packages/typespec-python/test/azure/generated/typetest-model-notdiscriminated/typetest/model/notdiscriminated/_vendor.py deleted file mode 100644 index 181f2d8067b..00000000000 --- a/packages/typespec-python/test/azure/generated/typetest-model-notdiscriminated/typetest/model/notdiscriminated/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) Python Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import NotDiscriminatedClientConfiguration - -if TYPE_CHECKING: - from azure.core import PipelineClient - - from ._serialization import Deserializer, Serializer - - -class NotDiscriminatedClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "PipelineClient" - _config: NotDiscriminatedClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/azure/generated/typetest-model-notdiscriminated/typetest/model/notdiscriminated/aio/_client.py b/packages/typespec-python/test/azure/generated/typetest-model-notdiscriminated/typetest/model/notdiscriminated/aio/_client.py index eb4fbab6f89..d62fb58ae31 100644 --- a/packages/typespec-python/test/azure/generated/typetest-model-notdiscriminated/typetest/model/notdiscriminated/aio/_client.py +++ b/packages/typespec-python/test/azure/generated/typetest-model-notdiscriminated/typetest/model/notdiscriminated/aio/_client.py @@ -14,7 +14,7 @@ from azure.core.pipeline import policies from azure.core.rest import AsyncHttpResponse, HttpRequest -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import NotDiscriminatedClientConfiguration from ._operations import NotDiscriminatedClientOperationsMixin diff --git a/packages/typespec-python/test/azure/generated/typetest-model-notdiscriminated/typetest/model/notdiscriminated/aio/_operations/_operations.py b/packages/typespec-python/test/azure/generated/typetest-model-notdiscriminated/typetest/model/notdiscriminated/aio/_operations/_operations.py index b998fff54b9..aa83bbf04a2 100644 --- a/packages/typespec-python/test/azure/generated/typetest-model-notdiscriminated/typetest/model/notdiscriminated/aio/_operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/typetest-model-notdiscriminated/typetest/model/notdiscriminated/aio/_operations/_operations.py @@ -11,6 +11,7 @@ import json from typing import Any, Callable, Dict, IO, Optional, TypeVar, Union, overload +from azure.core import AsyncPipelineClient from azure.core.exceptions import ( ClientAuthenticationError, HttpResponseError, @@ -27,20 +28,21 @@ from azure.core.utils import case_insensitive_dict from ... import models as _models -from ..._model_base import SdkJSONEncoder, _deserialize from ..._operations._operations import ( build_not_discriminated_get_valid_request, build_not_discriminated_post_valid_request, build_not_discriminated_put_valid_request, ) -from .._vendor import NotDiscriminatedClientMixinABC +from ..._utils.model_base import SdkJSONEncoder, _deserialize +from ..._utils.utils import ClientMixinABC +from .._configuration import NotDiscriminatedClientConfiguration JSON = MutableMapping[str, Any] T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, AsyncHttpResponse], T, Dict[str, Any]], Any]] -class NotDiscriminatedClientOperationsMixin(NotDiscriminatedClientMixinABC): +class NotDiscriminatedClientOperationsMixin(ClientMixinABC[AsyncPipelineClient, NotDiscriminatedClientConfiguration]): @overload async def post_valid( diff --git a/packages/typespec-python/test/azure/generated/typetest-model-notdiscriminated/typetest/model/notdiscriminated/aio/_vendor.py b/packages/typespec-python/test/azure/generated/typetest-model-notdiscriminated/typetest/model/notdiscriminated/aio/_vendor.py deleted file mode 100644 index bbe77210d78..00000000000 --- a/packages/typespec-python/test/azure/generated/typetest-model-notdiscriminated/typetest/model/notdiscriminated/aio/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) Python Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import NotDiscriminatedClientConfiguration - -if TYPE_CHECKING: - from azure.core import AsyncPipelineClient - - from .._serialization import Deserializer, Serializer - - -class NotDiscriminatedClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "AsyncPipelineClient" - _config: NotDiscriminatedClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/azure/generated/typetest-model-notdiscriminated/typetest/model/notdiscriminated/models/_models.py b/packages/typespec-python/test/azure/generated/typetest-model-notdiscriminated/typetest/model/notdiscriminated/models/_models.py index b605546e929..be87f1155db 100644 --- a/packages/typespec-python/test/azure/generated/typetest-model-notdiscriminated/typetest/model/notdiscriminated/models/_models.py +++ b/packages/typespec-python/test/azure/generated/typetest-model-notdiscriminated/typetest/model/notdiscriminated/models/_models.py @@ -9,11 +9,10 @@ from typing import Any, Mapping, overload -from .. import _model_base -from .._model_base import rest_field +from .._utils.model_base import Model as _Model, rest_field -class Pet(_model_base.Model): +class Pet(_Model): """This is base model for not-discriminated normal multiple levels inheritance. :ivar name: Required. diff --git a/packages/typespec-python/test/azure/generated/typetest-model-recursive/typetest/model/recursive/_client.py b/packages/typespec-python/test/azure/generated/typetest-model-recursive/typetest/model/recursive/_client.py index 7874a42e0da..14cf9d99d0e 100644 --- a/packages/typespec-python/test/azure/generated/typetest-model-recursive/typetest/model/recursive/_client.py +++ b/packages/typespec-python/test/azure/generated/typetest-model-recursive/typetest/model/recursive/_client.py @@ -16,7 +16,7 @@ from ._configuration import RecursiveClientConfiguration from ._operations import RecursiveClientOperationsMixin -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer class RecursiveClient(RecursiveClientOperationsMixin): # pylint: disable=client-accepts-api-version-keyword diff --git a/packages/typespec-python/test/azure/generated/typetest-model-recursive/typetest/model/recursive/_operations/_operations.py b/packages/typespec-python/test/azure/generated/typetest-model-recursive/typetest/model/recursive/_operations/_operations.py index 990ef59ca46..7d497d3b2f9 100644 --- a/packages/typespec-python/test/azure/generated/typetest-model-recursive/typetest/model/recursive/_operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/typetest-model-recursive/typetest/model/recursive/_operations/_operations.py @@ -10,6 +10,7 @@ import json from typing import Any, Callable, Dict, IO, Optional, TypeVar, Union, overload +from azure.core import PipelineClient from azure.core.exceptions import ( ClientAuthenticationError, HttpResponseError, @@ -26,9 +27,10 @@ from azure.core.utils import case_insensitive_dict from .. import models as _models -from .._model_base import SdkJSONEncoder, _deserialize -from .._serialization import Serializer -from .._vendor import RecursiveClientMixinABC +from .._configuration import RecursiveClientConfiguration +from .._utils.model_base import SdkJSONEncoder, _deserialize +from .._utils.serialization import Serializer +from .._utils.utils import ClientMixinABC JSON = MutableMapping[str, Any] T = TypeVar("T") @@ -66,7 +68,7 @@ def build_recursive_get_request(**kwargs: Any) -> HttpRequest: return HttpRequest(method="GET", url=_url, headers=_headers, **kwargs) -class RecursiveClientOperationsMixin(RecursiveClientMixinABC): +class RecursiveClientOperationsMixin(ClientMixinABC[PipelineClient, RecursiveClientConfiguration]): @overload def put(self, input: _models.Extension, *, content_type: str = "application/json", **kwargs: Any) -> None: diff --git a/packages/typespec-python/test/azure/generated/typetest-model-recursive/typetest/model/recursive/_utils/__init__.py b/packages/typespec-python/test/azure/generated/typetest-model-recursive/typetest/model/recursive/_utils/__init__.py new file mode 100644 index 00000000000..8026245c2ab --- /dev/null +++ b/packages/typespec-python/test/azure/generated/typetest-model-recursive/typetest/model/recursive/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) Python Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/typespec-python/test/azure/generated/typetest-model-singlediscriminator/typetest/model/singlediscriminator/_model_base.py b/packages/typespec-python/test/azure/generated/typetest-model-recursive/typetest/model/recursive/_utils/model_base.py similarity index 100% rename from packages/typespec-python/test/azure/generated/typetest-model-singlediscriminator/typetest/model/singlediscriminator/_model_base.py rename to packages/typespec-python/test/azure/generated/typetest-model-recursive/typetest/model/recursive/_utils/model_base.py diff --git a/packages/typespec-python/test/azure/generated/typetest-model-singlediscriminator/typetest/model/singlediscriminator/_serialization.py b/packages/typespec-python/test/azure/generated/typetest-model-recursive/typetest/model/recursive/_utils/serialization.py similarity index 100% rename from packages/typespec-python/test/azure/generated/typetest-model-singlediscriminator/typetest/model/singlediscriminator/_serialization.py rename to packages/typespec-python/test/azure/generated/typetest-model-recursive/typetest/model/recursive/_utils/serialization.py diff --git a/packages/typespec-python/test/azure/generated/typetest-model-recursive/typetest/model/recursive/_utils/utils.py b/packages/typespec-python/test/azure/generated/typetest-model-recursive/typetest/model/recursive/_utils/utils.py new file mode 100644 index 00000000000..35c9c836f85 --- /dev/null +++ b/packages/typespec-python/test/azure/generated/typetest-model-recursive/typetest/model/recursive/_utils/utils.py @@ -0,0 +1,25 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) Python Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from abc import ABC +from typing import Generic, TYPE_CHECKING, TypeVar + +if TYPE_CHECKING: + from .serialization import Deserializer, Serializer + + +TClient = TypeVar("TClient") +TConfig = TypeVar("TConfig") + + +class ClientMixinABC(ABC, Generic[TClient, TConfig]): + """DO NOT use this class. It is for internal typing use only.""" + + _client: TClient + _config: TConfig + _serialize: "Serializer" + _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/azure/generated/typetest-model-recursive/typetest/model/recursive/_vendor.py b/packages/typespec-python/test/azure/generated/typetest-model-recursive/typetest/model/recursive/_vendor.py deleted file mode 100644 index 1ed2509c3b6..00000000000 --- a/packages/typespec-python/test/azure/generated/typetest-model-recursive/typetest/model/recursive/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) Python Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import RecursiveClientConfiguration - -if TYPE_CHECKING: - from azure.core import PipelineClient - - from ._serialization import Deserializer, Serializer - - -class RecursiveClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "PipelineClient" - _config: RecursiveClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/azure/generated/typetest-model-recursive/typetest/model/recursive/aio/_client.py b/packages/typespec-python/test/azure/generated/typetest-model-recursive/typetest/model/recursive/aio/_client.py index 19dffcaf753..0d19e7d10f6 100644 --- a/packages/typespec-python/test/azure/generated/typetest-model-recursive/typetest/model/recursive/aio/_client.py +++ b/packages/typespec-python/test/azure/generated/typetest-model-recursive/typetest/model/recursive/aio/_client.py @@ -14,7 +14,7 @@ from azure.core.pipeline import policies from azure.core.rest import AsyncHttpResponse, HttpRequest -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import RecursiveClientConfiguration from ._operations import RecursiveClientOperationsMixin diff --git a/packages/typespec-python/test/azure/generated/typetest-model-recursive/typetest/model/recursive/aio/_operations/_operations.py b/packages/typespec-python/test/azure/generated/typetest-model-recursive/typetest/model/recursive/aio/_operations/_operations.py index a00f30cc242..eb03640ef6b 100644 --- a/packages/typespec-python/test/azure/generated/typetest-model-recursive/typetest/model/recursive/aio/_operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/typetest-model-recursive/typetest/model/recursive/aio/_operations/_operations.py @@ -11,6 +11,7 @@ import json from typing import Any, Callable, Dict, IO, Optional, TypeVar, Union, overload +from azure.core import AsyncPipelineClient from azure.core.exceptions import ( ClientAuthenticationError, HttpResponseError, @@ -27,16 +28,17 @@ from azure.core.utils import case_insensitive_dict from ... import models as _models -from ..._model_base import SdkJSONEncoder, _deserialize from ..._operations._operations import build_recursive_get_request, build_recursive_put_request -from .._vendor import RecursiveClientMixinABC +from ..._utils.model_base import SdkJSONEncoder, _deserialize +from ..._utils.utils import ClientMixinABC +from .._configuration import RecursiveClientConfiguration JSON = MutableMapping[str, Any] T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, AsyncHttpResponse], T, Dict[str, Any]], Any]] -class RecursiveClientOperationsMixin(RecursiveClientMixinABC): +class RecursiveClientOperationsMixin(ClientMixinABC[AsyncPipelineClient, RecursiveClientConfiguration]): @overload async def put(self, input: _models.Extension, *, content_type: str = "application/json", **kwargs: Any) -> None: diff --git a/packages/typespec-python/test/azure/generated/typetest-model-recursive/typetest/model/recursive/aio/_vendor.py b/packages/typespec-python/test/azure/generated/typetest-model-recursive/typetest/model/recursive/aio/_vendor.py deleted file mode 100644 index 8f54ccac103..00000000000 --- a/packages/typespec-python/test/azure/generated/typetest-model-recursive/typetest/model/recursive/aio/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) Python Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import RecursiveClientConfiguration - -if TYPE_CHECKING: - from azure.core import AsyncPipelineClient - - from .._serialization import Deserializer, Serializer - - -class RecursiveClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "AsyncPipelineClient" - _config: RecursiveClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/azure/generated/typetest-model-recursive/typetest/model/recursive/models/_models.py b/packages/typespec-python/test/azure/generated/typetest-model-recursive/typetest/model/recursive/models/_models.py index 0e47753623f..b891d4c5698 100644 --- a/packages/typespec-python/test/azure/generated/typetest-model-recursive/typetest/model/recursive/models/_models.py +++ b/packages/typespec-python/test/azure/generated/typetest-model-recursive/typetest/model/recursive/models/_models.py @@ -9,14 +9,13 @@ from typing import Any, List, Mapping, Optional, TYPE_CHECKING, overload -from .. import _model_base -from .._model_base import rest_field +from .._utils.model_base import Model as _Model, rest_field if TYPE_CHECKING: from .. import models as _models -class Element(_model_base.Model): +class Element(_Model): """element. :ivar extension: diff --git a/packages/typespec-python/test/azure/generated/typetest-model-singlediscriminator/typetest/model/singlediscriminator/_client.py b/packages/typespec-python/test/azure/generated/typetest-model-singlediscriminator/typetest/model/singlediscriminator/_client.py index 4c7755fde05..dffc6b98b9c 100644 --- a/packages/typespec-python/test/azure/generated/typetest-model-singlediscriminator/typetest/model/singlediscriminator/_client.py +++ b/packages/typespec-python/test/azure/generated/typetest-model-singlediscriminator/typetest/model/singlediscriminator/_client.py @@ -16,7 +16,7 @@ from ._configuration import SingleDiscriminatorClientConfiguration from ._operations import SingleDiscriminatorClientOperationsMixin -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer class SingleDiscriminatorClient( diff --git a/packages/typespec-python/test/azure/generated/typetest-model-singlediscriminator/typetest/model/singlediscriminator/_operations/_operations.py b/packages/typespec-python/test/azure/generated/typetest-model-singlediscriminator/typetest/model/singlediscriminator/_operations/_operations.py index a63a244aad4..5b3591465f2 100644 --- a/packages/typespec-python/test/azure/generated/typetest-model-singlediscriminator/typetest/model/singlediscriminator/_operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/typetest-model-singlediscriminator/typetest/model/singlediscriminator/_operations/_operations.py @@ -10,6 +10,7 @@ import json from typing import Any, Callable, Dict, IO, Optional, TypeVar, Union, overload +from azure.core import PipelineClient from azure.core.exceptions import ( ClientAuthenticationError, HttpResponseError, @@ -26,9 +27,10 @@ from azure.core.utils import case_insensitive_dict from .. import models as _models -from .._model_base import SdkJSONEncoder, _deserialize -from .._serialization import Serializer -from .._vendor import SingleDiscriminatorClientMixinABC +from .._configuration import SingleDiscriminatorClientConfiguration +from .._utils.model_base import SdkJSONEncoder, _deserialize +from .._utils.serialization import Serializer +from .._utils.utils import ClientMixinABC JSON = MutableMapping[str, Any] T = TypeVar("T") @@ -144,7 +146,7 @@ def build_single_discriminator_get_legacy_model_request(**kwargs: Any) -> HttpRe return HttpRequest(method="GET", url=_url, headers=_headers, **kwargs) -class SingleDiscriminatorClientOperationsMixin(SingleDiscriminatorClientMixinABC): +class SingleDiscriminatorClientOperationsMixin(ClientMixinABC[PipelineClient, SingleDiscriminatorClientConfiguration]): @distributed_trace def get_model(self, **kwargs: Any) -> _models.Bird: diff --git a/packages/typespec-python/test/azure/generated/typetest-model-singlediscriminator/typetest/model/singlediscriminator/_utils/__init__.py b/packages/typespec-python/test/azure/generated/typetest-model-singlediscriminator/typetest/model/singlediscriminator/_utils/__init__.py new file mode 100644 index 00000000000..8026245c2ab --- /dev/null +++ b/packages/typespec-python/test/azure/generated/typetest-model-singlediscriminator/typetest/model/singlediscriminator/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) Python Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/typespec-python/test/azure/generated/typetest-model-usage/typetest/model/usage/_model_base.py b/packages/typespec-python/test/azure/generated/typetest-model-singlediscriminator/typetest/model/singlediscriminator/_utils/model_base.py similarity index 100% rename from packages/typespec-python/test/azure/generated/typetest-model-usage/typetest/model/usage/_model_base.py rename to packages/typespec-python/test/azure/generated/typetest-model-singlediscriminator/typetest/model/singlediscriminator/_utils/model_base.py diff --git a/packages/typespec-python/test/azure/generated/typetest-model-usage/typetest/model/usage/_serialization.py b/packages/typespec-python/test/azure/generated/typetest-model-singlediscriminator/typetest/model/singlediscriminator/_utils/serialization.py similarity index 100% rename from packages/typespec-python/test/azure/generated/typetest-model-usage/typetest/model/usage/_serialization.py rename to packages/typespec-python/test/azure/generated/typetest-model-singlediscriminator/typetest/model/singlediscriminator/_utils/serialization.py diff --git a/packages/typespec-python/test/azure/generated/typetest-model-singlediscriminator/typetest/model/singlediscriminator/_utils/utils.py b/packages/typespec-python/test/azure/generated/typetest-model-singlediscriminator/typetest/model/singlediscriminator/_utils/utils.py new file mode 100644 index 00000000000..35c9c836f85 --- /dev/null +++ b/packages/typespec-python/test/azure/generated/typetest-model-singlediscriminator/typetest/model/singlediscriminator/_utils/utils.py @@ -0,0 +1,25 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) Python Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from abc import ABC +from typing import Generic, TYPE_CHECKING, TypeVar + +if TYPE_CHECKING: + from .serialization import Deserializer, Serializer + + +TClient = TypeVar("TClient") +TConfig = TypeVar("TConfig") + + +class ClientMixinABC(ABC, Generic[TClient, TConfig]): + """DO NOT use this class. It is for internal typing use only.""" + + _client: TClient + _config: TConfig + _serialize: "Serializer" + _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/azure/generated/typetest-model-singlediscriminator/typetest/model/singlediscriminator/_vendor.py b/packages/typespec-python/test/azure/generated/typetest-model-singlediscriminator/typetest/model/singlediscriminator/_vendor.py deleted file mode 100644 index ae3d24181dc..00000000000 --- a/packages/typespec-python/test/azure/generated/typetest-model-singlediscriminator/typetest/model/singlediscriminator/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) Python Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import SingleDiscriminatorClientConfiguration - -if TYPE_CHECKING: - from azure.core import PipelineClient - - from ._serialization import Deserializer, Serializer - - -class SingleDiscriminatorClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "PipelineClient" - _config: SingleDiscriminatorClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/azure/generated/typetest-model-singlediscriminator/typetest/model/singlediscriminator/aio/_client.py b/packages/typespec-python/test/azure/generated/typetest-model-singlediscriminator/typetest/model/singlediscriminator/aio/_client.py index 8da20806dab..678e4ebad44 100644 --- a/packages/typespec-python/test/azure/generated/typetest-model-singlediscriminator/typetest/model/singlediscriminator/aio/_client.py +++ b/packages/typespec-python/test/azure/generated/typetest-model-singlediscriminator/typetest/model/singlediscriminator/aio/_client.py @@ -14,7 +14,7 @@ from azure.core.pipeline import policies from azure.core.rest import AsyncHttpResponse, HttpRequest -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import SingleDiscriminatorClientConfiguration from ._operations import SingleDiscriminatorClientOperationsMixin diff --git a/packages/typespec-python/test/azure/generated/typetest-model-singlediscriminator/typetest/model/singlediscriminator/aio/_operations/_operations.py b/packages/typespec-python/test/azure/generated/typetest-model-singlediscriminator/typetest/model/singlediscriminator/aio/_operations/_operations.py index 4973f3a5c0b..15ffe307ad1 100644 --- a/packages/typespec-python/test/azure/generated/typetest-model-singlediscriminator/typetest/model/singlediscriminator/aio/_operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/typetest-model-singlediscriminator/typetest/model/singlediscriminator/aio/_operations/_operations.py @@ -11,6 +11,7 @@ import json from typing import Any, Callable, Dict, IO, Optional, TypeVar, Union, overload +from azure.core import AsyncPipelineClient from azure.core.exceptions import ( ClientAuthenticationError, HttpResponseError, @@ -27,7 +28,6 @@ from azure.core.utils import case_insensitive_dict from ... import models as _models -from ..._model_base import SdkJSONEncoder, _deserialize from ..._operations._operations import ( build_single_discriminator_get_legacy_model_request, build_single_discriminator_get_missing_discriminator_request, @@ -37,14 +37,18 @@ build_single_discriminator_put_model_request, build_single_discriminator_put_recursive_model_request, ) -from .._vendor import SingleDiscriminatorClientMixinABC +from ..._utils.model_base import SdkJSONEncoder, _deserialize +from ..._utils.utils import ClientMixinABC +from .._configuration import SingleDiscriminatorClientConfiguration JSON = MutableMapping[str, Any] T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, AsyncHttpResponse], T, Dict[str, Any]], Any]] -class SingleDiscriminatorClientOperationsMixin(SingleDiscriminatorClientMixinABC): +class SingleDiscriminatorClientOperationsMixin( + ClientMixinABC[AsyncPipelineClient, SingleDiscriminatorClientConfiguration] +): @distributed_trace_async async def get_model(self, **kwargs: Any) -> _models.Bird: diff --git a/packages/typespec-python/test/azure/generated/typetest-model-singlediscriminator/typetest/model/singlediscriminator/aio/_vendor.py b/packages/typespec-python/test/azure/generated/typetest-model-singlediscriminator/typetest/model/singlediscriminator/aio/_vendor.py deleted file mode 100644 index 5eed1f8a91d..00000000000 --- a/packages/typespec-python/test/azure/generated/typetest-model-singlediscriminator/typetest/model/singlediscriminator/aio/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) Python Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import SingleDiscriminatorClientConfiguration - -if TYPE_CHECKING: - from azure.core import AsyncPipelineClient - - from .._serialization import Deserializer, Serializer - - -class SingleDiscriminatorClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "AsyncPipelineClient" - _config: SingleDiscriminatorClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/azure/generated/typetest-model-singlediscriminator/typetest/model/singlediscriminator/models/_models.py b/packages/typespec-python/test/azure/generated/typetest-model-singlediscriminator/typetest/model/singlediscriminator/models/_models.py index 8c8631c8c53..17c67e818dc 100644 --- a/packages/typespec-python/test/azure/generated/typetest-model-singlediscriminator/typetest/model/singlediscriminator/models/_models.py +++ b/packages/typespec-python/test/azure/generated/typetest-model-singlediscriminator/typetest/model/singlediscriminator/models/_models.py @@ -10,14 +10,13 @@ from typing import Any, Dict, List, Literal, Mapping, Optional, TYPE_CHECKING, overload -from .. import _model_base -from .._model_base import rest_discriminator, rest_field +from .._utils.model_base import Model as _Model, rest_discriminator, rest_field if TYPE_CHECKING: from .. import models as _models -class Bird(_model_base.Model): +class Bird(_Model): """This is base model for polymorphic single level inheritance with a discriminator. You probably want to use the sub-classes and not this class directly. Known sub-classes are: @@ -29,7 +28,7 @@ class Bird(_model_base.Model): :vartype wingspan: int """ - __mapping__: Dict[str, _model_base.Model] = {} + __mapping__: Dict[str, _Model] = {} kind: str = rest_discriminator(name="kind", visibility=["read", "create", "update", "delete", "query"]) """Required. Default value is None.""" wingspan: int = rest_field(visibility=["read", "create", "update", "delete", "query"]) @@ -54,7 +53,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class Dinosaur(_model_base.Model): +class Dinosaur(_Model): """Define a base class in the legacy way. Discriminator property is not explicitly defined in the model. @@ -67,7 +66,7 @@ class Dinosaur(_model_base.Model): :vartype size: int """ - __mapping__: Dict[str, _model_base.Model] = {} + __mapping__: Dict[str, _Model] = {} kind: str = rest_discriminator(name="kind") """Discriminator property for Dinosaur. Required. Default value is None.""" size: int = rest_field(visibility=["read", "create", "update", "delete", "query"]) diff --git a/packages/typespec-python/test/azure/generated/typetest-model-usage/typetest/model/usage/_client.py b/packages/typespec-python/test/azure/generated/typetest-model-usage/typetest/model/usage/_client.py index dcce6924ad5..c7ae6137275 100644 --- a/packages/typespec-python/test/azure/generated/typetest-model-usage/typetest/model/usage/_client.py +++ b/packages/typespec-python/test/azure/generated/typetest-model-usage/typetest/model/usage/_client.py @@ -16,7 +16,7 @@ from ._configuration import UsageClientConfiguration from ._operations import UsageClientOperationsMixin -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer class UsageClient(UsageClientOperationsMixin): # pylint: disable=client-accepts-api-version-keyword diff --git a/packages/typespec-python/test/azure/generated/typetest-model-usage/typetest/model/usage/_operations/_operations.py b/packages/typespec-python/test/azure/generated/typetest-model-usage/typetest/model/usage/_operations/_operations.py index 1f46b494c0b..9f204bcfe38 100644 --- a/packages/typespec-python/test/azure/generated/typetest-model-usage/typetest/model/usage/_operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/typetest-model-usage/typetest/model/usage/_operations/_operations.py @@ -10,6 +10,7 @@ import json from typing import Any, Callable, Dict, IO, Optional, TypeVar, Union, overload +from azure.core import PipelineClient from azure.core.exceptions import ( ClientAuthenticationError, HttpResponseError, @@ -26,9 +27,10 @@ from azure.core.utils import case_insensitive_dict from .. import models as _models -from .._model_base import SdkJSONEncoder, _deserialize -from .._serialization import Serializer -from .._vendor import UsageClientMixinABC +from .._configuration import UsageClientConfiguration +from .._utils.model_base import SdkJSONEncoder, _deserialize +from .._utils.serialization import Serializer +from .._utils.utils import ClientMixinABC JSON = MutableMapping[str, Any] T = TypeVar("T") @@ -83,7 +85,7 @@ def build_usage_input_and_output_request(**kwargs: Any) -> HttpRequest: return HttpRequest(method="POST", url=_url, headers=_headers, **kwargs) -class UsageClientOperationsMixin(UsageClientMixinABC): +class UsageClientOperationsMixin(ClientMixinABC[PipelineClient, UsageClientConfiguration]): @overload def input(self, input: _models.InputRecord, *, content_type: str = "application/json", **kwargs: Any) -> None: diff --git a/packages/typespec-python/test/azure/generated/typetest-model-usage/typetest/model/usage/_utils/__init__.py b/packages/typespec-python/test/azure/generated/typetest-model-usage/typetest/model/usage/_utils/__init__.py new file mode 100644 index 00000000000..8026245c2ab --- /dev/null +++ b/packages/typespec-python/test/azure/generated/typetest-model-usage/typetest/model/usage/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) Python Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/typespec-python/test/azure/generated/typetest-model-visibility/typetest/model/visibility/_model_base.py b/packages/typespec-python/test/azure/generated/typetest-model-usage/typetest/model/usage/_utils/model_base.py similarity index 100% rename from packages/typespec-python/test/azure/generated/typetest-model-visibility/typetest/model/visibility/_model_base.py rename to packages/typespec-python/test/azure/generated/typetest-model-usage/typetest/model/usage/_utils/model_base.py diff --git a/packages/typespec-python/test/azure/generated/typetest-model-visibility/typetest/model/visibility/_serialization.py b/packages/typespec-python/test/azure/generated/typetest-model-usage/typetest/model/usage/_utils/serialization.py similarity index 100% rename from packages/typespec-python/test/azure/generated/typetest-model-visibility/typetest/model/visibility/_serialization.py rename to packages/typespec-python/test/azure/generated/typetest-model-usage/typetest/model/usage/_utils/serialization.py diff --git a/packages/typespec-python/test/azure/generated/typetest-model-usage/typetest/model/usage/_utils/utils.py b/packages/typespec-python/test/azure/generated/typetest-model-usage/typetest/model/usage/_utils/utils.py new file mode 100644 index 00000000000..35c9c836f85 --- /dev/null +++ b/packages/typespec-python/test/azure/generated/typetest-model-usage/typetest/model/usage/_utils/utils.py @@ -0,0 +1,25 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) Python Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from abc import ABC +from typing import Generic, TYPE_CHECKING, TypeVar + +if TYPE_CHECKING: + from .serialization import Deserializer, Serializer + + +TClient = TypeVar("TClient") +TConfig = TypeVar("TConfig") + + +class ClientMixinABC(ABC, Generic[TClient, TConfig]): + """DO NOT use this class. It is for internal typing use only.""" + + _client: TClient + _config: TConfig + _serialize: "Serializer" + _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/azure/generated/typetest-model-usage/typetest/model/usage/_vendor.py b/packages/typespec-python/test/azure/generated/typetest-model-usage/typetest/model/usage/_vendor.py deleted file mode 100644 index 3d8d44f371b..00000000000 --- a/packages/typespec-python/test/azure/generated/typetest-model-usage/typetest/model/usage/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) Python Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import UsageClientConfiguration - -if TYPE_CHECKING: - from azure.core import PipelineClient - - from ._serialization import Deserializer, Serializer - - -class UsageClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "PipelineClient" - _config: UsageClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/azure/generated/typetest-model-usage/typetest/model/usage/aio/_client.py b/packages/typespec-python/test/azure/generated/typetest-model-usage/typetest/model/usage/aio/_client.py index d51f37810ed..be8db2970a3 100644 --- a/packages/typespec-python/test/azure/generated/typetest-model-usage/typetest/model/usage/aio/_client.py +++ b/packages/typespec-python/test/azure/generated/typetest-model-usage/typetest/model/usage/aio/_client.py @@ -14,7 +14,7 @@ from azure.core.pipeline import policies from azure.core.rest import AsyncHttpResponse, HttpRequest -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import UsageClientConfiguration from ._operations import UsageClientOperationsMixin diff --git a/packages/typespec-python/test/azure/generated/typetest-model-usage/typetest/model/usage/aio/_operations/_operations.py b/packages/typespec-python/test/azure/generated/typetest-model-usage/typetest/model/usage/aio/_operations/_operations.py index 814b96bfbce..92c1084e0f4 100644 --- a/packages/typespec-python/test/azure/generated/typetest-model-usage/typetest/model/usage/aio/_operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/typetest-model-usage/typetest/model/usage/aio/_operations/_operations.py @@ -11,6 +11,7 @@ import json from typing import Any, Callable, Dict, IO, Optional, TypeVar, Union, overload +from azure.core import AsyncPipelineClient from azure.core.exceptions import ( ClientAuthenticationError, HttpResponseError, @@ -27,20 +28,21 @@ from azure.core.utils import case_insensitive_dict from ... import models as _models -from ..._model_base import SdkJSONEncoder, _deserialize from ..._operations._operations import ( build_usage_input_and_output_request, build_usage_input_request, build_usage_output_request, ) -from .._vendor import UsageClientMixinABC +from ..._utils.model_base import SdkJSONEncoder, _deserialize +from ..._utils.utils import ClientMixinABC +from .._configuration import UsageClientConfiguration JSON = MutableMapping[str, Any] T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, AsyncHttpResponse], T, Dict[str, Any]], Any]] -class UsageClientOperationsMixin(UsageClientMixinABC): +class UsageClientOperationsMixin(ClientMixinABC[AsyncPipelineClient, UsageClientConfiguration]): @overload async def input(self, input: _models.InputRecord, *, content_type: str = "application/json", **kwargs: Any) -> None: diff --git a/packages/typespec-python/test/azure/generated/typetest-model-usage/typetest/model/usage/aio/_vendor.py b/packages/typespec-python/test/azure/generated/typetest-model-usage/typetest/model/usage/aio/_vendor.py deleted file mode 100644 index 1de910cdbfe..00000000000 --- a/packages/typespec-python/test/azure/generated/typetest-model-usage/typetest/model/usage/aio/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) Python Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import UsageClientConfiguration - -if TYPE_CHECKING: - from azure.core import AsyncPipelineClient - - from .._serialization import Deserializer, Serializer - - -class UsageClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "AsyncPipelineClient" - _config: UsageClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/azure/generated/typetest-model-usage/typetest/model/usage/models/_models.py b/packages/typespec-python/test/azure/generated/typetest-model-usage/typetest/model/usage/models/_models.py index 70a57c40426..e0e921bbc54 100644 --- a/packages/typespec-python/test/azure/generated/typetest-model-usage/typetest/model/usage/models/_models.py +++ b/packages/typespec-python/test/azure/generated/typetest-model-usage/typetest/model/usage/models/_models.py @@ -9,11 +9,10 @@ from typing import Any, Mapping, overload -from .. import _model_base -from .._model_base import rest_field +from .._utils.model_base import Model as _Model, rest_field -class InputOutputRecord(_model_base.Model): +class InputOutputRecord(_Model): """Record used both as operation parameter and return type. :ivar required_prop: Required. @@ -41,7 +40,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class InputRecord(_model_base.Model): +class InputRecord(_Model): """Record used in operation parameters. :ivar required_prop: Required. @@ -69,7 +68,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class OutputRecord(_model_base.Model): +class OutputRecord(_Model): """Record used in operation return type. :ivar required_prop: Required. diff --git a/packages/typespec-python/test/azure/generated/typetest-model-visibility/typetest/model/visibility/_client.py b/packages/typespec-python/test/azure/generated/typetest-model-visibility/typetest/model/visibility/_client.py index 6bcb252c135..cf9ba9de23d 100644 --- a/packages/typespec-python/test/azure/generated/typetest-model-visibility/typetest/model/visibility/_client.py +++ b/packages/typespec-python/test/azure/generated/typetest-model-visibility/typetest/model/visibility/_client.py @@ -16,7 +16,7 @@ from ._configuration import VisibilityClientConfiguration from ._operations import VisibilityClientOperationsMixin -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer class VisibilityClient(VisibilityClientOperationsMixin): # pylint: disable=client-accepts-api-version-keyword diff --git a/packages/typespec-python/test/azure/generated/typetest-model-visibility/typetest/model/visibility/_operations/_operations.py b/packages/typespec-python/test/azure/generated/typetest-model-visibility/typetest/model/visibility/_operations/_operations.py index 9954e3d434b..827e1627c2d 100644 --- a/packages/typespec-python/test/azure/generated/typetest-model-visibility/typetest/model/visibility/_operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/typetest-model-visibility/typetest/model/visibility/_operations/_operations.py @@ -10,6 +10,7 @@ import json from typing import Any, Callable, Dict, IO, Optional, TypeVar, Union, overload +from azure.core import PipelineClient from azure.core.exceptions import ( ClientAuthenticationError, HttpResponseError, @@ -26,9 +27,10 @@ from azure.core.utils import case_insensitive_dict from .. import models as _models -from .._model_base import SdkJSONEncoder, _deserialize -from .._serialization import Serializer -from .._vendor import VisibilityClientMixinABC +from .._configuration import VisibilityClientConfiguration +from .._utils.model_base import SdkJSONEncoder, _deserialize +from .._utils.serialization import Serializer +from .._utils.utils import ClientMixinABC JSON = MutableMapping[str, Any] T = TypeVar("T") @@ -150,7 +152,7 @@ def build_visibility_put_read_only_model_request(**kwargs: Any) -> HttpRequest: return HttpRequest(method="PUT", url=_url, headers=_headers, **kwargs) -class VisibilityClientOperationsMixin(VisibilityClientMixinABC): +class VisibilityClientOperationsMixin(ClientMixinABC[PipelineClient, VisibilityClientConfiguration]): @overload def get_model( diff --git a/packages/typespec-python/test/azure/generated/typetest-model-visibility/typetest/model/visibility/_utils/__init__.py b/packages/typespec-python/test/azure/generated/typetest-model-visibility/typetest/model/visibility/_utils/__init__.py new file mode 100644 index 00000000000..8026245c2ab --- /dev/null +++ b/packages/typespec-python/test/azure/generated/typetest-model-visibility/typetest/model/visibility/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) Python Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/typespec-python/test/azure/generated/typetest-property-additionalproperties/typetest/property/additionalproperties/_model_base.py b/packages/typespec-python/test/azure/generated/typetest-model-visibility/typetest/model/visibility/_utils/model_base.py similarity index 100% rename from packages/typespec-python/test/azure/generated/typetest-property-additionalproperties/typetest/property/additionalproperties/_model_base.py rename to packages/typespec-python/test/azure/generated/typetest-model-visibility/typetest/model/visibility/_utils/model_base.py diff --git a/packages/typespec-python/test/azure/generated/typetest-property-additionalproperties/typetest/property/additionalproperties/_serialization.py b/packages/typespec-python/test/azure/generated/typetest-model-visibility/typetest/model/visibility/_utils/serialization.py similarity index 100% rename from packages/typespec-python/test/azure/generated/typetest-property-additionalproperties/typetest/property/additionalproperties/_serialization.py rename to packages/typespec-python/test/azure/generated/typetest-model-visibility/typetest/model/visibility/_utils/serialization.py diff --git a/packages/typespec-python/test/azure/generated/typetest-model-visibility/typetest/model/visibility/_utils/utils.py b/packages/typespec-python/test/azure/generated/typetest-model-visibility/typetest/model/visibility/_utils/utils.py new file mode 100644 index 00000000000..35c9c836f85 --- /dev/null +++ b/packages/typespec-python/test/azure/generated/typetest-model-visibility/typetest/model/visibility/_utils/utils.py @@ -0,0 +1,25 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) Python Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from abc import ABC +from typing import Generic, TYPE_CHECKING, TypeVar + +if TYPE_CHECKING: + from .serialization import Deserializer, Serializer + + +TClient = TypeVar("TClient") +TConfig = TypeVar("TConfig") + + +class ClientMixinABC(ABC, Generic[TClient, TConfig]): + """DO NOT use this class. It is for internal typing use only.""" + + _client: TClient + _config: TConfig + _serialize: "Serializer" + _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/azure/generated/typetest-model-visibility/typetest/model/visibility/_vendor.py b/packages/typespec-python/test/azure/generated/typetest-model-visibility/typetest/model/visibility/_vendor.py deleted file mode 100644 index f3eb127559a..00000000000 --- a/packages/typespec-python/test/azure/generated/typetest-model-visibility/typetest/model/visibility/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) Python Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import VisibilityClientConfiguration - -if TYPE_CHECKING: - from azure.core import PipelineClient - - from ._serialization import Deserializer, Serializer - - -class VisibilityClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "PipelineClient" - _config: VisibilityClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/azure/generated/typetest-model-visibility/typetest/model/visibility/aio/_client.py b/packages/typespec-python/test/azure/generated/typetest-model-visibility/typetest/model/visibility/aio/_client.py index 4e1e87d614a..8d64d30a7a2 100644 --- a/packages/typespec-python/test/azure/generated/typetest-model-visibility/typetest/model/visibility/aio/_client.py +++ b/packages/typespec-python/test/azure/generated/typetest-model-visibility/typetest/model/visibility/aio/_client.py @@ -14,7 +14,7 @@ from azure.core.pipeline import policies from azure.core.rest import AsyncHttpResponse, HttpRequest -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import VisibilityClientConfiguration from ._operations import VisibilityClientOperationsMixin diff --git a/packages/typespec-python/test/azure/generated/typetest-model-visibility/typetest/model/visibility/aio/_operations/_operations.py b/packages/typespec-python/test/azure/generated/typetest-model-visibility/typetest/model/visibility/aio/_operations/_operations.py index 87d4b0fb08d..11807a282cc 100644 --- a/packages/typespec-python/test/azure/generated/typetest-model-visibility/typetest/model/visibility/aio/_operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/typetest-model-visibility/typetest/model/visibility/aio/_operations/_operations.py @@ -11,6 +11,7 @@ import json from typing import Any, Callable, Dict, IO, Optional, TypeVar, Union, overload +from azure.core import AsyncPipelineClient from azure.core.exceptions import ( ClientAuthenticationError, HttpResponseError, @@ -27,7 +28,6 @@ from azure.core.utils import case_insensitive_dict from ... import models as _models -from ..._model_base import SdkJSONEncoder, _deserialize from ..._operations._operations import ( build_visibility_delete_model_request, build_visibility_get_model_request, @@ -37,14 +37,16 @@ build_visibility_put_model_request, build_visibility_put_read_only_model_request, ) -from .._vendor import VisibilityClientMixinABC +from ..._utils.model_base import SdkJSONEncoder, _deserialize +from ..._utils.utils import ClientMixinABC +from .._configuration import VisibilityClientConfiguration JSON = MutableMapping[str, Any] T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, AsyncHttpResponse], T, Dict[str, Any]], Any]] -class VisibilityClientOperationsMixin(VisibilityClientMixinABC): +class VisibilityClientOperationsMixin(ClientMixinABC[AsyncPipelineClient, VisibilityClientConfiguration]): @overload async def get_model( diff --git a/packages/typespec-python/test/azure/generated/typetest-model-visibility/typetest/model/visibility/aio/_vendor.py b/packages/typespec-python/test/azure/generated/typetest-model-visibility/typetest/model/visibility/aio/_vendor.py deleted file mode 100644 index 59219e20434..00000000000 --- a/packages/typespec-python/test/azure/generated/typetest-model-visibility/typetest/model/visibility/aio/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) Python Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import VisibilityClientConfiguration - -if TYPE_CHECKING: - from azure.core import AsyncPipelineClient - - from .._serialization import Deserializer, Serializer - - -class VisibilityClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "AsyncPipelineClient" - _config: VisibilityClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/azure/generated/typetest-model-visibility/typetest/model/visibility/models/_models.py b/packages/typespec-python/test/azure/generated/typetest-model-visibility/typetest/model/visibility/models/_models.py index 8bb7ceb2bb3..e4b8dcd1fd4 100644 --- a/packages/typespec-python/test/azure/generated/typetest-model-visibility/typetest/model/visibility/models/_models.py +++ b/packages/typespec-python/test/azure/generated/typetest-model-visibility/typetest/model/visibility/models/_models.py @@ -9,11 +9,10 @@ from typing import Any, Dict, List, Mapping, Optional, overload -from .. import _model_base -from .._model_base import rest_field +from .._utils.model_base import Model as _Model, rest_field -class ReadOnlyModel(_model_base.Model): +class ReadOnlyModel(_Model): """RoundTrip model with readonly optional properties. :ivar optional_nullable_int_list: Optional readonly nullable int list. @@ -28,7 +27,7 @@ class ReadOnlyModel(_model_base.Model): """Optional readonly string dictionary.""" -class VisibilityModel(_model_base.Model): +class VisibilityModel(_Model): """Output model with visibility properties. :ivar read_prop: Required string, illustrating a readonly property. Required. diff --git a/packages/typespec-python/test/azure/generated/typetest-property-additionalproperties/typetest/property/additionalproperties/_client.py b/packages/typespec-python/test/azure/generated/typetest-property-additionalproperties/typetest/property/additionalproperties/_client.py index 0815eeccac6..e727c1f0ac4 100644 --- a/packages/typespec-python/test/azure/generated/typetest-property-additionalproperties/typetest/property/additionalproperties/_client.py +++ b/packages/typespec-python/test/azure/generated/typetest-property-additionalproperties/typetest/property/additionalproperties/_client.py @@ -15,7 +15,7 @@ from azure.core.rest import HttpRequest, HttpResponse from ._configuration import AdditionalPropertiesClientConfiguration -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer from .operations import ( ExtendsDifferentSpreadFloatOperations, ExtendsDifferentSpreadModelArrayOperations, diff --git a/packages/typespec-python/test/azure/generated/typetest-property-additionalproperties/typetest/property/additionalproperties/_utils/__init__.py b/packages/typespec-python/test/azure/generated/typetest-property-additionalproperties/typetest/property/additionalproperties/_utils/__init__.py new file mode 100644 index 00000000000..8026245c2ab --- /dev/null +++ b/packages/typespec-python/test/azure/generated/typetest-property-additionalproperties/typetest/property/additionalproperties/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) Python Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/typespec-python/test/azure/generated/typetest-property-nullable/typetest/property/nullable/_model_base.py b/packages/typespec-python/test/azure/generated/typetest-property-additionalproperties/typetest/property/additionalproperties/_utils/model_base.py similarity index 100% rename from packages/typespec-python/test/azure/generated/typetest-property-nullable/typetest/property/nullable/_model_base.py rename to packages/typespec-python/test/azure/generated/typetest-property-additionalproperties/typetest/property/additionalproperties/_utils/model_base.py diff --git a/packages/typespec-python/test/azure/generated/typetest-property-nullable/typetest/property/nullable/_serialization.py b/packages/typespec-python/test/azure/generated/typetest-property-additionalproperties/typetest/property/additionalproperties/_utils/serialization.py similarity index 100% rename from packages/typespec-python/test/azure/generated/typetest-property-nullable/typetest/property/nullable/_serialization.py rename to packages/typespec-python/test/azure/generated/typetest-property-additionalproperties/typetest/property/additionalproperties/_utils/serialization.py diff --git a/packages/typespec-python/test/azure/generated/typetest-property-additionalproperties/typetest/property/additionalproperties/aio/_client.py b/packages/typespec-python/test/azure/generated/typetest-property-additionalproperties/typetest/property/additionalproperties/aio/_client.py index 9e6d092d7c7..1afeb43acc1 100644 --- a/packages/typespec-python/test/azure/generated/typetest-property-additionalproperties/typetest/property/additionalproperties/aio/_client.py +++ b/packages/typespec-python/test/azure/generated/typetest-property-additionalproperties/typetest/property/additionalproperties/aio/_client.py @@ -14,7 +14,7 @@ from azure.core.pipeline import policies from azure.core.rest import AsyncHttpResponse, HttpRequest -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import AdditionalPropertiesClientConfiguration from .operations import ( ExtendsDifferentSpreadFloatOperations, diff --git a/packages/typespec-python/test/azure/generated/typetest-property-additionalproperties/typetest/property/additionalproperties/aio/operations/_operations.py b/packages/typespec-python/test/azure/generated/typetest-property-additionalproperties/typetest/property/additionalproperties/aio/operations/_operations.py index 918b3df3745..e5bb5b59c71 100644 --- a/packages/typespec-python/test/azure/generated/typetest-property-additionalproperties/typetest/property/additionalproperties/aio/operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/typetest-property-additionalproperties/typetest/property/additionalproperties/aio/operations/_operations.py @@ -28,8 +28,8 @@ from azure.core.utils import case_insensitive_dict from ... import models as _models -from ..._model_base import SdkJSONEncoder, _deserialize -from ..._serialization import Deserializer, Serializer +from ..._utils.model_base import SdkJSONEncoder, _deserialize +from ..._utils.serialization import Deserializer, Serializer from ...operations._operations import ( build_extends_different_spread_float_get_request, build_extends_different_spread_float_put_request, diff --git a/packages/typespec-python/test/azure/generated/typetest-property-additionalproperties/typetest/property/additionalproperties/models/_models.py b/packages/typespec-python/test/azure/generated/typetest-property-additionalproperties/typetest/property/additionalproperties/models/_models.py index 05289245c58..4a0318014f5 100644 --- a/packages/typespec-python/test/azure/generated/typetest-property-additionalproperties/typetest/property/additionalproperties/models/_models.py +++ b/packages/typespec-python/test/azure/generated/typetest-property-additionalproperties/typetest/property/additionalproperties/models/_models.py @@ -11,14 +11,13 @@ import datetime from typing import Any, Dict, List, Literal, Mapping, Optional, TYPE_CHECKING, overload -from .. import _model_base -from .._model_base import rest_discriminator, rest_field +from .._utils.model_base import Model as _Model, rest_discriminator, rest_field if TYPE_CHECKING: from .. import models as _models -class DifferentSpreadFloatRecord(_model_base.Model): +class DifferentSpreadFloatRecord(_Model): """The model spread Record with the different known property type. :ivar name: The id property. Required. @@ -78,7 +77,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class DifferentSpreadModelArrayRecord(_model_base.Model): +class DifferentSpreadModelArrayRecord(_Model): """The model spread Record with the different known property type. :ivar known_prop: Required. @@ -140,7 +139,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class DifferentSpreadModelRecord(_model_base.Model): +class DifferentSpreadModelRecord(_Model): """The model spread Record with the different known property type. :ivar known_prop: Required. @@ -202,7 +201,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class DifferentSpreadStringRecord(_model_base.Model): +class DifferentSpreadStringRecord(_Model): """The model spread Record with the different known property type. :ivar id: The name property. Required. @@ -262,7 +261,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class ExtendsFloatAdditionalProperties(_model_base.Model): +class ExtendsFloatAdditionalProperties(_Model): """The model extends from Record type. :ivar id: The id property. Required. @@ -290,7 +289,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class ExtendsModelAdditionalProperties(_model_base.Model): +class ExtendsModelAdditionalProperties(_Model): """The model extends from Record type. :ivar known_prop: Required. @@ -320,7 +319,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class ExtendsModelArrayAdditionalProperties(_model_base.Model): +class ExtendsModelArrayAdditionalProperties(_Model): """The model extends from Record type. :ivar known_prop: Required. @@ -350,7 +349,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class ExtendsStringAdditionalProperties(_model_base.Model): +class ExtendsStringAdditionalProperties(_Model): """The model extends from Record type. :ivar name: The name property. Required. @@ -378,7 +377,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class ExtendsUnknownAdditionalProperties(_model_base.Model): +class ExtendsUnknownAdditionalProperties(_Model): """The model extends from Record type. :ivar name: The name property. Required. @@ -442,7 +441,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class ExtendsUnknownAdditionalPropertiesDiscriminated(_model_base.Model): # pylint: disable=name-too-long +class ExtendsUnknownAdditionalPropertiesDiscriminated(_Model): # pylint: disable=name-too-long """The model extends from Record with a discriminator. You probably want to use the sub-classes and not this class directly. Known sub-classes are: @@ -454,7 +453,7 @@ class ExtendsUnknownAdditionalPropertiesDiscriminated(_model_base.Model): # pyl :vartype kind: str """ - __mapping__: Dict[str, _model_base.Model] = {} + __mapping__: Dict[str, _Model] = {} name: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) """The name property. Required.""" kind: str = rest_discriminator(name="kind", visibility=["read", "create", "update", "delete", "query"]) @@ -521,7 +520,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, kind="derived", **kwargs) -class IsFloatAdditionalProperties(_model_base.Model): +class IsFloatAdditionalProperties(_Model): """The model is from Record type. :ivar id: The id property. Required. @@ -549,7 +548,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class IsModelAdditionalProperties(_model_base.Model): +class IsModelAdditionalProperties(_Model): """The model is from Record type. :ivar known_prop: Required. @@ -579,7 +578,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class IsModelArrayAdditionalProperties(_model_base.Model): +class IsModelArrayAdditionalProperties(_Model): """The model is from Record type. :ivar known_prop: Required. @@ -609,7 +608,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class IsStringAdditionalProperties(_model_base.Model): +class IsStringAdditionalProperties(_Model): """The model is from Record type. :ivar name: The name property. Required. @@ -637,7 +636,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class IsUnknownAdditionalProperties(_model_base.Model): +class IsUnknownAdditionalProperties(_Model): """The model is from Record type. :ivar name: The name property. Required. @@ -701,7 +700,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class IsUnknownAdditionalPropertiesDiscriminated(_model_base.Model): # pylint: disable=name-too-long +class IsUnknownAdditionalPropertiesDiscriminated(_Model): # pylint: disable=name-too-long """The model is Record with a discriminator. You probably want to use the sub-classes and not this class directly. Known sub-classes are: @@ -713,7 +712,7 @@ class IsUnknownAdditionalPropertiesDiscriminated(_model_base.Model): # pylint: :vartype kind: str """ - __mapping__: Dict[str, _model_base.Model] = {} + __mapping__: Dict[str, _Model] = {} name: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) """The name property. Required.""" kind: str = rest_discriminator(name="kind", visibility=["read", "create", "update", "delete", "query"]) @@ -780,7 +779,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, kind="derived", **kwargs) -class ModelForRecord(_model_base.Model): +class ModelForRecord(_Model): """model for record. :ivar state: The state property. Required. @@ -808,7 +807,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class MultipleSpreadRecord(_model_base.Model): +class MultipleSpreadRecord(_Model): """The model spread Record and Record. :ivar flag: The name property. Required. @@ -836,7 +835,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class SpreadFloatRecord(_model_base.Model): +class SpreadFloatRecord(_Model): """The model spread Record with the same known property type. :ivar id: The id property. Required. @@ -864,7 +863,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class SpreadModelArrayRecord(_model_base.Model): +class SpreadModelArrayRecord(_Model): """SpreadModelArrayRecord. :ivar known_prop: Required. @@ -894,7 +893,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class SpreadModelRecord(_model_base.Model): +class SpreadModelRecord(_Model): """The model spread Record with the same known property type. :ivar known_prop: Required. @@ -924,7 +923,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class SpreadRecordForNonDiscriminatedUnion(_model_base.Model): +class SpreadRecordForNonDiscriminatedUnion(_Model): """The model spread Record. :ivar name: The name property. Required. @@ -952,7 +951,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class SpreadRecordForNonDiscriminatedUnion2(_model_base.Model): +class SpreadRecordForNonDiscriminatedUnion2(_Model): """The model spread Record. :ivar name: The name property. Required. @@ -980,7 +979,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class SpreadRecordForNonDiscriminatedUnion3(_model_base.Model): +class SpreadRecordForNonDiscriminatedUnion3(_Model): """The model spread Record. :ivar name: The name property. Required. @@ -1008,7 +1007,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class SpreadRecordForUnion(_model_base.Model): +class SpreadRecordForUnion(_Model): """The model spread Record. :ivar flag: The name property. Required. @@ -1036,7 +1035,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class SpreadStringRecord(_model_base.Model): +class SpreadStringRecord(_Model): """The model spread Record with the same known property type. :ivar name: The name property. Required. @@ -1064,7 +1063,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class WidgetData0(_model_base.Model): +class WidgetData0(_Model): """WidgetData0. :ivar kind: Required. Default value is "kind0". @@ -1097,7 +1096,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: self.kind: Literal["kind0"] = "kind0" -class WidgetData1(_model_base.Model): +class WidgetData1(_Model): """WidgetData1. :ivar kind: Required. Default value is "kind1". @@ -1136,7 +1135,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: self.kind: Literal["kind1"] = "kind1" -class WidgetData2(_model_base.Model): +class WidgetData2(_Model): """WidgetData2. :ivar kind: Required. Default value is "kind1". diff --git a/packages/typespec-python/test/azure/generated/typetest-property-additionalproperties/typetest/property/additionalproperties/operations/_operations.py b/packages/typespec-python/test/azure/generated/typetest-property-additionalproperties/typetest/property/additionalproperties/operations/_operations.py index 7bdb37b1972..cdbff049c0d 100644 --- a/packages/typespec-python/test/azure/generated/typetest-property-additionalproperties/typetest/property/additionalproperties/operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/typetest-property-additionalproperties/typetest/property/additionalproperties/operations/_operations.py @@ -29,8 +29,8 @@ from .. import models as _models from .._configuration import AdditionalPropertiesClientConfiguration -from .._model_base import SdkJSONEncoder, _deserialize -from .._serialization import Deserializer, Serializer +from .._utils.model_base import SdkJSONEncoder, _deserialize +from .._utils.serialization import Deserializer, Serializer JSON = MutableMapping[str, Any] T = TypeVar("T") diff --git a/packages/typespec-python/test/azure/generated/typetest-property-nullable/typetest/property/nullable/_client.py b/packages/typespec-python/test/azure/generated/typetest-property-nullable/typetest/property/nullable/_client.py index 09c3fb182cf..f7015c59690 100644 --- a/packages/typespec-python/test/azure/generated/typetest-property-nullable/typetest/property/nullable/_client.py +++ b/packages/typespec-python/test/azure/generated/typetest-property-nullable/typetest/property/nullable/_client.py @@ -15,7 +15,7 @@ from azure.core.rest import HttpRequest, HttpResponse from ._configuration import NullableClientConfiguration -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer from .operations import ( BytesOperations, CollectionsByteOperations, diff --git a/packages/typespec-python/test/azure/generated/typetest-property-nullable/typetest/property/nullable/_utils/__init__.py b/packages/typespec-python/test/azure/generated/typetest-property-nullable/typetest/property/nullable/_utils/__init__.py new file mode 100644 index 00000000000..8026245c2ab --- /dev/null +++ b/packages/typespec-python/test/azure/generated/typetest-property-nullable/typetest/property/nullable/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) Python Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/typespec-python/test/azure/generated/typetest-property-optional/typetest/property/optional/_model_base.py b/packages/typespec-python/test/azure/generated/typetest-property-nullable/typetest/property/nullable/_utils/model_base.py similarity index 100% rename from packages/typespec-python/test/azure/generated/typetest-property-optional/typetest/property/optional/_model_base.py rename to packages/typespec-python/test/azure/generated/typetest-property-nullable/typetest/property/nullable/_utils/model_base.py diff --git a/packages/typespec-python/test/azure/generated/typetest-property-optional/typetest/property/optional/_serialization.py b/packages/typespec-python/test/azure/generated/typetest-property-nullable/typetest/property/nullable/_utils/serialization.py similarity index 100% rename from packages/typespec-python/test/azure/generated/typetest-property-optional/typetest/property/optional/_serialization.py rename to packages/typespec-python/test/azure/generated/typetest-property-nullable/typetest/property/nullable/_utils/serialization.py diff --git a/packages/typespec-python/test/azure/generated/typetest-property-nullable/typetest/property/nullable/aio/_client.py b/packages/typespec-python/test/azure/generated/typetest-property-nullable/typetest/property/nullable/aio/_client.py index 781bcb04694..3ae4a7daab0 100644 --- a/packages/typespec-python/test/azure/generated/typetest-property-nullable/typetest/property/nullable/aio/_client.py +++ b/packages/typespec-python/test/azure/generated/typetest-property-nullable/typetest/property/nullable/aio/_client.py @@ -14,7 +14,7 @@ from azure.core.pipeline import policies from azure.core.rest import AsyncHttpResponse, HttpRequest -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import NullableClientConfiguration from .operations import ( BytesOperations, diff --git a/packages/typespec-python/test/azure/generated/typetest-property-nullable/typetest/property/nullable/aio/operations/_operations.py b/packages/typespec-python/test/azure/generated/typetest-property-nullable/typetest/property/nullable/aio/operations/_operations.py index 8c415a3c91d..d8c8dd25bfe 100644 --- a/packages/typespec-python/test/azure/generated/typetest-property-nullable/typetest/property/nullable/aio/operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/typetest-property-nullable/typetest/property/nullable/aio/operations/_operations.py @@ -28,8 +28,8 @@ from azure.core.utils import case_insensitive_dict from ... import models as _models -from ..._model_base import SdkJSONEncoder, _deserialize -from ..._serialization import Deserializer, Serializer +from ..._utils.model_base import SdkJSONEncoder, _deserialize +from ..._utils.serialization import Deserializer, Serializer from ...operations._operations import ( build_bytes_get_non_null_request, build_bytes_get_null_request, diff --git a/packages/typespec-python/test/azure/generated/typetest-property-nullable/typetest/property/nullable/models/_models.py b/packages/typespec-python/test/azure/generated/typetest-property-nullable/typetest/property/nullable/models/_models.py index f903a0b6593..5a49135941f 100644 --- a/packages/typespec-python/test/azure/generated/typetest-property-nullable/typetest/property/nullable/models/_models.py +++ b/packages/typespec-python/test/azure/generated/typetest-property-nullable/typetest/property/nullable/models/_models.py @@ -10,14 +10,13 @@ import datetime from typing import Any, List, Mapping, TYPE_CHECKING, overload -from .. import _model_base -from .._model_base import rest_field +from .._utils.model_base import Model as _Model, rest_field if TYPE_CHECKING: from .. import models as _models -class BytesProperty(_model_base.Model): +class BytesProperty(_Model): """Template type for testing models with nullable property. Pass in the type of the property you are looking for. @@ -55,7 +54,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class CollectionsByteProperty(_model_base.Model): +class CollectionsByteProperty(_Model): """Model with collection bytes properties. :ivar required_property: Required property. Required. @@ -92,7 +91,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class CollectionsModelProperty(_model_base.Model): +class CollectionsModelProperty(_Model): """Model with collection models properties. :ivar required_property: Required property. Required. @@ -129,7 +128,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class CollectionsStringProperty(_model_base.Model): +class CollectionsStringProperty(_Model): """Model with collection string properties. :ivar required_property: Required property. Required. @@ -166,7 +165,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class DatetimeProperty(_model_base.Model): +class DatetimeProperty(_Model): """Model with a datetime property. :ivar required_property: Required property. Required. @@ -203,7 +202,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class DurationProperty(_model_base.Model): +class DurationProperty(_Model): """Model with a duration property. :ivar required_property: Required property. Required. @@ -240,7 +239,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class InnerModel(_model_base.Model): +class InnerModel(_Model): """Inner model used in collections model property. :ivar property: Inner model property. Required. @@ -268,7 +267,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class StringProperty(_model_base.Model): +class StringProperty(_Model): """Template type for testing models with nullable property. Pass in the type of the property you are looking for. diff --git a/packages/typespec-python/test/azure/generated/typetest-property-nullable/typetest/property/nullable/operations/_operations.py b/packages/typespec-python/test/azure/generated/typetest-property-nullable/typetest/property/nullable/operations/_operations.py index b32369e2429..3d8f19a93f0 100644 --- a/packages/typespec-python/test/azure/generated/typetest-property-nullable/typetest/property/nullable/operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/typetest-property-nullable/typetest/property/nullable/operations/_operations.py @@ -29,8 +29,8 @@ from .. import models as _models from .._configuration import NullableClientConfiguration -from .._model_base import SdkJSONEncoder, _deserialize -from .._serialization import Deserializer, Serializer +from .._utils.model_base import SdkJSONEncoder, _deserialize +from .._utils.serialization import Deserializer, Serializer JSON = MutableMapping[str, Any] T = TypeVar("T") diff --git a/packages/typespec-python/test/azure/generated/typetest-property-optional/typetest/property/optional/_client.py b/packages/typespec-python/test/azure/generated/typetest-property-optional/typetest/property/optional/_client.py index 3525bf670fa..b06efb80a58 100644 --- a/packages/typespec-python/test/azure/generated/typetest-property-optional/typetest/property/optional/_client.py +++ b/packages/typespec-python/test/azure/generated/typetest-property-optional/typetest/property/optional/_client.py @@ -15,7 +15,7 @@ from azure.core.rest import HttpRequest, HttpResponse from ._configuration import OptionalClientConfiguration -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer from .operations import ( BooleanLiteralOperations, BytesOperations, diff --git a/packages/typespec-python/test/azure/generated/typetest-property-optional/typetest/property/optional/_utils/__init__.py b/packages/typespec-python/test/azure/generated/typetest-property-optional/typetest/property/optional/_utils/__init__.py new file mode 100644 index 00000000000..8026245c2ab --- /dev/null +++ b/packages/typespec-python/test/azure/generated/typetest-property-optional/typetest/property/optional/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) Python Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/typespec-python/test/azure/generated/typetest-property-valuetypes/typetest/property/valuetypes/_model_base.py b/packages/typespec-python/test/azure/generated/typetest-property-optional/typetest/property/optional/_utils/model_base.py similarity index 100% rename from packages/typespec-python/test/azure/generated/typetest-property-valuetypes/typetest/property/valuetypes/_model_base.py rename to packages/typespec-python/test/azure/generated/typetest-property-optional/typetest/property/optional/_utils/model_base.py diff --git a/packages/typespec-python/test/azure/generated/typetest-property-valuetypes/typetest/property/valuetypes/_serialization.py b/packages/typespec-python/test/azure/generated/typetest-property-optional/typetest/property/optional/_utils/serialization.py similarity index 100% rename from packages/typespec-python/test/azure/generated/typetest-property-valuetypes/typetest/property/valuetypes/_serialization.py rename to packages/typespec-python/test/azure/generated/typetest-property-optional/typetest/property/optional/_utils/serialization.py diff --git a/packages/typespec-python/test/azure/generated/typetest-property-optional/typetest/property/optional/aio/_client.py b/packages/typespec-python/test/azure/generated/typetest-property-optional/typetest/property/optional/aio/_client.py index da172771da5..504284f11f3 100644 --- a/packages/typespec-python/test/azure/generated/typetest-property-optional/typetest/property/optional/aio/_client.py +++ b/packages/typespec-python/test/azure/generated/typetest-property-optional/typetest/property/optional/aio/_client.py @@ -14,7 +14,7 @@ from azure.core.pipeline import policies from azure.core.rest import AsyncHttpResponse, HttpRequest -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import OptionalClientConfiguration from .operations import ( BooleanLiteralOperations, diff --git a/packages/typespec-python/test/azure/generated/typetest-property-optional/typetest/property/optional/aio/operations/_operations.py b/packages/typespec-python/test/azure/generated/typetest-property-optional/typetest/property/optional/aio/operations/_operations.py index f44313d2903..1da2e8bff06 100644 --- a/packages/typespec-python/test/azure/generated/typetest-property-optional/typetest/property/optional/aio/operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/typetest-property-optional/typetest/property/optional/aio/operations/_operations.py @@ -28,8 +28,8 @@ from azure.core.utils import case_insensitive_dict from ... import models as _models -from ..._model_base import SdkJSONEncoder, _deserialize -from ..._serialization import Deserializer, Serializer +from ..._utils.model_base import SdkJSONEncoder, _deserialize +from ..._utils.serialization import Deserializer, Serializer from ...operations._operations import ( build_boolean_literal_get_all_request, build_boolean_literal_get_default_request, diff --git a/packages/typespec-python/test/azure/generated/typetest-property-optional/typetest/property/optional/models/_models.py b/packages/typespec-python/test/azure/generated/typetest-property-optional/typetest/property/optional/models/_models.py index fa782ae9327..31a2c418f04 100644 --- a/packages/typespec-python/test/azure/generated/typetest-property-optional/typetest/property/optional/models/_models.py +++ b/packages/typespec-python/test/azure/generated/typetest-property-optional/typetest/property/optional/models/_models.py @@ -10,14 +10,13 @@ import datetime from typing import Any, List, Literal, Mapping, Optional, TYPE_CHECKING, overload -from .. import _model_base -from .._model_base import rest_field +from .._utils.model_base import Model as _Model, rest_field if TYPE_CHECKING: from .. import models as _models -class BooleanLiteralProperty(_model_base.Model): +class BooleanLiteralProperty(_Model): """Model with boolean literal property. :ivar property: Property. Default value is True. @@ -45,7 +44,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class BytesProperty(_model_base.Model): +class BytesProperty(_Model): """Template type for testing models with optional property. Pass in the type of the property you are looking for. @@ -74,7 +73,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class CollectionsByteProperty(_model_base.Model): +class CollectionsByteProperty(_Model): """Model with collection bytes properties. :ivar property: Property. @@ -104,7 +103,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class CollectionsModelProperty(_model_base.Model): +class CollectionsModelProperty(_Model): """Model with collection models properties. :ivar property: Property. @@ -134,7 +133,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class DatetimeProperty(_model_base.Model): +class DatetimeProperty(_Model): """Model with a datetime property. :ivar property: Property. @@ -164,7 +163,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class DurationProperty(_model_base.Model): +class DurationProperty(_Model): """Model with a duration property. :ivar property: Property. @@ -192,7 +191,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class FloatLiteralProperty(_model_base.Model): +class FloatLiteralProperty(_Model): """Model with float literal property. :ivar property: Property. Default value is 1.25. @@ -220,7 +219,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class IntLiteralProperty(_model_base.Model): +class IntLiteralProperty(_Model): """Model with int literal property. :ivar property: Property. Default value is 1. @@ -248,7 +247,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class PlainDateProperty(_model_base.Model): +class PlainDateProperty(_Model): """Model with a plainDate property. :ivar property: Property. @@ -276,7 +275,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class PlainTimeProperty(_model_base.Model): +class PlainTimeProperty(_Model): """Model with a plainTime property. :ivar property: Property. @@ -304,7 +303,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class RequiredAndOptionalProperty(_model_base.Model): +class RequiredAndOptionalProperty(_Model): """Model with required and optional properties. :ivar optional_property: optional string property. @@ -341,7 +340,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class StringLiteralProperty(_model_base.Model): +class StringLiteralProperty(_Model): """Model with string literal property. :ivar property: Property. Default value is "hello". @@ -369,7 +368,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class StringProperty(_model_base.Model): +class StringProperty(_Model): """Template type for testing models with optional property. Pass in the type of the property you are looking for. @@ -398,7 +397,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class UnionFloatLiteralProperty(_model_base.Model): +class UnionFloatLiteralProperty(_Model): """Model with union of float literal property. :ivar property: Property. Is one of the following types: float @@ -426,7 +425,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class UnionIntLiteralProperty(_model_base.Model): +class UnionIntLiteralProperty(_Model): """Model with union of int literal property. :ivar property: Property. Is either a Literal[1] type or a Literal[2] type. @@ -454,7 +453,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class UnionStringLiteralProperty(_model_base.Model): +class UnionStringLiteralProperty(_Model): """Model with union of string literal property. :ivar property: Property. Is either a Literal["hello"] type or a Literal["world"] type. diff --git a/packages/typespec-python/test/azure/generated/typetest-property-optional/typetest/property/optional/operations/_operations.py b/packages/typespec-python/test/azure/generated/typetest-property-optional/typetest/property/optional/operations/_operations.py index 58b16b25c27..16b569dab1d 100644 --- a/packages/typespec-python/test/azure/generated/typetest-property-optional/typetest/property/optional/operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/typetest-property-optional/typetest/property/optional/operations/_operations.py @@ -29,8 +29,8 @@ from .. import models as _models from .._configuration import OptionalClientConfiguration -from .._model_base import SdkJSONEncoder, _deserialize -from .._serialization import Deserializer, Serializer +from .._utils.model_base import SdkJSONEncoder, _deserialize +from .._utils.serialization import Deserializer, Serializer JSON = MutableMapping[str, Any] T = TypeVar("T") diff --git a/packages/typespec-python/test/azure/generated/typetest-property-valuetypes/typetest/property/valuetypes/_client.py b/packages/typespec-python/test/azure/generated/typetest-property-valuetypes/typetest/property/valuetypes/_client.py index e88a79a0c7d..e284c7ec2eb 100644 --- a/packages/typespec-python/test/azure/generated/typetest-property-valuetypes/typetest/property/valuetypes/_client.py +++ b/packages/typespec-python/test/azure/generated/typetest-property-valuetypes/typetest/property/valuetypes/_client.py @@ -15,7 +15,7 @@ from azure.core.rest import HttpRequest, HttpResponse from ._configuration import ValueTypesClientConfiguration -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer from .operations import ( BooleanLiteralOperations, BooleanOperations, diff --git a/packages/typespec-python/test/azure/generated/typetest-property-valuetypes/typetest/property/valuetypes/_utils/__init__.py b/packages/typespec-python/test/azure/generated/typetest-property-valuetypes/typetest/property/valuetypes/_utils/__init__.py new file mode 100644 index 00000000000..8026245c2ab --- /dev/null +++ b/packages/typespec-python/test/azure/generated/typetest-property-valuetypes/typetest/property/valuetypes/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) Python Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/typespec-python/test/azure/generated/typetest-scalar/typetest/scalar/_model_base.py b/packages/typespec-python/test/azure/generated/typetest-property-valuetypes/typetest/property/valuetypes/_utils/model_base.py similarity index 100% rename from packages/typespec-python/test/azure/generated/typetest-scalar/typetest/scalar/_model_base.py rename to packages/typespec-python/test/azure/generated/typetest-property-valuetypes/typetest/property/valuetypes/_utils/model_base.py diff --git a/packages/typespec-python/test/azure/generated/typetest-scalar/typetest/scalar/_serialization.py b/packages/typespec-python/test/azure/generated/typetest-property-valuetypes/typetest/property/valuetypes/_utils/serialization.py similarity index 100% rename from packages/typespec-python/test/azure/generated/typetest-scalar/typetest/scalar/_serialization.py rename to packages/typespec-python/test/azure/generated/typetest-property-valuetypes/typetest/property/valuetypes/_utils/serialization.py diff --git a/packages/typespec-python/test/azure/generated/typetest-property-valuetypes/typetest/property/valuetypes/aio/_client.py b/packages/typespec-python/test/azure/generated/typetest-property-valuetypes/typetest/property/valuetypes/aio/_client.py index 4e5e15f545e..1b455c9c8a8 100644 --- a/packages/typespec-python/test/azure/generated/typetest-property-valuetypes/typetest/property/valuetypes/aio/_client.py +++ b/packages/typespec-python/test/azure/generated/typetest-property-valuetypes/typetest/property/valuetypes/aio/_client.py @@ -14,7 +14,7 @@ from azure.core.pipeline import policies from azure.core.rest import AsyncHttpResponse, HttpRequest -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import ValueTypesClientConfiguration from .operations import ( BooleanLiteralOperations, diff --git a/packages/typespec-python/test/azure/generated/typetest-property-valuetypes/typetest/property/valuetypes/aio/operations/_operations.py b/packages/typespec-python/test/azure/generated/typetest-property-valuetypes/typetest/property/valuetypes/aio/operations/_operations.py index 7ed3f51190e..947cb0972d1 100644 --- a/packages/typespec-python/test/azure/generated/typetest-property-valuetypes/typetest/property/valuetypes/aio/operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/typetest-property-valuetypes/typetest/property/valuetypes/aio/operations/_operations.py @@ -28,8 +28,8 @@ from azure.core.utils import case_insensitive_dict from ... import models as _models -from ..._model_base import SdkJSONEncoder, _deserialize -from ..._serialization import Deserializer, Serializer +from ..._utils.model_base import SdkJSONEncoder, _deserialize +from ..._utils.serialization import Deserializer, Serializer from ...operations._operations import ( build_boolean_get_request, build_boolean_literal_get_request, diff --git a/packages/typespec-python/test/azure/generated/typetest-property-valuetypes/typetest/property/valuetypes/models/_models.py b/packages/typespec-python/test/azure/generated/typetest-property-valuetypes/typetest/property/valuetypes/models/_models.py index 77a4ca14594..e797f231c2b 100644 --- a/packages/typespec-python/test/azure/generated/typetest-property-valuetypes/typetest/property/valuetypes/models/_models.py +++ b/packages/typespec-python/test/azure/generated/typetest-property-valuetypes/typetest/property/valuetypes/models/_models.py @@ -11,15 +11,14 @@ import decimal from typing import Any, Dict, List, Literal, Mapping, TYPE_CHECKING, Union, overload -from .. import _model_base -from .._model_base import rest_field +from .._utils.model_base import Model as _Model, rest_field from ._enums import ExtendedEnum if TYPE_CHECKING: from .. import models as _models -class BooleanLiteralProperty(_model_base.Model): +class BooleanLiteralProperty(_Model): """Model with a boolean literal property. :ivar property: Property. Required. Default value is True. @@ -34,7 +33,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: self.property: Literal[True] = True -class BooleanProperty(_model_base.Model): +class BooleanProperty(_Model): """Model with a boolean property. :ivar property: Property. Required. @@ -62,7 +61,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class BytesProperty(_model_base.Model): +class BytesProperty(_Model): """Model with a bytes property. :ivar property: Property. Required. @@ -90,7 +89,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class CollectionsIntProperty(_model_base.Model): +class CollectionsIntProperty(_Model): """Model with collection int properties. :ivar property: Property. Required. @@ -118,7 +117,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class CollectionsModelProperty(_model_base.Model): +class CollectionsModelProperty(_Model): """Model with collection model properties. :ivar property: Property. Required. @@ -146,7 +145,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class CollectionsStringProperty(_model_base.Model): +class CollectionsStringProperty(_Model): """Model with collection string properties. :ivar property: Property. Required. @@ -174,7 +173,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class DatetimeProperty(_model_base.Model): +class DatetimeProperty(_Model): """Model with a datetime property. :ivar property: Property. Required. @@ -204,7 +203,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class Decimal128Property(_model_base.Model): +class Decimal128Property(_Model): """Model with a decimal128 property. :ivar property: Property. Required. @@ -232,7 +231,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class DecimalProperty(_model_base.Model): +class DecimalProperty(_Model): """Model with a decimal property. :ivar property: Property. Required. @@ -260,7 +259,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class DictionaryStringProperty(_model_base.Model): +class DictionaryStringProperty(_Model): """Model with dictionary string properties. :ivar property: Property. Required. @@ -288,7 +287,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class DurationProperty(_model_base.Model): +class DurationProperty(_Model): """Model with a duration property. :ivar property: Property. Required. @@ -316,7 +315,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class EnumProperty(_model_base.Model): +class EnumProperty(_Model): """Model with enum properties. :ivar property: Property. Required. Known values are: "ValueOne" and "ValueTwo". @@ -346,7 +345,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class ExtensibleEnumProperty(_model_base.Model): +class ExtensibleEnumProperty(_Model): """Model with extensible enum properties. :ivar property: Property. Required. Known values are: "ValueOne" and "ValueTwo". @@ -374,7 +373,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class FloatLiteralProperty(_model_base.Model): +class FloatLiteralProperty(_Model): """Model with a float literal property. :ivar property: Property. Required. Default value is 43.125. @@ -389,7 +388,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: self.property: float = 43.125 -class FloatProperty(_model_base.Model): +class FloatProperty(_Model): """Model with a float property. :ivar property: Property. Required. @@ -417,7 +416,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class InnerModel(_model_base.Model): +class InnerModel(_Model): """Inner model. Will be a property type for ModelWithModelProperties. :ivar property: Required string property. Required. @@ -445,7 +444,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class IntLiteralProperty(_model_base.Model): +class IntLiteralProperty(_Model): """Model with a int literal property. :ivar property: Property. Required. Default value is 42. @@ -460,7 +459,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: self.property: Literal[42] = 42 -class IntProperty(_model_base.Model): +class IntProperty(_Model): """Model with a int property. :ivar property: Property. Required. @@ -488,7 +487,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class ModelProperty(_model_base.Model): +class ModelProperty(_Model): """Model with model properties. :ivar property: Property. Required. @@ -516,11 +515,11 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class NeverProperty(_model_base.Model): +class NeverProperty(_Model): """Model with a property never. (This property should not be included).""" -class StringLiteralProperty(_model_base.Model): +class StringLiteralProperty(_Model): """Model with a string literal property. :ivar property: Property. Required. Default value is "hello". @@ -535,7 +534,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: self.property: Literal["hello"] = "hello" -class StringProperty(_model_base.Model): +class StringProperty(_Model): """Model with a string property. :ivar property: Property. Required. @@ -563,7 +562,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class UnionEnumValueProperty(_model_base.Model): +class UnionEnumValueProperty(_Model): """Template type for testing models with specific properties. Pass in the type of the property you are looking for. @@ -592,7 +591,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class UnionFloatLiteralProperty(_model_base.Model): +class UnionFloatLiteralProperty(_Model): """Model with a union of float literal as property. :ivar property: Property. Required. Is one of the following types: float @@ -620,7 +619,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class UnionIntLiteralProperty(_model_base.Model): +class UnionIntLiteralProperty(_Model): """Model with a union of int literal as property. :ivar property: Property. Required. Is either a Literal[42] type or a Literal[43] type. @@ -648,7 +647,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class UnionStringLiteralProperty(_model_base.Model): +class UnionStringLiteralProperty(_Model): """Model with a union of string literal as property. :ivar property: Property. Required. Is either a Literal["hello"] type or a Literal["world"] @@ -677,7 +676,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class UnknownArrayProperty(_model_base.Model): +class UnknownArrayProperty(_Model): """Model with a property unknown, and the data is an array. :ivar property: Property. Required. @@ -705,7 +704,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class UnknownDictProperty(_model_base.Model): +class UnknownDictProperty(_Model): """Model with a property unknown, and the data is a dictionnary. :ivar property: Property. Required. @@ -733,7 +732,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class UnknownIntProperty(_model_base.Model): +class UnknownIntProperty(_Model): """Model with a property unknown, and the data is a int32. :ivar property: Property. Required. @@ -761,7 +760,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class UnknownStringProperty(_model_base.Model): +class UnknownStringProperty(_Model): """Model with a property unknown, and the data is a string. :ivar property: Property. Required. diff --git a/packages/typespec-python/test/azure/generated/typetest-property-valuetypes/typetest/property/valuetypes/operations/_operations.py b/packages/typespec-python/test/azure/generated/typetest-property-valuetypes/typetest/property/valuetypes/operations/_operations.py index efc7ebbe06d..b7a05fdb8b1 100644 --- a/packages/typespec-python/test/azure/generated/typetest-property-valuetypes/typetest/property/valuetypes/operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/typetest-property-valuetypes/typetest/property/valuetypes/operations/_operations.py @@ -29,8 +29,8 @@ from .. import models as _models from .._configuration import ValueTypesClientConfiguration -from .._model_base import SdkJSONEncoder, _deserialize -from .._serialization import Deserializer, Serializer +from .._utils.model_base import SdkJSONEncoder, _deserialize +from .._utils.serialization import Deserializer, Serializer JSON = MutableMapping[str, Any] T = TypeVar("T") diff --git a/packages/typespec-python/test/azure/generated/typetest-scalar/typetest/scalar/_client.py b/packages/typespec-python/test/azure/generated/typetest-scalar/typetest/scalar/_client.py index a3d64e0402a..1d3f74d18d0 100644 --- a/packages/typespec-python/test/azure/generated/typetest-scalar/typetest/scalar/_client.py +++ b/packages/typespec-python/test/azure/generated/typetest-scalar/typetest/scalar/_client.py @@ -15,7 +15,7 @@ from azure.core.rest import HttpRequest, HttpResponse from ._configuration import ScalarClientConfiguration -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer from .operations import ( BooleanOperations, Decimal128TypeOperations, diff --git a/packages/typespec-python/test/azure/generated/typetest-scalar/typetest/scalar/_utils/__init__.py b/packages/typespec-python/test/azure/generated/typetest-scalar/typetest/scalar/_utils/__init__.py new file mode 100644 index 00000000000..8026245c2ab --- /dev/null +++ b/packages/typespec-python/test/azure/generated/typetest-scalar/typetest/scalar/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) Python Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/typespec-python/test/azure/generated/typetest-union/typetest/union/_model_base.py b/packages/typespec-python/test/azure/generated/typetest-scalar/typetest/scalar/_utils/model_base.py similarity index 100% rename from packages/typespec-python/test/azure/generated/typetest-union/typetest/union/_model_base.py rename to packages/typespec-python/test/azure/generated/typetest-scalar/typetest/scalar/_utils/model_base.py diff --git a/packages/typespec-python/test/azure/generated/typetest-union/typetest/union/_serialization.py b/packages/typespec-python/test/azure/generated/typetest-scalar/typetest/scalar/_utils/serialization.py similarity index 100% rename from packages/typespec-python/test/azure/generated/typetest-union/typetest/union/_serialization.py rename to packages/typespec-python/test/azure/generated/typetest-scalar/typetest/scalar/_utils/serialization.py diff --git a/packages/typespec-python/test/azure/generated/typetest-scalar/typetest/scalar/aio/_client.py b/packages/typespec-python/test/azure/generated/typetest-scalar/typetest/scalar/aio/_client.py index 2ebe3284b5d..488eac03d3b 100644 --- a/packages/typespec-python/test/azure/generated/typetest-scalar/typetest/scalar/aio/_client.py +++ b/packages/typespec-python/test/azure/generated/typetest-scalar/typetest/scalar/aio/_client.py @@ -14,7 +14,7 @@ from azure.core.pipeline import policies from azure.core.rest import AsyncHttpResponse, HttpRequest -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import ScalarClientConfiguration from .operations import ( BooleanOperations, diff --git a/packages/typespec-python/test/azure/generated/typetest-scalar/typetest/scalar/aio/operations/_operations.py b/packages/typespec-python/test/azure/generated/typetest-scalar/typetest/scalar/aio/operations/_operations.py index 8db39ca3a26..ad52cfbe2a3 100644 --- a/packages/typespec-python/test/azure/generated/typetest-scalar/typetest/scalar/aio/operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/typetest-scalar/typetest/scalar/aio/operations/_operations.py @@ -27,8 +27,8 @@ from azure.core.tracing.decorator_async import distributed_trace_async from azure.core.utils import case_insensitive_dict -from ..._model_base import SdkJSONEncoder, _deserialize -from ..._serialization import Deserializer, Serializer +from ..._utils.model_base import SdkJSONEncoder, _deserialize +from ..._utils.serialization import Deserializer, Serializer from ...operations._operations import ( build_boolean_get_request, build_boolean_put_request, diff --git a/packages/typespec-python/test/azure/generated/typetest-scalar/typetest/scalar/operations/_operations.py b/packages/typespec-python/test/azure/generated/typetest-scalar/typetest/scalar/operations/_operations.py index 516871c8aba..00bb3c8d340 100644 --- a/packages/typespec-python/test/azure/generated/typetest-scalar/typetest/scalar/operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/typetest-scalar/typetest/scalar/operations/_operations.py @@ -28,8 +28,8 @@ from azure.core.utils import case_insensitive_dict from .._configuration import ScalarClientConfiguration -from .._model_base import SdkJSONEncoder, _deserialize -from .._serialization import Deserializer, Serializer +from .._utils.model_base import SdkJSONEncoder, _deserialize +from .._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/typespec-python/test/azure/generated/typetest-union/typetest/union/_client.py b/packages/typespec-python/test/azure/generated/typetest-union/typetest/union/_client.py index a22ca034d8b..8863b50c815 100644 --- a/packages/typespec-python/test/azure/generated/typetest-union/typetest/union/_client.py +++ b/packages/typespec-python/test/azure/generated/typetest-union/typetest/union/_client.py @@ -15,7 +15,7 @@ from azure.core.rest import HttpRequest, HttpResponse from ._configuration import UnionClientConfiguration -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer from .operations import ( EnumsOnlyOperations, FloatsOnlyOperations, diff --git a/packages/typespec-python/test/azure/generated/typetest-union/typetest/union/_utils/__init__.py b/packages/typespec-python/test/azure/generated/typetest-union/typetest/union/_utils/__init__.py new file mode 100644 index 00000000000..8026245c2ab --- /dev/null +++ b/packages/typespec-python/test/azure/generated/typetest-union/typetest/union/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) Python Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/typespec-python/test/azure/generated/versioning-added/versioning/added/_model_base.py b/packages/typespec-python/test/azure/generated/typetest-union/typetest/union/_utils/model_base.py similarity index 100% rename from packages/typespec-python/test/azure/generated/versioning-added/versioning/added/_model_base.py rename to packages/typespec-python/test/azure/generated/typetest-union/typetest/union/_utils/model_base.py diff --git a/packages/typespec-python/test/azure/generated/versioning-added/versioning/added/_serialization.py b/packages/typespec-python/test/azure/generated/typetest-union/typetest/union/_utils/serialization.py similarity index 100% rename from packages/typespec-python/test/azure/generated/versioning-added/versioning/added/_serialization.py rename to packages/typespec-python/test/azure/generated/typetest-union/typetest/union/_utils/serialization.py diff --git a/packages/typespec-python/test/azure/generated/typetest-union/typetest/union/aio/_client.py b/packages/typespec-python/test/azure/generated/typetest-union/typetest/union/aio/_client.py index 157d7030d4c..1b43016396f 100644 --- a/packages/typespec-python/test/azure/generated/typetest-union/typetest/union/aio/_client.py +++ b/packages/typespec-python/test/azure/generated/typetest-union/typetest/union/aio/_client.py @@ -14,7 +14,7 @@ from azure.core.pipeline import policies from azure.core.rest import AsyncHttpResponse, HttpRequest -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import UnionClientConfiguration from .operations import ( EnumsOnlyOperations, diff --git a/packages/typespec-python/test/azure/generated/typetest-union/typetest/union/aio/operations/_operations.py b/packages/typespec-python/test/azure/generated/typetest-union/typetest/union/aio/operations/_operations.py index 4427eb5239d..6313b30f4bc 100644 --- a/packages/typespec-python/test/azure/generated/typetest-union/typetest/union/aio/operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/typetest-union/typetest/union/aio/operations/_operations.py @@ -28,8 +28,8 @@ from azure.core.utils import case_insensitive_dict from ... import models as _models -from ..._model_base import SdkJSONEncoder, _deserialize -from ..._serialization import Deserializer, Serializer +from ..._utils.model_base import SdkJSONEncoder, _deserialize +from ..._utils.serialization import Deserializer, Serializer from ...operations._operations import ( build_enums_only_get_request, build_enums_only_send_request, diff --git a/packages/typespec-python/test/azure/generated/typetest-union/typetest/union/models/_models.py b/packages/typespec-python/test/azure/generated/typetest-union/typetest/union/models/_models.py index a635d6561b2..a9bdc5878bd 100644 --- a/packages/typespec-python/test/azure/generated/typetest-union/typetest/union/models/_models.py +++ b/packages/typespec-python/test/azure/generated/typetest-union/typetest/union/models/_models.py @@ -9,14 +9,13 @@ from typing import Any, List, Literal, Mapping, TYPE_CHECKING, Union, overload -from .. import _model_base -from .._model_base import rest_field +from .._utils.model_base import Model as _Model, rest_field if TYPE_CHECKING: from .. import models as _models -class Cat(_model_base.Model): +class Cat(_Model): """Cat. :ivar name: Required. @@ -44,7 +43,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class Dog(_model_base.Model): +class Dog(_Model): """Dog. :ivar bark: Required. @@ -72,7 +71,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class EnumsOnlyCases(_model_base.Model): +class EnumsOnlyCases(_Model): """EnumsOnlyCases. :ivar lr: This should be receive/send the left variant. Required. Is one of the following @@ -109,7 +108,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class GetResponse(_model_base.Model): +class GetResponse(_Model): """GetResponse. :ivar prop: Required. Is one of the following types: Literal["a"], Literal["b"], Literal["c"] @@ -137,7 +136,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class GetResponse1(_model_base.Model): +class GetResponse1(_Model): """GetResponse1. :ivar prop: Required. Is one of the following types: Literal["b"], Literal["c"], str @@ -167,7 +166,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class GetResponse2(_model_base.Model): +class GetResponse2(_Model): """GetResponse2. :ivar prop: Required. Known values are: "b" and "c". @@ -197,7 +196,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class GetResponse3(_model_base.Model): +class GetResponse3(_Model): """GetResponse3. :ivar prop: Required. Is one of the following types: Literal[1], Literal[2], Literal[3] @@ -225,7 +224,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class GetResponse4(_model_base.Model): +class GetResponse4(_Model): """GetResponse4. :ivar prop: Required. Is one of the following types: float @@ -253,7 +252,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class GetResponse5(_model_base.Model): +class GetResponse5(_Model): """GetResponse5. :ivar prop: Required. Is either a Cat type or a Dog type. @@ -281,7 +280,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class GetResponse6(_model_base.Model): +class GetResponse6(_Model): """GetResponse6. :ivar prop: Required. @@ -309,7 +308,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class GetResponse7(_model_base.Model): +class GetResponse7(_Model): """GetResponse7. :ivar prop: Required. @@ -337,7 +336,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class GetResponse8(_model_base.Model): +class GetResponse8(_Model): """GetResponse8. :ivar prop: Required. @@ -365,7 +364,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class GetResponse9(_model_base.Model): +class GetResponse9(_Model): """GetResponse9. :ivar prop: Required. @@ -393,7 +392,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class MixedLiteralsCases(_model_base.Model): +class MixedLiteralsCases(_Model): """MixedLiteralsCases. :ivar string_literal: This should be receive/send the "a" variant. Required. Is one of the @@ -452,7 +451,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class MixedTypesCases(_model_base.Model): +class MixedTypesCases(_Model): """MixedTypesCases. :ivar model: This should be receive/send the Cat variant. Required. Is one of the following @@ -518,7 +517,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class StringAndArrayCases(_model_base.Model): +class StringAndArrayCases(_Model): """StringAndArrayCases. :ivar string: This should be receive/send the string variant. Required. Is either a str type or diff --git a/packages/typespec-python/test/azure/generated/typetest-union/typetest/union/operations/_operations.py b/packages/typespec-python/test/azure/generated/typetest-union/typetest/union/operations/_operations.py index d71c0ff8461..bea2bfff05a 100644 --- a/packages/typespec-python/test/azure/generated/typetest-union/typetest/union/operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/typetest-union/typetest/union/operations/_operations.py @@ -29,8 +29,8 @@ from .. import models as _models from .._configuration import UnionClientConfiguration -from .._model_base import SdkJSONEncoder, _deserialize -from .._serialization import Deserializer, Serializer +from .._utils.model_base import SdkJSONEncoder, _deserialize +from .._utils.serialization import Deserializer, Serializer JSON = MutableMapping[str, Any] _Unset: Any = object() diff --git a/packages/typespec-python/test/azure/generated/versioning-added/versioning/added/_client.py b/packages/typespec-python/test/azure/generated/versioning-added/versioning/added/_client.py index 23783477857..40617eb8748 100644 --- a/packages/typespec-python/test/azure/generated/versioning-added/versioning/added/_client.py +++ b/packages/typespec-python/test/azure/generated/versioning-added/versioning/added/_client.py @@ -16,7 +16,7 @@ from . import models as _models from ._configuration import AddedClientConfiguration -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer from .operations import AddedClientOperationsMixin, InterfaceV2Operations diff --git a/packages/typespec-python/test/azure/generated/versioning-added/versioning/added/_utils/__init__.py b/packages/typespec-python/test/azure/generated/versioning-added/versioning/added/_utils/__init__.py new file mode 100644 index 00000000000..8026245c2ab --- /dev/null +++ b/packages/typespec-python/test/azure/generated/versioning-added/versioning/added/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) Python Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/typespec-python/test/azure/generated/versioning-madeoptional/versioning/madeoptional/_model_base.py b/packages/typespec-python/test/azure/generated/versioning-added/versioning/added/_utils/model_base.py similarity index 100% rename from packages/typespec-python/test/azure/generated/versioning-madeoptional/versioning/madeoptional/_model_base.py rename to packages/typespec-python/test/azure/generated/versioning-added/versioning/added/_utils/model_base.py diff --git a/packages/typespec-python/test/azure/generated/versioning-madeoptional/versioning/madeoptional/_serialization.py b/packages/typespec-python/test/azure/generated/versioning-added/versioning/added/_utils/serialization.py similarity index 100% rename from packages/typespec-python/test/azure/generated/versioning-madeoptional/versioning/madeoptional/_serialization.py rename to packages/typespec-python/test/azure/generated/versioning-added/versioning/added/_utils/serialization.py diff --git a/packages/typespec-python/test/azure/generated/versioning-added/versioning/added/_utils/utils.py b/packages/typespec-python/test/azure/generated/versioning-added/versioning/added/_utils/utils.py new file mode 100644 index 00000000000..35c9c836f85 --- /dev/null +++ b/packages/typespec-python/test/azure/generated/versioning-added/versioning/added/_utils/utils.py @@ -0,0 +1,25 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) Python Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from abc import ABC +from typing import Generic, TYPE_CHECKING, TypeVar + +if TYPE_CHECKING: + from .serialization import Deserializer, Serializer + + +TClient = TypeVar("TClient") +TConfig = TypeVar("TConfig") + + +class ClientMixinABC(ABC, Generic[TClient, TConfig]): + """DO NOT use this class. It is for internal typing use only.""" + + _client: TClient + _config: TConfig + _serialize: "Serializer" + _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/azure/generated/versioning-added/versioning/added/_vendor.py b/packages/typespec-python/test/azure/generated/versioning-added/versioning/added/_vendor.py deleted file mode 100644 index 9be6e919385..00000000000 --- a/packages/typespec-python/test/azure/generated/versioning-added/versioning/added/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) Python Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import AddedClientConfiguration - -if TYPE_CHECKING: - from azure.core import PipelineClient - - from ._serialization import Deserializer, Serializer - - -class AddedClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "PipelineClient" - _config: AddedClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/azure/generated/versioning-added/versioning/added/aio/_client.py b/packages/typespec-python/test/azure/generated/versioning-added/versioning/added/aio/_client.py index d817d8c213e..a4fd2b5a7a4 100644 --- a/packages/typespec-python/test/azure/generated/versioning-added/versioning/added/aio/_client.py +++ b/packages/typespec-python/test/azure/generated/versioning-added/versioning/added/aio/_client.py @@ -15,7 +15,7 @@ from azure.core.rest import AsyncHttpResponse, HttpRequest from .. import models as _models -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import AddedClientConfiguration from .operations import AddedClientOperationsMixin, InterfaceV2Operations diff --git a/packages/typespec-python/test/azure/generated/versioning-added/versioning/added/aio/_vendor.py b/packages/typespec-python/test/azure/generated/versioning-added/versioning/added/aio/_vendor.py deleted file mode 100644 index 27a5ba89938..00000000000 --- a/packages/typespec-python/test/azure/generated/versioning-added/versioning/added/aio/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) Python Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import AddedClientConfiguration - -if TYPE_CHECKING: - from azure.core import AsyncPipelineClient - - from .._serialization import Deserializer, Serializer - - -class AddedClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "AsyncPipelineClient" - _config: AddedClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/azure/generated/versioning-added/versioning/added/aio/operations/_operations.py b/packages/typespec-python/test/azure/generated/versioning-added/versioning/added/aio/operations/_operations.py index 1fb8f94e630..20606137fa9 100644 --- a/packages/typespec-python/test/azure/generated/versioning-added/versioning/added/aio/operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/versioning-added/versioning/added/aio/operations/_operations.py @@ -28,8 +28,9 @@ from azure.core.utils import case_insensitive_dict from ... import models as _models -from ..._model_base import SdkJSONEncoder, _deserialize -from ..._serialization import Deserializer, Serializer +from ..._utils.model_base import SdkJSONEncoder, _deserialize +from ..._utils.serialization import Deserializer, Serializer +from ..._utils.utils import ClientMixinABC from ..._validation import api_version_validation from ...operations._operations import ( build_added_v1_request, @@ -37,7 +38,6 @@ build_interface_v2_v2_in_interface_request, ) from .._configuration import AddedClientConfiguration -from .._vendor import AddedClientMixinABC JSON = MutableMapping[str, Any] T = TypeVar("T") @@ -183,7 +183,7 @@ async def v2_in_interface(self, body: Union[_models.ModelV2, JSON, IO[bytes]], * return deserialized # type: ignore -class AddedClientOperationsMixin(AddedClientMixinABC): +class AddedClientOperationsMixin(ClientMixinABC[AsyncPipelineClient, AddedClientConfiguration]): @overload async def v1( diff --git a/packages/typespec-python/test/azure/generated/versioning-added/versioning/added/models/_models.py b/packages/typespec-python/test/azure/generated/versioning-added/versioning/added/models/_models.py index ed9f8d9d37f..00c1ffc3add 100644 --- a/packages/typespec-python/test/azure/generated/versioning-added/versioning/added/models/_models.py +++ b/packages/typespec-python/test/azure/generated/versioning-added/versioning/added/models/_models.py @@ -9,14 +9,13 @@ from typing import Any, Mapping, TYPE_CHECKING, Union, overload -from .. import _model_base -from .._model_base import rest_field +from .._utils.model_base import Model as _Model, rest_field if TYPE_CHECKING: from .. import _types, models as _models -class ModelV1(_model_base.Model): +class ModelV1(_Model): """ModelV1. :ivar prop: Required. @@ -58,7 +57,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class ModelV2(_model_base.Model): +class ModelV2(_Model): """ModelV2. :ivar prop: Required. diff --git a/packages/typespec-python/test/azure/generated/versioning-added/versioning/added/operations/_operations.py b/packages/typespec-python/test/azure/generated/versioning-added/versioning/added/operations/_operations.py index 390a38689de..d1d37fe3bfe 100644 --- a/packages/typespec-python/test/azure/generated/versioning-added/versioning/added/operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/versioning-added/versioning/added/operations/_operations.py @@ -28,10 +28,10 @@ from .. import models as _models from .._configuration import AddedClientConfiguration -from .._model_base import SdkJSONEncoder, _deserialize -from .._serialization import Deserializer, Serializer +from .._utils.model_base import SdkJSONEncoder, _deserialize +from .._utils.serialization import Deserializer, Serializer +from .._utils.utils import ClientMixinABC from .._validation import api_version_validation -from .._vendor import AddedClientMixinABC JSON = MutableMapping[str, Any] T = TypeVar("T") @@ -230,7 +230,7 @@ def v2_in_interface(self, body: Union[_models.ModelV2, JSON, IO[bytes]], **kwarg return deserialized # type: ignore -class AddedClientOperationsMixin(AddedClientMixinABC): +class AddedClientOperationsMixin(ClientMixinABC[PipelineClient, AddedClientConfiguration]): @overload def v1( diff --git a/packages/typespec-python/test/azure/generated/versioning-madeoptional/versioning/madeoptional/_client.py b/packages/typespec-python/test/azure/generated/versioning-madeoptional/versioning/madeoptional/_client.py index 00297b5770d..78236b3e369 100644 --- a/packages/typespec-python/test/azure/generated/versioning-madeoptional/versioning/madeoptional/_client.py +++ b/packages/typespec-python/test/azure/generated/versioning-madeoptional/versioning/madeoptional/_client.py @@ -17,7 +17,7 @@ from . import models as _models from ._configuration import MadeOptionalClientConfiguration from ._operations import MadeOptionalClientOperationsMixin -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer class MadeOptionalClient(MadeOptionalClientOperationsMixin): # pylint: disable=client-accepts-api-version-keyword diff --git a/packages/typespec-python/test/azure/generated/versioning-madeoptional/versioning/madeoptional/_operations/_operations.py b/packages/typespec-python/test/azure/generated/versioning-madeoptional/versioning/madeoptional/_operations/_operations.py index a19db0bde2a..d9a35d76ac0 100644 --- a/packages/typespec-python/test/azure/generated/versioning-madeoptional/versioning/madeoptional/_operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/versioning-madeoptional/versioning/madeoptional/_operations/_operations.py @@ -10,6 +10,7 @@ import json from typing import Any, Callable, Dict, IO, Optional, TypeVar, Union, overload +from azure.core import PipelineClient from azure.core.exceptions import ( ClientAuthenticationError, HttpResponseError, @@ -26,9 +27,10 @@ from azure.core.utils import case_insensitive_dict from .. import models as _models -from .._model_base import SdkJSONEncoder, _deserialize -from .._serialization import Serializer -from .._vendor import MadeOptionalClientMixinABC +from .._configuration import MadeOptionalClientConfiguration +from .._utils.model_base import SdkJSONEncoder, _deserialize +from .._utils.serialization import Serializer +from .._utils.utils import ClientMixinABC JSON = MutableMapping[str, Any] T = TypeVar("T") @@ -60,7 +62,7 @@ def build_made_optional_test_request(*, param: Optional[str] = None, **kwargs: A return HttpRequest(method="POST", url=_url, params=_params, headers=_headers, **kwargs) -class MadeOptionalClientOperationsMixin(MadeOptionalClientMixinABC): +class MadeOptionalClientOperationsMixin(ClientMixinABC[PipelineClient, MadeOptionalClientConfiguration]): @overload def test( diff --git a/packages/typespec-python/test/azure/generated/versioning-madeoptional/versioning/madeoptional/_utils/__init__.py b/packages/typespec-python/test/azure/generated/versioning-madeoptional/versioning/madeoptional/_utils/__init__.py new file mode 100644 index 00000000000..8026245c2ab --- /dev/null +++ b/packages/typespec-python/test/azure/generated/versioning-madeoptional/versioning/madeoptional/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) Python Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/typespec-python/test/azure/generated/versioning-removed/versioning/removed/_model_base.py b/packages/typespec-python/test/azure/generated/versioning-madeoptional/versioning/madeoptional/_utils/model_base.py similarity index 100% rename from packages/typespec-python/test/azure/generated/versioning-removed/versioning/removed/_model_base.py rename to packages/typespec-python/test/azure/generated/versioning-madeoptional/versioning/madeoptional/_utils/model_base.py diff --git a/packages/typespec-python/test/azure/generated/versioning-removed/versioning/removed/_serialization.py b/packages/typespec-python/test/azure/generated/versioning-madeoptional/versioning/madeoptional/_utils/serialization.py similarity index 100% rename from packages/typespec-python/test/azure/generated/versioning-removed/versioning/removed/_serialization.py rename to packages/typespec-python/test/azure/generated/versioning-madeoptional/versioning/madeoptional/_utils/serialization.py diff --git a/packages/typespec-python/test/azure/generated/versioning-madeoptional/versioning/madeoptional/_utils/utils.py b/packages/typespec-python/test/azure/generated/versioning-madeoptional/versioning/madeoptional/_utils/utils.py new file mode 100644 index 00000000000..35c9c836f85 --- /dev/null +++ b/packages/typespec-python/test/azure/generated/versioning-madeoptional/versioning/madeoptional/_utils/utils.py @@ -0,0 +1,25 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) Python Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from abc import ABC +from typing import Generic, TYPE_CHECKING, TypeVar + +if TYPE_CHECKING: + from .serialization import Deserializer, Serializer + + +TClient = TypeVar("TClient") +TConfig = TypeVar("TConfig") + + +class ClientMixinABC(ABC, Generic[TClient, TConfig]): + """DO NOT use this class. It is for internal typing use only.""" + + _client: TClient + _config: TConfig + _serialize: "Serializer" + _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/azure/generated/versioning-madeoptional/versioning/madeoptional/_vendor.py b/packages/typespec-python/test/azure/generated/versioning-madeoptional/versioning/madeoptional/_vendor.py deleted file mode 100644 index cd65b2e21c7..00000000000 --- a/packages/typespec-python/test/azure/generated/versioning-madeoptional/versioning/madeoptional/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) Python Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import MadeOptionalClientConfiguration - -if TYPE_CHECKING: - from azure.core import PipelineClient - - from ._serialization import Deserializer, Serializer - - -class MadeOptionalClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "PipelineClient" - _config: MadeOptionalClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/azure/generated/versioning-madeoptional/versioning/madeoptional/aio/_client.py b/packages/typespec-python/test/azure/generated/versioning-madeoptional/versioning/madeoptional/aio/_client.py index c1454ab4772..21f7052ed61 100644 --- a/packages/typespec-python/test/azure/generated/versioning-madeoptional/versioning/madeoptional/aio/_client.py +++ b/packages/typespec-python/test/azure/generated/versioning-madeoptional/versioning/madeoptional/aio/_client.py @@ -15,7 +15,7 @@ from azure.core.rest import AsyncHttpResponse, HttpRequest from .. import models as _models -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import MadeOptionalClientConfiguration from ._operations import MadeOptionalClientOperationsMixin diff --git a/packages/typespec-python/test/azure/generated/versioning-madeoptional/versioning/madeoptional/aio/_operations/_operations.py b/packages/typespec-python/test/azure/generated/versioning-madeoptional/versioning/madeoptional/aio/_operations/_operations.py index 04aba959ec1..dc6852ad369 100644 --- a/packages/typespec-python/test/azure/generated/versioning-madeoptional/versioning/madeoptional/aio/_operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/versioning-madeoptional/versioning/madeoptional/aio/_operations/_operations.py @@ -11,6 +11,7 @@ import json from typing import Any, Callable, Dict, IO, Optional, TypeVar, Union, overload +from azure.core import AsyncPipelineClient from azure.core.exceptions import ( ClientAuthenticationError, HttpResponseError, @@ -27,16 +28,17 @@ from azure.core.utils import case_insensitive_dict from ... import models as _models -from ..._model_base import SdkJSONEncoder, _deserialize from ..._operations._operations import build_made_optional_test_request -from .._vendor import MadeOptionalClientMixinABC +from ..._utils.model_base import SdkJSONEncoder, _deserialize +from ..._utils.utils import ClientMixinABC +from .._configuration import MadeOptionalClientConfiguration JSON = MutableMapping[str, Any] T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, AsyncHttpResponse], T, Dict[str, Any]], Any]] -class MadeOptionalClientOperationsMixin(MadeOptionalClientMixinABC): +class MadeOptionalClientOperationsMixin(ClientMixinABC[AsyncPipelineClient, MadeOptionalClientConfiguration]): @overload async def test( diff --git a/packages/typespec-python/test/azure/generated/versioning-madeoptional/versioning/madeoptional/aio/_vendor.py b/packages/typespec-python/test/azure/generated/versioning-madeoptional/versioning/madeoptional/aio/_vendor.py deleted file mode 100644 index 88e2f72f142..00000000000 --- a/packages/typespec-python/test/azure/generated/versioning-madeoptional/versioning/madeoptional/aio/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) Python Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import MadeOptionalClientConfiguration - -if TYPE_CHECKING: - from azure.core import AsyncPipelineClient - - from .._serialization import Deserializer, Serializer - - -class MadeOptionalClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "AsyncPipelineClient" - _config: MadeOptionalClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/azure/generated/versioning-madeoptional/versioning/madeoptional/models/_models.py b/packages/typespec-python/test/azure/generated/versioning-madeoptional/versioning/madeoptional/models/_models.py index c2449575c39..fc39c72cbaf 100644 --- a/packages/typespec-python/test/azure/generated/versioning-madeoptional/versioning/madeoptional/models/_models.py +++ b/packages/typespec-python/test/azure/generated/versioning-madeoptional/versioning/madeoptional/models/_models.py @@ -9,11 +9,10 @@ from typing import Any, Mapping, Optional, overload -from .. import _model_base -from .._model_base import rest_field +from .._utils.model_base import Model as _Model, rest_field -class TestModel(_model_base.Model): +class TestModel(_Model): """TestModel. :ivar prop: Required. diff --git a/packages/typespec-python/test/azure/generated/versioning-removed/versioning/removed/_client.py b/packages/typespec-python/test/azure/generated/versioning-removed/versioning/removed/_client.py index 1728970044f..767add0bd06 100644 --- a/packages/typespec-python/test/azure/generated/versioning-removed/versioning/removed/_client.py +++ b/packages/typespec-python/test/azure/generated/versioning-removed/versioning/removed/_client.py @@ -17,7 +17,7 @@ from . import models as _models from ._configuration import RemovedClientConfiguration from ._operations import RemovedClientOperationsMixin -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer class RemovedClient(RemovedClientOperationsMixin): # pylint: disable=client-accepts-api-version-keyword diff --git a/packages/typespec-python/test/azure/generated/versioning-removed/versioning/removed/_operations/_operations.py b/packages/typespec-python/test/azure/generated/versioning-removed/versioning/removed/_operations/_operations.py index 0e90b2c5007..4ff1ba9a157 100644 --- a/packages/typespec-python/test/azure/generated/versioning-removed/versioning/removed/_operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/versioning-removed/versioning/removed/_operations/_operations.py @@ -10,6 +10,7 @@ import json from typing import Any, Callable, Dict, IO, Optional, TypeVar, Union, overload +from azure.core import PipelineClient from azure.core.exceptions import ( ClientAuthenticationError, HttpResponseError, @@ -26,9 +27,10 @@ from azure.core.utils import case_insensitive_dict from .. import models as _models -from .._model_base import SdkJSONEncoder, _deserialize -from .._serialization import Serializer -from .._vendor import RemovedClientMixinABC +from .._configuration import RemovedClientConfiguration +from .._utils.model_base import SdkJSONEncoder, _deserialize +from .._utils.serialization import Serializer +from .._utils.utils import ClientMixinABC JSON = MutableMapping[str, Any] T = TypeVar("T") @@ -72,7 +74,7 @@ def build_removed_model_v3_request(**kwargs: Any) -> HttpRequest: return HttpRequest(method="POST", url=_url, headers=_headers, **kwargs) -class RemovedClientOperationsMixin(RemovedClientMixinABC): +class RemovedClientOperationsMixin(ClientMixinABC[PipelineClient, RemovedClientConfiguration]): @overload def v2(self, body: _models.ModelV2, *, content_type: str = "application/json", **kwargs: Any) -> _models.ModelV2: diff --git a/packages/typespec-python/test/azure/generated/versioning-removed/versioning/removed/_utils/__init__.py b/packages/typespec-python/test/azure/generated/versioning-removed/versioning/removed/_utils/__init__.py new file mode 100644 index 00000000000..8026245c2ab --- /dev/null +++ b/packages/typespec-python/test/azure/generated/versioning-removed/versioning/removed/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) Python Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/typespec-python/test/azure/generated/versioning-renamedfrom/versioning/renamedfrom/_model_base.py b/packages/typespec-python/test/azure/generated/versioning-removed/versioning/removed/_utils/model_base.py similarity index 100% rename from packages/typespec-python/test/azure/generated/versioning-renamedfrom/versioning/renamedfrom/_model_base.py rename to packages/typespec-python/test/azure/generated/versioning-removed/versioning/removed/_utils/model_base.py diff --git a/packages/typespec-python/test/azure/generated/versioning-renamedfrom/versioning/renamedfrom/_serialization.py b/packages/typespec-python/test/azure/generated/versioning-removed/versioning/removed/_utils/serialization.py similarity index 100% rename from packages/typespec-python/test/azure/generated/versioning-renamedfrom/versioning/renamedfrom/_serialization.py rename to packages/typespec-python/test/azure/generated/versioning-removed/versioning/removed/_utils/serialization.py diff --git a/packages/typespec-python/test/azure/generated/versioning-removed/versioning/removed/_utils/utils.py b/packages/typespec-python/test/azure/generated/versioning-removed/versioning/removed/_utils/utils.py new file mode 100644 index 00000000000..35c9c836f85 --- /dev/null +++ b/packages/typespec-python/test/azure/generated/versioning-removed/versioning/removed/_utils/utils.py @@ -0,0 +1,25 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) Python Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from abc import ABC +from typing import Generic, TYPE_CHECKING, TypeVar + +if TYPE_CHECKING: + from .serialization import Deserializer, Serializer + + +TClient = TypeVar("TClient") +TConfig = TypeVar("TConfig") + + +class ClientMixinABC(ABC, Generic[TClient, TConfig]): + """DO NOT use this class. It is for internal typing use only.""" + + _client: TClient + _config: TConfig + _serialize: "Serializer" + _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/azure/generated/versioning-removed/versioning/removed/_vendor.py b/packages/typespec-python/test/azure/generated/versioning-removed/versioning/removed/_vendor.py deleted file mode 100644 index bc90285b643..00000000000 --- a/packages/typespec-python/test/azure/generated/versioning-removed/versioning/removed/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) Python Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import RemovedClientConfiguration - -if TYPE_CHECKING: - from azure.core import PipelineClient - - from ._serialization import Deserializer, Serializer - - -class RemovedClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "PipelineClient" - _config: RemovedClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/azure/generated/versioning-removed/versioning/removed/aio/_client.py b/packages/typespec-python/test/azure/generated/versioning-removed/versioning/removed/aio/_client.py index 85de8e83f14..0ed3de59de9 100644 --- a/packages/typespec-python/test/azure/generated/versioning-removed/versioning/removed/aio/_client.py +++ b/packages/typespec-python/test/azure/generated/versioning-removed/versioning/removed/aio/_client.py @@ -15,7 +15,7 @@ from azure.core.rest import AsyncHttpResponse, HttpRequest from .. import models as _models -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import RemovedClientConfiguration from ._operations import RemovedClientOperationsMixin diff --git a/packages/typespec-python/test/azure/generated/versioning-removed/versioning/removed/aio/_operations/_operations.py b/packages/typespec-python/test/azure/generated/versioning-removed/versioning/removed/aio/_operations/_operations.py index 342ea4c3029..989d8643791 100644 --- a/packages/typespec-python/test/azure/generated/versioning-removed/versioning/removed/aio/_operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/versioning-removed/versioning/removed/aio/_operations/_operations.py @@ -11,6 +11,7 @@ import json from typing import Any, Callable, Dict, IO, Optional, TypeVar, Union, overload +from azure.core import AsyncPipelineClient from azure.core.exceptions import ( ClientAuthenticationError, HttpResponseError, @@ -27,16 +28,17 @@ from azure.core.utils import case_insensitive_dict from ... import models as _models -from ..._model_base import SdkJSONEncoder, _deserialize from ..._operations._operations import build_removed_model_v3_request, build_removed_v2_request -from .._vendor import RemovedClientMixinABC +from ..._utils.model_base import SdkJSONEncoder, _deserialize +from ..._utils.utils import ClientMixinABC +from .._configuration import RemovedClientConfiguration JSON = MutableMapping[str, Any] T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, AsyncHttpResponse], T, Dict[str, Any]], Any]] -class RemovedClientOperationsMixin(RemovedClientMixinABC): +class RemovedClientOperationsMixin(ClientMixinABC[AsyncPipelineClient, RemovedClientConfiguration]): @overload async def v2( diff --git a/packages/typespec-python/test/azure/generated/versioning-removed/versioning/removed/aio/_vendor.py b/packages/typespec-python/test/azure/generated/versioning-removed/versioning/removed/aio/_vendor.py deleted file mode 100644 index 2da759abf44..00000000000 --- a/packages/typespec-python/test/azure/generated/versioning-removed/versioning/removed/aio/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) Python Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import RemovedClientConfiguration - -if TYPE_CHECKING: - from azure.core import AsyncPipelineClient - - from .._serialization import Deserializer, Serializer - - -class RemovedClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "AsyncPipelineClient" - _config: RemovedClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/azure/generated/versioning-removed/versioning/removed/models/_models.py b/packages/typespec-python/test/azure/generated/versioning-removed/versioning/removed/models/_models.py index dbce875014e..6b0caf6b2b5 100644 --- a/packages/typespec-python/test/azure/generated/versioning-removed/versioning/removed/models/_models.py +++ b/packages/typespec-python/test/azure/generated/versioning-removed/versioning/removed/models/_models.py @@ -9,14 +9,13 @@ from typing import Any, Mapping, TYPE_CHECKING, Union, overload -from .. import _model_base -from .._model_base import rest_field +from .._utils.model_base import Model as _Model, rest_field if TYPE_CHECKING: from .. import _types, models as _models -class ModelV2(_model_base.Model): +class ModelV2(_Model): """ModelV2. :ivar prop: Required. @@ -58,7 +57,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class ModelV3(_model_base.Model): +class ModelV3(_Model): """ModelV3. :ivar id: Required. diff --git a/packages/typespec-python/test/azure/generated/versioning-renamedfrom/versioning/renamedfrom/_client.py b/packages/typespec-python/test/azure/generated/versioning-renamedfrom/versioning/renamedfrom/_client.py index 3c47db31a46..703005eae60 100644 --- a/packages/typespec-python/test/azure/generated/versioning-renamedfrom/versioning/renamedfrom/_client.py +++ b/packages/typespec-python/test/azure/generated/versioning-renamedfrom/versioning/renamedfrom/_client.py @@ -16,7 +16,7 @@ from . import models as _models from ._configuration import RenamedFromClientConfiguration -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer from .operations import NewInterfaceOperations, RenamedFromClientOperationsMixin diff --git a/packages/typespec-python/test/azure/generated/versioning-renamedfrom/versioning/renamedfrom/_utils/__init__.py b/packages/typespec-python/test/azure/generated/versioning-renamedfrom/versioning/renamedfrom/_utils/__init__.py new file mode 100644 index 00000000000..8026245c2ab --- /dev/null +++ b/packages/typespec-python/test/azure/generated/versioning-renamedfrom/versioning/renamedfrom/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) Python Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/typespec-python/test/azure/generated/versioning-returntypechangedfrom/versioning/returntypechangedfrom/_model_base.py b/packages/typespec-python/test/azure/generated/versioning-renamedfrom/versioning/renamedfrom/_utils/model_base.py similarity index 100% rename from packages/typespec-python/test/azure/generated/versioning-returntypechangedfrom/versioning/returntypechangedfrom/_model_base.py rename to packages/typespec-python/test/azure/generated/versioning-renamedfrom/versioning/renamedfrom/_utils/model_base.py diff --git a/packages/typespec-python/test/azure/generated/versioning-returntypechangedfrom/versioning/returntypechangedfrom/_serialization.py b/packages/typespec-python/test/azure/generated/versioning-renamedfrom/versioning/renamedfrom/_utils/serialization.py similarity index 100% rename from packages/typespec-python/test/azure/generated/versioning-returntypechangedfrom/versioning/returntypechangedfrom/_serialization.py rename to packages/typespec-python/test/azure/generated/versioning-renamedfrom/versioning/renamedfrom/_utils/serialization.py diff --git a/packages/typespec-python/test/azure/generated/versioning-renamedfrom/versioning/renamedfrom/_utils/utils.py b/packages/typespec-python/test/azure/generated/versioning-renamedfrom/versioning/renamedfrom/_utils/utils.py new file mode 100644 index 00000000000..35c9c836f85 --- /dev/null +++ b/packages/typespec-python/test/azure/generated/versioning-renamedfrom/versioning/renamedfrom/_utils/utils.py @@ -0,0 +1,25 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) Python Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from abc import ABC +from typing import Generic, TYPE_CHECKING, TypeVar + +if TYPE_CHECKING: + from .serialization import Deserializer, Serializer + + +TClient = TypeVar("TClient") +TConfig = TypeVar("TConfig") + + +class ClientMixinABC(ABC, Generic[TClient, TConfig]): + """DO NOT use this class. It is for internal typing use only.""" + + _client: TClient + _config: TConfig + _serialize: "Serializer" + _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/azure/generated/versioning-renamedfrom/versioning/renamedfrom/_vendor.py b/packages/typespec-python/test/azure/generated/versioning-renamedfrom/versioning/renamedfrom/_vendor.py deleted file mode 100644 index 58ea6f6e27e..00000000000 --- a/packages/typespec-python/test/azure/generated/versioning-renamedfrom/versioning/renamedfrom/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) Python Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import RenamedFromClientConfiguration - -if TYPE_CHECKING: - from azure.core import PipelineClient - - from ._serialization import Deserializer, Serializer - - -class RenamedFromClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "PipelineClient" - _config: RenamedFromClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/azure/generated/versioning-renamedfrom/versioning/renamedfrom/aio/_client.py b/packages/typespec-python/test/azure/generated/versioning-renamedfrom/versioning/renamedfrom/aio/_client.py index dc5c1e215e0..5867e4ccf29 100644 --- a/packages/typespec-python/test/azure/generated/versioning-renamedfrom/versioning/renamedfrom/aio/_client.py +++ b/packages/typespec-python/test/azure/generated/versioning-renamedfrom/versioning/renamedfrom/aio/_client.py @@ -15,7 +15,7 @@ from azure.core.rest import AsyncHttpResponse, HttpRequest from .. import models as _models -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import RenamedFromClientConfiguration from .operations import NewInterfaceOperations, RenamedFromClientOperationsMixin diff --git a/packages/typespec-python/test/azure/generated/versioning-renamedfrom/versioning/renamedfrom/aio/_vendor.py b/packages/typespec-python/test/azure/generated/versioning-renamedfrom/versioning/renamedfrom/aio/_vendor.py deleted file mode 100644 index 9efbf1c2f6d..00000000000 --- a/packages/typespec-python/test/azure/generated/versioning-renamedfrom/versioning/renamedfrom/aio/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) Python Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import RenamedFromClientConfiguration - -if TYPE_CHECKING: - from azure.core import AsyncPipelineClient - - from .._serialization import Deserializer, Serializer - - -class RenamedFromClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "AsyncPipelineClient" - _config: RenamedFromClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/azure/generated/versioning-renamedfrom/versioning/renamedfrom/aio/operations/_operations.py b/packages/typespec-python/test/azure/generated/versioning-renamedfrom/versioning/renamedfrom/aio/operations/_operations.py index e58565759df..57701d70812 100644 --- a/packages/typespec-python/test/azure/generated/versioning-renamedfrom/versioning/renamedfrom/aio/operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/versioning-renamedfrom/versioning/renamedfrom/aio/operations/_operations.py @@ -28,14 +28,14 @@ from azure.core.utils import case_insensitive_dict from ... import models as _models -from ..._model_base import SdkJSONEncoder, _deserialize -from ..._serialization import Deserializer, Serializer +from ..._utils.model_base import SdkJSONEncoder, _deserialize +from ..._utils.serialization import Deserializer, Serializer +from ..._utils.utils import ClientMixinABC from ...operations._operations import ( build_new_interface_new_op_in_new_interface_request, build_renamed_from_new_op_request, ) from .._configuration import RenamedFromClientConfiguration -from .._vendor import RenamedFromClientMixinABC JSON = MutableMapping[str, Any] T = TypeVar("T") @@ -179,7 +179,7 @@ async def new_op_in_new_interface( return deserialized # type: ignore -class RenamedFromClientOperationsMixin(RenamedFromClientMixinABC): +class RenamedFromClientOperationsMixin(ClientMixinABC[AsyncPipelineClient, RenamedFromClientConfiguration]): @overload async def new_op( diff --git a/packages/typespec-python/test/azure/generated/versioning-renamedfrom/versioning/renamedfrom/models/_models.py b/packages/typespec-python/test/azure/generated/versioning-renamedfrom/versioning/renamedfrom/models/_models.py index cd263115fd2..0683fe19dee 100644 --- a/packages/typespec-python/test/azure/generated/versioning-renamedfrom/versioning/renamedfrom/models/_models.py +++ b/packages/typespec-python/test/azure/generated/versioning-renamedfrom/versioning/renamedfrom/models/_models.py @@ -9,14 +9,13 @@ from typing import Any, Mapping, TYPE_CHECKING, Union, overload -from .. import _model_base -from .._model_base import rest_field +from .._utils.model_base import Model as _Model, rest_field if TYPE_CHECKING: from .. import _types, models as _models -class NewModel(_model_base.Model): +class NewModel(_Model): """NewModel. :ivar new_prop: Required. diff --git a/packages/typespec-python/test/azure/generated/versioning-renamedfrom/versioning/renamedfrom/operations/_operations.py b/packages/typespec-python/test/azure/generated/versioning-renamedfrom/versioning/renamedfrom/operations/_operations.py index 47412a7c721..07c2496ea84 100644 --- a/packages/typespec-python/test/azure/generated/versioning-renamedfrom/versioning/renamedfrom/operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/versioning-renamedfrom/versioning/renamedfrom/operations/_operations.py @@ -28,9 +28,9 @@ from .. import models as _models from .._configuration import RenamedFromClientConfiguration -from .._model_base import SdkJSONEncoder, _deserialize -from .._serialization import Deserializer, Serializer -from .._vendor import RenamedFromClientMixinABC +from .._utils.model_base import SdkJSONEncoder, _deserialize +from .._utils.serialization import Deserializer, Serializer +from .._utils.utils import ClientMixinABC JSON = MutableMapping[str, Any] T = TypeVar("T") @@ -215,7 +215,7 @@ def new_op_in_new_interface( return deserialized # type: ignore -class RenamedFromClientOperationsMixin(RenamedFromClientMixinABC): +class RenamedFromClientOperationsMixin(ClientMixinABC[PipelineClient, RenamedFromClientConfiguration]): @overload def new_op( diff --git a/packages/typespec-python/test/azure/generated/versioning-returntypechangedfrom/versioning/returntypechangedfrom/_client.py b/packages/typespec-python/test/azure/generated/versioning-returntypechangedfrom/versioning/returntypechangedfrom/_client.py index 91cc97cc55f..4a96297500a 100644 --- a/packages/typespec-python/test/azure/generated/versioning-returntypechangedfrom/versioning/returntypechangedfrom/_client.py +++ b/packages/typespec-python/test/azure/generated/versioning-returntypechangedfrom/versioning/returntypechangedfrom/_client.py @@ -17,7 +17,7 @@ from . import models as _models from ._configuration import ReturnTypeChangedFromClientConfiguration from ._operations import ReturnTypeChangedFromClientOperationsMixin -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer class ReturnTypeChangedFromClient( diff --git a/packages/typespec-python/test/azure/generated/versioning-returntypechangedfrom/versioning/returntypechangedfrom/_operations/_operations.py b/packages/typespec-python/test/azure/generated/versioning-returntypechangedfrom/versioning/returntypechangedfrom/_operations/_operations.py index 700a54746f2..af7b7767766 100644 --- a/packages/typespec-python/test/azure/generated/versioning-returntypechangedfrom/versioning/returntypechangedfrom/_operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/versioning-returntypechangedfrom/versioning/returntypechangedfrom/_operations/_operations.py @@ -9,6 +9,7 @@ import json from typing import Any, Callable, Dict, Optional, TypeVar +from azure.core import PipelineClient from azure.core.exceptions import ( ClientAuthenticationError, HttpResponseError, @@ -24,9 +25,10 @@ from azure.core.tracing.decorator import distributed_trace from azure.core.utils import case_insensitive_dict -from .._model_base import SdkJSONEncoder, _deserialize -from .._serialization import Serializer -from .._vendor import ReturnTypeChangedFromClientMixinABC +from .._configuration import ReturnTypeChangedFromClientConfiguration +from .._utils.model_base import SdkJSONEncoder, _deserialize +from .._utils.serialization import Serializer +from .._utils.utils import ClientMixinABC T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] @@ -51,7 +53,9 @@ def build_return_type_changed_from_test_request(**kwargs: Any) -> HttpRequest: return HttpRequest(method="POST", url=_url, headers=_headers, **kwargs) -class ReturnTypeChangedFromClientOperationsMixin(ReturnTypeChangedFromClientMixinABC): # pylint: disable=name-too-long +class ReturnTypeChangedFromClientOperationsMixin( # pylint: disable=name-too-long + ClientMixinABC[PipelineClient, ReturnTypeChangedFromClientConfiguration] +): @distributed_trace def test(self, body: str, **kwargs: Any) -> str: diff --git a/packages/typespec-python/test/azure/generated/versioning-returntypechangedfrom/versioning/returntypechangedfrom/_utils/__init__.py b/packages/typespec-python/test/azure/generated/versioning-returntypechangedfrom/versioning/returntypechangedfrom/_utils/__init__.py new file mode 100644 index 00000000000..8026245c2ab --- /dev/null +++ b/packages/typespec-python/test/azure/generated/versioning-returntypechangedfrom/versioning/returntypechangedfrom/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) Python Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/typespec-python/test/azure/generated/versioning-typechangedfrom/versioning/typechangedfrom/_model_base.py b/packages/typespec-python/test/azure/generated/versioning-returntypechangedfrom/versioning/returntypechangedfrom/_utils/model_base.py similarity index 100% rename from packages/typespec-python/test/azure/generated/versioning-typechangedfrom/versioning/typechangedfrom/_model_base.py rename to packages/typespec-python/test/azure/generated/versioning-returntypechangedfrom/versioning/returntypechangedfrom/_utils/model_base.py diff --git a/packages/typespec-python/test/azure/generated/versioning-typechangedfrom/versioning/typechangedfrom/_serialization.py b/packages/typespec-python/test/azure/generated/versioning-returntypechangedfrom/versioning/returntypechangedfrom/_utils/serialization.py similarity index 100% rename from packages/typespec-python/test/azure/generated/versioning-typechangedfrom/versioning/typechangedfrom/_serialization.py rename to packages/typespec-python/test/azure/generated/versioning-returntypechangedfrom/versioning/returntypechangedfrom/_utils/serialization.py diff --git a/packages/typespec-python/test/azure/generated/versioning-returntypechangedfrom/versioning/returntypechangedfrom/_utils/utils.py b/packages/typespec-python/test/azure/generated/versioning-returntypechangedfrom/versioning/returntypechangedfrom/_utils/utils.py new file mode 100644 index 00000000000..35c9c836f85 --- /dev/null +++ b/packages/typespec-python/test/azure/generated/versioning-returntypechangedfrom/versioning/returntypechangedfrom/_utils/utils.py @@ -0,0 +1,25 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) Python Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from abc import ABC +from typing import Generic, TYPE_CHECKING, TypeVar + +if TYPE_CHECKING: + from .serialization import Deserializer, Serializer + + +TClient = TypeVar("TClient") +TConfig = TypeVar("TConfig") + + +class ClientMixinABC(ABC, Generic[TClient, TConfig]): + """DO NOT use this class. It is for internal typing use only.""" + + _client: TClient + _config: TConfig + _serialize: "Serializer" + _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/azure/generated/versioning-returntypechangedfrom/versioning/returntypechangedfrom/_vendor.py b/packages/typespec-python/test/azure/generated/versioning-returntypechangedfrom/versioning/returntypechangedfrom/_vendor.py deleted file mode 100644 index b3ff6f2365c..00000000000 --- a/packages/typespec-python/test/azure/generated/versioning-returntypechangedfrom/versioning/returntypechangedfrom/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) Python Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import ReturnTypeChangedFromClientConfiguration - -if TYPE_CHECKING: - from azure.core import PipelineClient - - from ._serialization import Deserializer, Serializer - - -class ReturnTypeChangedFromClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "PipelineClient" - _config: ReturnTypeChangedFromClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/azure/generated/versioning-returntypechangedfrom/versioning/returntypechangedfrom/aio/_client.py b/packages/typespec-python/test/azure/generated/versioning-returntypechangedfrom/versioning/returntypechangedfrom/aio/_client.py index 1207292d438..53b456e57eb 100644 --- a/packages/typespec-python/test/azure/generated/versioning-returntypechangedfrom/versioning/returntypechangedfrom/aio/_client.py +++ b/packages/typespec-python/test/azure/generated/versioning-returntypechangedfrom/versioning/returntypechangedfrom/aio/_client.py @@ -15,7 +15,7 @@ from azure.core.rest import AsyncHttpResponse, HttpRequest from .. import models as _models -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import ReturnTypeChangedFromClientConfiguration from ._operations import ReturnTypeChangedFromClientOperationsMixin diff --git a/packages/typespec-python/test/azure/generated/versioning-returntypechangedfrom/versioning/returntypechangedfrom/aio/_operations/_operations.py b/packages/typespec-python/test/azure/generated/versioning-returntypechangedfrom/versioning/returntypechangedfrom/aio/_operations/_operations.py index 49ba89900fb..ea4ea898b22 100644 --- a/packages/typespec-python/test/azure/generated/versioning-returntypechangedfrom/versioning/returntypechangedfrom/aio/_operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/versioning-returntypechangedfrom/versioning/returntypechangedfrom/aio/_operations/_operations.py @@ -10,6 +10,7 @@ import json from typing import Any, Callable, Dict, Optional, TypeVar +from azure.core import AsyncPipelineClient from azure.core.exceptions import ( ClientAuthenticationError, HttpResponseError, @@ -25,15 +26,18 @@ from azure.core.tracing.decorator_async import distributed_trace_async from azure.core.utils import case_insensitive_dict -from ..._model_base import SdkJSONEncoder, _deserialize from ..._operations._operations import build_return_type_changed_from_test_request -from .._vendor import ReturnTypeChangedFromClientMixinABC +from ..._utils.model_base import SdkJSONEncoder, _deserialize +from ..._utils.utils import ClientMixinABC +from .._configuration import ReturnTypeChangedFromClientConfiguration T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, AsyncHttpResponse], T, Dict[str, Any]], Any]] -class ReturnTypeChangedFromClientOperationsMixin(ReturnTypeChangedFromClientMixinABC): # pylint: disable=name-too-long +class ReturnTypeChangedFromClientOperationsMixin( # pylint: disable=name-too-long + ClientMixinABC[AsyncPipelineClient, ReturnTypeChangedFromClientConfiguration] +): @distributed_trace_async async def test(self, body: str, **kwargs: Any) -> str: diff --git a/packages/typespec-python/test/azure/generated/versioning-returntypechangedfrom/versioning/returntypechangedfrom/aio/_vendor.py b/packages/typespec-python/test/azure/generated/versioning-returntypechangedfrom/versioning/returntypechangedfrom/aio/_vendor.py deleted file mode 100644 index fd597fb4fe8..00000000000 --- a/packages/typespec-python/test/azure/generated/versioning-returntypechangedfrom/versioning/returntypechangedfrom/aio/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) Python Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import ReturnTypeChangedFromClientConfiguration - -if TYPE_CHECKING: - from azure.core import AsyncPipelineClient - - from .._serialization import Deserializer, Serializer - - -class ReturnTypeChangedFromClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "AsyncPipelineClient" - _config: ReturnTypeChangedFromClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/azure/generated/versioning-typechangedfrom/versioning/typechangedfrom/_client.py b/packages/typespec-python/test/azure/generated/versioning-typechangedfrom/versioning/typechangedfrom/_client.py index 01aa204e048..a5a8481e329 100644 --- a/packages/typespec-python/test/azure/generated/versioning-typechangedfrom/versioning/typechangedfrom/_client.py +++ b/packages/typespec-python/test/azure/generated/versioning-typechangedfrom/versioning/typechangedfrom/_client.py @@ -17,7 +17,7 @@ from . import models as _models from ._configuration import TypeChangedFromClientConfiguration from ._operations import TypeChangedFromClientOperationsMixin -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer class TypeChangedFromClient(TypeChangedFromClientOperationsMixin): # pylint: disable=client-accepts-api-version-keyword diff --git a/packages/typespec-python/test/azure/generated/versioning-typechangedfrom/versioning/typechangedfrom/_operations/_operations.py b/packages/typespec-python/test/azure/generated/versioning-typechangedfrom/versioning/typechangedfrom/_operations/_operations.py index a249c327ccb..34e0a09030a 100644 --- a/packages/typespec-python/test/azure/generated/versioning-typechangedfrom/versioning/typechangedfrom/_operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/versioning-typechangedfrom/versioning/typechangedfrom/_operations/_operations.py @@ -10,6 +10,7 @@ import json from typing import Any, Callable, Dict, IO, Optional, TypeVar, Union, overload +from azure.core import PipelineClient from azure.core.exceptions import ( ClientAuthenticationError, HttpResponseError, @@ -26,9 +27,10 @@ from azure.core.utils import case_insensitive_dict from .. import models as _models -from .._model_base import SdkJSONEncoder, _deserialize -from .._serialization import Serializer -from .._vendor import TypeChangedFromClientMixinABC +from .._configuration import TypeChangedFromClientConfiguration +from .._utils.model_base import SdkJSONEncoder, _deserialize +from .._utils.serialization import Serializer +from .._utils.utils import ClientMixinABC JSON = MutableMapping[str, Any] T = TypeVar("T") @@ -59,7 +61,7 @@ def build_type_changed_from_test_request(*, param: str, **kwargs: Any) -> HttpRe return HttpRequest(method="POST", url=_url, params=_params, headers=_headers, **kwargs) -class TypeChangedFromClientOperationsMixin(TypeChangedFromClientMixinABC): +class TypeChangedFromClientOperationsMixin(ClientMixinABC[PipelineClient, TypeChangedFromClientConfiguration]): @overload def test( diff --git a/packages/typespec-python/test/azure/generated/versioning-typechangedfrom/versioning/typechangedfrom/_utils/__init__.py b/packages/typespec-python/test/azure/generated/versioning-typechangedfrom/versioning/typechangedfrom/_utils/__init__.py new file mode 100644 index 00000000000..8026245c2ab --- /dev/null +++ b/packages/typespec-python/test/azure/generated/versioning-typechangedfrom/versioning/typechangedfrom/_utils/__init__.py @@ -0,0 +1,6 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) Python Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- diff --git a/packages/typespec-python/test/azure/generated/versioning-typechangedfrom/versioning/typechangedfrom/_utils/model_base.py b/packages/typespec-python/test/azure/generated/versioning-typechangedfrom/versioning/typechangedfrom/_utils/model_base.py new file mode 100644 index 00000000000..49d5c725938 --- /dev/null +++ b/packages/typespec-python/test/azure/generated/versioning-typechangedfrom/versioning/typechangedfrom/_utils/model_base.py @@ -0,0 +1,1232 @@ +# pylint: disable=too-many-lines +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) Python Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- +# pylint: disable=protected-access, broad-except + +import copy +import calendar +import decimal +import functools +import sys +import logging +import base64 +import re +import typing +import enum +import email.utils +from datetime import datetime, date, time, timedelta, timezone +from json import JSONEncoder +import xml.etree.ElementTree as ET +from collections.abc import MutableMapping +from typing_extensions import Self +import isodate +from azure.core.exceptions import DeserializationError +from azure.core import CaseInsensitiveEnumMeta +from azure.core.pipeline import PipelineResponse +from azure.core.serialization import _Null + +_LOGGER = logging.getLogger(__name__) + +__all__ = ["SdkJSONEncoder", "Model", "rest_field", "rest_discriminator"] + +TZ_UTC = timezone.utc +_T = typing.TypeVar("_T") + + +def _timedelta_as_isostr(td: timedelta) -> str: + """Converts a datetime.timedelta object into an ISO 8601 formatted string, e.g. 'P4DT12H30M05S' + + Function adapted from the Tin Can Python project: https://github.com/RusticiSoftware/TinCanPython + + :param timedelta td: The timedelta to convert + :rtype: str + :return: ISO8601 version of this timedelta + """ + + # Split seconds to larger units + seconds = td.total_seconds() + minutes, seconds = divmod(seconds, 60) + hours, minutes = divmod(minutes, 60) + days, hours = divmod(hours, 24) + + days, hours, minutes = list(map(int, (days, hours, minutes))) + seconds = round(seconds, 6) + + # Build date + date_str = "" + if days: + date_str = "%sD" % days + + if hours or minutes or seconds: + # Build time + time_str = "T" + + # Hours + bigger_exists = date_str or hours + if bigger_exists: + time_str += "{:02}H".format(hours) + + # Minutes + bigger_exists = bigger_exists or minutes + if bigger_exists: + time_str += "{:02}M".format(minutes) + + # Seconds + try: + if seconds.is_integer(): + seconds_string = "{:02}".format(int(seconds)) + else: + # 9 chars long w/ leading 0, 6 digits after decimal + seconds_string = "%09.6f" % seconds + # Remove trailing zeros + seconds_string = seconds_string.rstrip("0") + except AttributeError: # int.is_integer() raises + seconds_string = "{:02}".format(seconds) + + time_str += "{}S".format(seconds_string) + else: + time_str = "" + + return "P" + date_str + time_str + + +def _serialize_bytes(o, format: typing.Optional[str] = None) -> str: + encoded = base64.b64encode(o).decode() + if format == "base64url": + return encoded.strip("=").replace("+", "-").replace("/", "_") + return encoded + + +def _serialize_datetime(o, format: typing.Optional[str] = None): + if hasattr(o, "year") and hasattr(o, "hour"): + if format == "rfc7231": + return email.utils.format_datetime(o, usegmt=True) + if format == "unix-timestamp": + return int(calendar.timegm(o.utctimetuple())) + + # astimezone() fails for naive times in Python 2.7, so make make sure o is aware (tzinfo is set) + if not o.tzinfo: + iso_formatted = o.replace(tzinfo=TZ_UTC).isoformat() + else: + iso_formatted = o.astimezone(TZ_UTC).isoformat() + # Replace the trailing "+00:00" UTC offset with "Z" (RFC 3339: https://www.ietf.org/rfc/rfc3339.txt) + return iso_formatted.replace("+00:00", "Z") + # Next try datetime.date or datetime.time + return o.isoformat() + + +def _is_readonly(p): + try: + return p._visibility == ["read"] + except AttributeError: + return False + + +class SdkJSONEncoder(JSONEncoder): + """A JSON encoder that's capable of serializing datetime objects and bytes.""" + + def __init__(self, *args, exclude_readonly: bool = False, format: typing.Optional[str] = None, **kwargs): + super().__init__(*args, **kwargs) + self.exclude_readonly = exclude_readonly + self.format = format + + def default(self, o): # pylint: disable=too-many-return-statements + if _is_model(o): + if self.exclude_readonly: + readonly_props = [p._rest_name for p in o._attr_to_rest_field.values() if _is_readonly(p)] + return {k: v for k, v in o.items() if k not in readonly_props} + return dict(o.items()) + try: + return super(SdkJSONEncoder, self).default(o) + except TypeError: + if isinstance(o, _Null): + return None + if isinstance(o, decimal.Decimal): + return float(o) + if isinstance(o, (bytes, bytearray)): + return _serialize_bytes(o, self.format) + try: + # First try datetime.datetime + return _serialize_datetime(o, self.format) + except AttributeError: + pass + # Last, try datetime.timedelta + try: + return _timedelta_as_isostr(o) + except AttributeError: + # This will be raised when it hits value.total_seconds in the method above + pass + return super(SdkJSONEncoder, self).default(o) + + +_VALID_DATE = re.compile(r"\d{4}[-]\d{2}[-]\d{2}T\d{2}:\d{2}:\d{2}" + r"\.?\d*Z?[-+]?[\d{2}]?:?[\d{2}]?") +_VALID_RFC7231 = re.compile( + r"(Mon|Tue|Wed|Thu|Fri|Sat|Sun),\s\d{2}\s" + r"(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\s\d{4}\s\d{2}:\d{2}:\d{2}\sGMT" +) + + +def _deserialize_datetime(attr: typing.Union[str, datetime]) -> datetime: + """Deserialize ISO-8601 formatted string into Datetime object. + + :param str attr: response string to be deserialized. + :rtype: ~datetime.datetime + :returns: The datetime object from that input + """ + if isinstance(attr, datetime): + # i'm already deserialized + return attr + attr = attr.upper() + match = _VALID_DATE.match(attr) + if not match: + raise ValueError("Invalid datetime string: " + attr) + + check_decimal = attr.split(".") + if len(check_decimal) > 1: + decimal_str = "" + for digit in check_decimal[1]: + if digit.isdigit(): + decimal_str += digit + else: + break + if len(decimal_str) > 6: + attr = attr.replace(decimal_str, decimal_str[0:6]) + + date_obj = isodate.parse_datetime(attr) + test_utc = date_obj.utctimetuple() + if test_utc.tm_year > 9999 or test_utc.tm_year < 1: + raise OverflowError("Hit max or min date") + return date_obj + + +def _deserialize_datetime_rfc7231(attr: typing.Union[str, datetime]) -> datetime: + """Deserialize RFC7231 formatted string into Datetime object. + + :param str attr: response string to be deserialized. + :rtype: ~datetime.datetime + :returns: The datetime object from that input + """ + if isinstance(attr, datetime): + # i'm already deserialized + return attr + match = _VALID_RFC7231.match(attr) + if not match: + raise ValueError("Invalid datetime string: " + attr) + + return email.utils.parsedate_to_datetime(attr) + + +def _deserialize_datetime_unix_timestamp(attr: typing.Union[float, datetime]) -> datetime: + """Deserialize unix timestamp into Datetime object. + + :param str attr: response string to be deserialized. + :rtype: ~datetime.datetime + :returns: The datetime object from that input + """ + if isinstance(attr, datetime): + # i'm already deserialized + return attr + return datetime.fromtimestamp(attr, TZ_UTC) + + +def _deserialize_date(attr: typing.Union[str, date]) -> date: + """Deserialize ISO-8601 formatted string into Date object. + :param str attr: response string to be deserialized. + :rtype: date + :returns: The date object from that input + """ + # This must NOT use defaultmonth/defaultday. Using None ensure this raises an exception. + if isinstance(attr, date): + return attr + return isodate.parse_date(attr, defaultmonth=None, defaultday=None) # type: ignore + + +def _deserialize_time(attr: typing.Union[str, time]) -> time: + """Deserialize ISO-8601 formatted string into time object. + + :param str attr: response string to be deserialized. + :rtype: datetime.time + :returns: The time object from that input + """ + if isinstance(attr, time): + return attr + return isodate.parse_time(attr) + + +def _deserialize_bytes(attr): + if isinstance(attr, (bytes, bytearray)): + return attr + return bytes(base64.b64decode(attr)) + + +def _deserialize_bytes_base64(attr): + if isinstance(attr, (bytes, bytearray)): + return attr + padding = "=" * (3 - (len(attr) + 3) % 4) # type: ignore + attr = attr + padding # type: ignore + encoded = attr.replace("-", "+").replace("_", "/") + return bytes(base64.b64decode(encoded)) + + +def _deserialize_duration(attr): + if isinstance(attr, timedelta): + return attr + return isodate.parse_duration(attr) + + +def _deserialize_decimal(attr): + if isinstance(attr, decimal.Decimal): + return attr + return decimal.Decimal(str(attr)) + + +def _deserialize_int_as_str(attr): + if isinstance(attr, int): + return attr + return int(attr) + + +_DESERIALIZE_MAPPING = { + datetime: _deserialize_datetime, + date: _deserialize_date, + time: _deserialize_time, + bytes: _deserialize_bytes, + bytearray: _deserialize_bytes, + timedelta: _deserialize_duration, + typing.Any: lambda x: x, + decimal.Decimal: _deserialize_decimal, +} + +_DESERIALIZE_MAPPING_WITHFORMAT = { + "rfc3339": _deserialize_datetime, + "rfc7231": _deserialize_datetime_rfc7231, + "unix-timestamp": _deserialize_datetime_unix_timestamp, + "base64": _deserialize_bytes, + "base64url": _deserialize_bytes_base64, +} + + +def get_deserializer(annotation: typing.Any, rf: typing.Optional["_RestField"] = None): + if annotation is int and rf and rf._format == "str": + return _deserialize_int_as_str + if rf and rf._format: + return _DESERIALIZE_MAPPING_WITHFORMAT.get(rf._format) + return _DESERIALIZE_MAPPING.get(annotation) # pyright: ignore + + +def _get_type_alias_type(module_name: str, alias_name: str): + types = { + k: v + for k, v in sys.modules[module_name].__dict__.items() + if isinstance(v, typing._GenericAlias) # type: ignore + } + if alias_name not in types: + return alias_name + return types[alias_name] + + +def _get_model(module_name: str, model_name: str): + models = {k: v for k, v in sys.modules[module_name].__dict__.items() if isinstance(v, type)} + module_end = module_name.rsplit(".", 1)[0] + models.update({k: v for k, v in sys.modules[module_end].__dict__.items() if isinstance(v, type)}) + if isinstance(model_name, str): + model_name = model_name.split(".")[-1] + if model_name not in models: + return model_name + return models[model_name] + + +_UNSET = object() + + +class _MyMutableMapping(MutableMapping[str, typing.Any]): + def __init__(self, data: typing.Dict[str, typing.Any]) -> None: + self._data = data + + def __contains__(self, key: typing.Any) -> bool: + return key in self._data + + def __getitem__(self, key: str) -> typing.Any: + return self._data.__getitem__(key) + + def __setitem__(self, key: str, value: typing.Any) -> None: + self._data.__setitem__(key, value) + + def __delitem__(self, key: str) -> None: + self._data.__delitem__(key) + + def __iter__(self) -> typing.Iterator[typing.Any]: + return self._data.__iter__() + + def __len__(self) -> int: + return self._data.__len__() + + def __ne__(self, other: typing.Any) -> bool: + return not self.__eq__(other) + + def keys(self) -> typing.KeysView[str]: + """ + :returns: a set-like object providing a view on D's keys + :rtype: ~typing.KeysView + """ + return self._data.keys() + + def values(self) -> typing.ValuesView[typing.Any]: + """ + :returns: an object providing a view on D's values + :rtype: ~typing.ValuesView + """ + return self._data.values() + + def items(self) -> typing.ItemsView[str, typing.Any]: + """ + :returns: set-like object providing a view on D's items + :rtype: ~typing.ItemsView + """ + return self._data.items() + + def get(self, key: str, default: typing.Any = None) -> typing.Any: + """ + Get the value for key if key is in the dictionary, else default. + :param str key: The key to look up. + :param any default: The value to return if key is not in the dictionary. Defaults to None + :returns: D[k] if k in D, else d. + :rtype: any + """ + try: + return self[key] + except KeyError: + return default + + @typing.overload + def pop(self, key: str) -> typing.Any: ... # pylint: disable=arguments-differ + + @typing.overload + def pop(self, key: str, default: _T) -> _T: ... # pylint: disable=signature-differs + + @typing.overload + def pop(self, key: str, default: typing.Any) -> typing.Any: ... # pylint: disable=signature-differs + + def pop(self, key: str, default: typing.Any = _UNSET) -> typing.Any: + """ + Removes specified key and return the corresponding value. + :param str key: The key to pop. + :param any default: The value to return if key is not in the dictionary + :returns: The value corresponding to the key. + :rtype: any + :raises KeyError: If key is not found and default is not given. + """ + if default is _UNSET: + return self._data.pop(key) + return self._data.pop(key, default) + + def popitem(self) -> typing.Tuple[str, typing.Any]: + """ + Removes and returns some (key, value) pair + :returns: The (key, value) pair. + :rtype: tuple + :raises KeyError: if D is empty. + """ + return self._data.popitem() + + def clear(self) -> None: + """ + Remove all items from D. + """ + self._data.clear() + + def update(self, *args: typing.Any, **kwargs: typing.Any) -> None: # pylint: disable=arguments-differ + """ + Updates D from mapping/iterable E and F. + :param any args: Either a mapping object or an iterable of key-value pairs. + """ + self._data.update(*args, **kwargs) + + @typing.overload + def setdefault(self, key: str, default: None = None) -> None: ... + + @typing.overload + def setdefault(self, key: str, default: typing.Any) -> typing.Any: ... # pylint: disable=signature-differs + + def setdefault(self, key: str, default: typing.Any = _UNSET) -> typing.Any: + """ + Same as calling D.get(k, d), and setting D[k]=d if k not found + :param str key: The key to look up. + :param any default: The value to set if key is not in the dictionary + :returns: D[k] if k in D, else d. + :rtype: any + """ + if default is _UNSET: + return self._data.setdefault(key) + return self._data.setdefault(key, default) + + def __eq__(self, other: typing.Any) -> bool: + try: + other_model = self.__class__(other) + except Exception: + return False + return self._data == other_model._data + + def __repr__(self) -> str: + return str(self._data) + + +def _is_model(obj: typing.Any) -> bool: + return getattr(obj, "_is_model", False) + + +def _serialize(o, format: typing.Optional[str] = None): # pylint: disable=too-many-return-statements + if isinstance(o, list): + return [_serialize(x, format) for x in o] + if isinstance(o, dict): + return {k: _serialize(v, format) for k, v in o.items()} + if isinstance(o, set): + return {_serialize(x, format) for x in o} + if isinstance(o, tuple): + return tuple(_serialize(x, format) for x in o) + if isinstance(o, (bytes, bytearray)): + return _serialize_bytes(o, format) + if isinstance(o, decimal.Decimal): + return float(o) + if isinstance(o, enum.Enum): + return o.value + if isinstance(o, int): + if format == "str": + return str(o) + return o + try: + # First try datetime.datetime + return _serialize_datetime(o, format) + except AttributeError: + pass + # Last, try datetime.timedelta + try: + return _timedelta_as_isostr(o) + except AttributeError: + # This will be raised when it hits value.total_seconds in the method above + pass + return o + + +def _get_rest_field( + attr_to_rest_field: typing.Dict[str, "_RestField"], rest_name: str +) -> typing.Optional["_RestField"]: + try: + return next(rf for rf in attr_to_rest_field.values() if rf._rest_name == rest_name) + except StopIteration: + return None + + +def _create_value(rf: typing.Optional["_RestField"], value: typing.Any) -> typing.Any: + if not rf: + return _serialize(value, None) + if rf._is_multipart_file_input: + return value + if rf._is_model: + return _deserialize(rf._type, value) + if isinstance(value, ET.Element): + value = _deserialize(rf._type, value) + return _serialize(value, rf._format) + + +class Model(_MyMutableMapping): + _is_model = True + # label whether current class's _attr_to_rest_field has been calculated + # could not see _attr_to_rest_field directly because subclass inherits it from parent class + _calculated: typing.Set[str] = set() + + def __init__(self, *args: typing.Any, **kwargs: typing.Any) -> None: + class_name = self.__class__.__name__ + if len(args) > 1: + raise TypeError(f"{class_name}.__init__() takes 2 positional arguments but {len(args) + 1} were given") + dict_to_pass = { + rest_field._rest_name: rest_field._default + for rest_field in self._attr_to_rest_field.values() + if rest_field._default is not _UNSET + } + if args: # pylint: disable=too-many-nested-blocks + if isinstance(args[0], ET.Element): + existed_attr_keys = [] + model_meta = getattr(self, "_xml", {}) + + for rf in self._attr_to_rest_field.values(): + prop_meta = getattr(rf, "_xml", {}) + xml_name = prop_meta.get("name", rf._rest_name) + xml_ns = prop_meta.get("ns", model_meta.get("ns", None)) + if xml_ns: + xml_name = "{" + xml_ns + "}" + xml_name + + # attribute + if prop_meta.get("attribute", False) and args[0].get(xml_name) is not None: + existed_attr_keys.append(xml_name) + dict_to_pass[rf._rest_name] = _deserialize(rf._type, args[0].get(xml_name)) + continue + + # unwrapped element is array + if prop_meta.get("unwrapped", False): + # unwrapped array could either use prop items meta/prop meta + if prop_meta.get("itemsName"): + xml_name = prop_meta.get("itemsName") + xml_ns = prop_meta.get("itemNs") + if xml_ns: + xml_name = "{" + xml_ns + "}" + xml_name + items = args[0].findall(xml_name) # pyright: ignore + if len(items) > 0: + existed_attr_keys.append(xml_name) + dict_to_pass[rf._rest_name] = _deserialize(rf._type, items) + continue + + # text element is primitive type + if prop_meta.get("text", False): + if args[0].text is not None: + dict_to_pass[rf._rest_name] = _deserialize(rf._type, args[0].text) + continue + + # wrapped element could be normal property or array, it should only have one element + item = args[0].find(xml_name) + if item is not None: + existed_attr_keys.append(xml_name) + dict_to_pass[rf._rest_name] = _deserialize(rf._type, item) + + # rest thing is additional properties + for e in args[0]: + if e.tag not in existed_attr_keys: + dict_to_pass[e.tag] = _convert_element(e) + else: + dict_to_pass.update( + {k: _create_value(_get_rest_field(self._attr_to_rest_field, k), v) for k, v in args[0].items()} + ) + else: + non_attr_kwargs = [k for k in kwargs if k not in self._attr_to_rest_field] + if non_attr_kwargs: + # actual type errors only throw the first wrong keyword arg they see, so following that. + raise TypeError(f"{class_name}.__init__() got an unexpected keyword argument '{non_attr_kwargs[0]}'") + dict_to_pass.update( + { + self._attr_to_rest_field[k]._rest_name: _create_value(self._attr_to_rest_field[k], v) + for k, v in kwargs.items() + if v is not None + } + ) + super().__init__(dict_to_pass) + + def copy(self) -> "Model": + return Model(self.__dict__) + + def __new__(cls, *args: typing.Any, **kwargs: typing.Any) -> Self: + if f"{cls.__module__}.{cls.__qualname__}" not in cls._calculated: + # we know the last nine classes in mro are going to be 'Model', '_MyMutableMapping', 'MutableMapping', + # 'Mapping', 'Collection', 'Sized', 'Iterable', 'Container' and 'object' + mros = cls.__mro__[:-9][::-1] # ignore parents, and reverse the mro order + attr_to_rest_field: typing.Dict[str, _RestField] = { # map attribute name to rest_field property + k: v for mro_class in mros for k, v in mro_class.__dict__.items() if k[0] != "_" and hasattr(v, "_type") + } + annotations = { + k: v + for mro_class in mros + if hasattr(mro_class, "__annotations__") + for k, v in mro_class.__annotations__.items() + } + for attr, rf in attr_to_rest_field.items(): + rf._module = cls.__module__ + if not rf._type: + rf._type = rf._get_deserialize_callable_from_annotation(annotations.get(attr, None)) + if not rf._rest_name_input: + rf._rest_name_input = attr + cls._attr_to_rest_field: typing.Dict[str, _RestField] = dict(attr_to_rest_field.items()) + cls._calculated.add(f"{cls.__module__}.{cls.__qualname__}") + + return super().__new__(cls) + + def __init_subclass__(cls, discriminator: typing.Optional[str] = None) -> None: + for base in cls.__bases__: + if hasattr(base, "__mapping__"): + base.__mapping__[discriminator or cls.__name__] = cls # type: ignore + + @classmethod + def _get_discriminator(cls, exist_discriminators) -> typing.Optional["_RestField"]: + for v in cls.__dict__.values(): + if isinstance(v, _RestField) and v._is_discriminator and v._rest_name not in exist_discriminators: + return v + return None + + @classmethod + def _deserialize(cls, data, exist_discriminators): + if not hasattr(cls, "__mapping__"): + return cls(data) + discriminator = cls._get_discriminator(exist_discriminators) + if discriminator is None: + return cls(data) + exist_discriminators.append(discriminator._rest_name) + if isinstance(data, ET.Element): + model_meta = getattr(cls, "_xml", {}) + prop_meta = getattr(discriminator, "_xml", {}) + xml_name = prop_meta.get("name", discriminator._rest_name) + xml_ns = prop_meta.get("ns", model_meta.get("ns", None)) + if xml_ns: + xml_name = "{" + xml_ns + "}" + xml_name + + if data.get(xml_name) is not None: + discriminator_value = data.get(xml_name) + else: + discriminator_value = data.find(xml_name).text # pyright: ignore + else: + discriminator_value = data.get(discriminator._rest_name) + mapped_cls = cls.__mapping__.get(discriminator_value, cls) # pyright: ignore # pylint: disable=no-member + return mapped_cls._deserialize(data, exist_discriminators) + + def as_dict(self, *, exclude_readonly: bool = False) -> typing.Dict[str, typing.Any]: + """Return a dict that can be turned into json using json.dump. + + :keyword bool exclude_readonly: Whether to remove the readonly properties. + :returns: A dict JSON compatible object + :rtype: dict + """ + + result = {} + readonly_props = [] + if exclude_readonly: + readonly_props = [p._rest_name for p in self._attr_to_rest_field.values() if _is_readonly(p)] + for k, v in self.items(): + if exclude_readonly and k in readonly_props: # pyright: ignore + continue + is_multipart_file_input = False + try: + is_multipart_file_input = next( + rf for rf in self._attr_to_rest_field.values() if rf._rest_name == k + )._is_multipart_file_input + except StopIteration: + pass + result[k] = v if is_multipart_file_input else Model._as_dict_value(v, exclude_readonly=exclude_readonly) + return result + + @staticmethod + def _as_dict_value(v: typing.Any, exclude_readonly: bool = False) -> typing.Any: + if v is None or isinstance(v, _Null): + return None + if isinstance(v, (list, tuple, set)): + return type(v)(Model._as_dict_value(x, exclude_readonly=exclude_readonly) for x in v) + if isinstance(v, dict): + return {dk: Model._as_dict_value(dv, exclude_readonly=exclude_readonly) for dk, dv in v.items()} + return v.as_dict(exclude_readonly=exclude_readonly) if hasattr(v, "as_dict") else v + + +def _deserialize_model(model_deserializer: typing.Optional[typing.Callable], obj): + if _is_model(obj): + return obj + return _deserialize(model_deserializer, obj) + + +def _deserialize_with_optional(if_obj_deserializer: typing.Optional[typing.Callable], obj): + if obj is None: + return obj + return _deserialize_with_callable(if_obj_deserializer, obj) + + +def _deserialize_with_union(deserializers, obj): + for deserializer in deserializers: + try: + return _deserialize(deserializer, obj) + except DeserializationError: + pass + raise DeserializationError() + + +def _deserialize_dict( + value_deserializer: typing.Optional[typing.Callable], + module: typing.Optional[str], + obj: typing.Dict[typing.Any, typing.Any], +): + if obj is None: + return obj + if isinstance(obj, ET.Element): + obj = {child.tag: child for child in obj} + return {k: _deserialize(value_deserializer, v, module) for k, v in obj.items()} + + +def _deserialize_multiple_sequence( + entry_deserializers: typing.List[typing.Optional[typing.Callable]], + module: typing.Optional[str], + obj, +): + if obj is None: + return obj + return type(obj)(_deserialize(deserializer, entry, module) for entry, deserializer in zip(obj, entry_deserializers)) + + +def _deserialize_sequence( + deserializer: typing.Optional[typing.Callable], + module: typing.Optional[str], + obj, +): + if obj is None: + return obj + if isinstance(obj, ET.Element): + obj = list(obj) + return type(obj)(_deserialize(deserializer, entry, module) for entry in obj) + + +def _sorted_annotations(types: typing.List[typing.Any]) -> typing.List[typing.Any]: + return sorted( + types, + key=lambda x: hasattr(x, "__name__") and x.__name__.lower() in ("str", "float", "int", "bool"), + ) + + +def _get_deserialize_callable_from_annotation( # pylint: disable=too-many-return-statements, too-many-branches + annotation: typing.Any, + module: typing.Optional[str], + rf: typing.Optional["_RestField"] = None, +) -> typing.Optional[typing.Callable[[typing.Any], typing.Any]]: + if not annotation: + return None + + # is it a type alias? + if isinstance(annotation, str): + if module is not None: + annotation = _get_type_alias_type(module, annotation) + + # is it a forward ref / in quotes? + if isinstance(annotation, (str, typing.ForwardRef)): + try: + model_name = annotation.__forward_arg__ # type: ignore + except AttributeError: + model_name = annotation + if module is not None: + annotation = _get_model(module, model_name) # type: ignore + + try: + if module and _is_model(annotation): + if rf: + rf._is_model = True + + return functools.partial(_deserialize_model, annotation) # pyright: ignore + except Exception: + pass + + # is it a literal? + try: + if annotation.__origin__ is typing.Literal: # pyright: ignore + return None + except AttributeError: + pass + + # is it optional? + try: + if any(a for a in annotation.__args__ if a == type(None)): # pyright: ignore + if len(annotation.__args__) <= 2: # pyright: ignore + if_obj_deserializer = _get_deserialize_callable_from_annotation( + next(a for a in annotation.__args__ if a != type(None)), module, rf # pyright: ignore + ) + + return functools.partial(_deserialize_with_optional, if_obj_deserializer) + # the type is Optional[Union[...]], we need to remove the None type from the Union + annotation_copy = copy.copy(annotation) + annotation_copy.__args__ = [a for a in annotation_copy.__args__ if a != type(None)] # pyright: ignore + return _get_deserialize_callable_from_annotation(annotation_copy, module, rf) + except AttributeError: + pass + + # is it union? + if getattr(annotation, "__origin__", None) is typing.Union: + # initial ordering is we make `string` the last deserialization option, because it is often them most generic + deserializers = [ + _get_deserialize_callable_from_annotation(arg, module, rf) + for arg in _sorted_annotations(annotation.__args__) # pyright: ignore + ] + + return functools.partial(_deserialize_with_union, deserializers) + + try: + if annotation._name == "Dict": # pyright: ignore + value_deserializer = _get_deserialize_callable_from_annotation( + annotation.__args__[1], module, rf # pyright: ignore + ) + + return functools.partial( + _deserialize_dict, + value_deserializer, + module, + ) + except (AttributeError, IndexError): + pass + try: + if annotation._name in ["List", "Set", "Tuple", "Sequence"]: # pyright: ignore + if len(annotation.__args__) > 1: # pyright: ignore + entry_deserializers = [ + _get_deserialize_callable_from_annotation(dt, module, rf) + for dt in annotation.__args__ # pyright: ignore + ] + return functools.partial(_deserialize_multiple_sequence, entry_deserializers, module) + deserializer = _get_deserialize_callable_from_annotation( + annotation.__args__[0], module, rf # pyright: ignore + ) + + return functools.partial(_deserialize_sequence, deserializer, module) + except (TypeError, IndexError, AttributeError, SyntaxError): + pass + + def _deserialize_default( + deserializer, + obj, + ): + if obj is None: + return obj + try: + return _deserialize_with_callable(deserializer, obj) + except Exception: + pass + return obj + + if get_deserializer(annotation, rf): + return functools.partial(_deserialize_default, get_deserializer(annotation, rf)) + + return functools.partial(_deserialize_default, annotation) + + +def _deserialize_with_callable( + deserializer: typing.Optional[typing.Callable[[typing.Any], typing.Any]], + value: typing.Any, +): # pylint: disable=too-many-return-statements + try: + if value is None or isinstance(value, _Null): + return None + if isinstance(value, ET.Element): + if deserializer is str: + return value.text or "" + if deserializer is int: + return int(value.text) if value.text else None + if deserializer is float: + return float(value.text) if value.text else None + if deserializer is bool: + return value.text == "true" if value.text else None + if deserializer is None: + return value + if deserializer in [int, float, bool]: + return deserializer(value) + if isinstance(deserializer, CaseInsensitiveEnumMeta): + try: + return deserializer(value) + except ValueError: + # for unknown value, return raw value + return value + if isinstance(deserializer, type) and issubclass(deserializer, Model): + return deserializer._deserialize(value, []) + return typing.cast(typing.Callable[[typing.Any], typing.Any], deserializer)(value) + except Exception as e: + raise DeserializationError() from e + + +def _deserialize( + deserializer: typing.Any, + value: typing.Any, + module: typing.Optional[str] = None, + rf: typing.Optional["_RestField"] = None, + format: typing.Optional[str] = None, +) -> typing.Any: + if isinstance(value, PipelineResponse): + value = value.http_response.json() + if rf is None and format: + rf = _RestField(format=format) + if not isinstance(deserializer, functools.partial): + deserializer = _get_deserialize_callable_from_annotation(deserializer, module, rf) + 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 DeserializationError: + _LOGGER.warning( + "Ran into a deserialization error. Ignoring since this is failsafe deserialization", exc_info=True + ) + return None + + +def _failsafe_deserialize_xml( + deserializer: typing.Any, + value: typing.Any, +) -> typing.Any: + try: + return _deserialize_xml(deserializer, value) + except DeserializationError: + _LOGGER.warning( + "Ran into a deserialization error. Ignoring since this is failsafe deserialization", exc_info=True + ) + return None + + +class _RestField: + def __init__( + self, + *, + name: typing.Optional[str] = None, + type: typing.Optional[typing.Callable] = None, # pylint: disable=redefined-builtin + is_discriminator: bool = False, + visibility: typing.Optional[typing.List[str]] = None, + default: typing.Any = _UNSET, + format: typing.Optional[str] = None, + is_multipart_file_input: bool = False, + xml: typing.Optional[typing.Dict[str, typing.Any]] = None, + ): + self._type = type + self._rest_name_input = name + self._module: typing.Optional[str] = None + self._is_discriminator = is_discriminator + self._visibility = visibility + self._is_model = False + self._default = default + self._format = format + self._is_multipart_file_input = is_multipart_file_input + self._xml = xml if xml is not None else {} + + @property + def _class_type(self) -> typing.Any: + return getattr(self._type, "args", [None])[0] + + @property + def _rest_name(self) -> str: + if self._rest_name_input is None: + raise ValueError("Rest name was never set") + return self._rest_name_input + + def __get__(self, obj: Model, type=None): # pylint: disable=redefined-builtin + # by this point, type and rest_name will have a value bc we default + # them in __new__ of the Model class + item = obj.get(self._rest_name) + if item is None: + return item + if self._is_model: + return item + return _deserialize(self._type, _serialize(item, self._format), rf=self) + + def __set__(self, obj: Model, value) -> None: + if value is None: + # we want to wipe out entries if users set attr to None + try: + obj.__delitem__(self._rest_name) + except KeyError: + pass + return + if self._is_model: + if not _is_model(value): + value = _deserialize(self._type, value) + obj.__setitem__(self._rest_name, value) + return + obj.__setitem__(self._rest_name, _serialize(value, self._format)) + + def _get_deserialize_callable_from_annotation( + self, annotation: typing.Any + ) -> typing.Optional[typing.Callable[[typing.Any], typing.Any]]: + return _get_deserialize_callable_from_annotation(annotation, self._module, self) + + +def rest_field( + *, + name: typing.Optional[str] = None, + type: typing.Optional[typing.Callable] = None, # pylint: disable=redefined-builtin + visibility: typing.Optional[typing.List[str]] = None, + default: typing.Any = _UNSET, + format: typing.Optional[str] = None, + is_multipart_file_input: bool = False, + xml: typing.Optional[typing.Dict[str, typing.Any]] = None, +) -> typing.Any: + return _RestField( + name=name, + type=type, + visibility=visibility, + default=default, + format=format, + is_multipart_file_input=is_multipart_file_input, + xml=xml, + ) + + +def rest_discriminator( + *, + name: typing.Optional[str] = None, + type: typing.Optional[typing.Callable] = None, # pylint: disable=redefined-builtin + visibility: typing.Optional[typing.List[str]] = None, + xml: typing.Optional[typing.Dict[str, typing.Any]] = None, +) -> typing.Any: + return _RestField(name=name, type=type, is_discriminator=True, visibility=visibility, xml=xml) + + +def serialize_xml(model: Model, exclude_readonly: bool = False) -> str: + """Serialize a model to XML. + + :param Model model: The model to serialize. + :param bool exclude_readonly: Whether to exclude readonly properties. + :returns: The XML representation of the model. + :rtype: str + """ + return ET.tostring(_get_element(model, exclude_readonly), encoding="unicode") # type: ignore + + +def _get_element( + o: typing.Any, + exclude_readonly: bool = False, + parent_meta: typing.Optional[typing.Dict[str, typing.Any]] = None, + wrapped_element: typing.Optional[ET.Element] = None, +) -> typing.Union[ET.Element, typing.List[ET.Element]]: + if _is_model(o): + model_meta = getattr(o, "_xml", {}) + + # if prop is a model, then use the prop element directly, else generate a wrapper of model + if wrapped_element is None: + wrapped_element = _create_xml_element( + model_meta.get("name", o.__class__.__name__), + model_meta.get("prefix"), + model_meta.get("ns"), + ) + + readonly_props = [] + if exclude_readonly: + readonly_props = [p._rest_name for p in o._attr_to_rest_field.values() if _is_readonly(p)] + + for k, v in o.items(): + # do not serialize readonly properties + if exclude_readonly and k in readonly_props: + continue + + prop_rest_field = _get_rest_field(o._attr_to_rest_field, k) + if prop_rest_field: + prop_meta = getattr(prop_rest_field, "_xml").copy() + # use the wire name as xml name if no specific name is set + if prop_meta.get("name") is None: + prop_meta["name"] = k + else: + # additional properties will not have rest field, use the wire name as xml name + prop_meta = {"name": k} + + # if no ns for prop, use model's + if prop_meta.get("ns") is None and model_meta.get("ns"): + prop_meta["ns"] = model_meta.get("ns") + prop_meta["prefix"] = model_meta.get("prefix") + + if prop_meta.get("unwrapped", False): + # unwrapped could only set on array + wrapped_element.extend(_get_element(v, exclude_readonly, prop_meta)) + elif prop_meta.get("text", False): + # text could only set on primitive type + wrapped_element.text = _get_primitive_type_value(v) + elif prop_meta.get("attribute", False): + xml_name = prop_meta.get("name", k) + if prop_meta.get("ns"): + ET.register_namespace(prop_meta.get("prefix"), prop_meta.get("ns")) # pyright: ignore + xml_name = "{" + prop_meta.get("ns") + "}" + xml_name # pyright: ignore + # attribute should be primitive type + wrapped_element.set(xml_name, _get_primitive_type_value(v)) + else: + # other wrapped prop element + wrapped_element.append(_get_wrapped_element(v, exclude_readonly, prop_meta)) + return wrapped_element + if isinstance(o, list): + return [_get_element(x, exclude_readonly, parent_meta) for x in o] # type: ignore + if isinstance(o, dict): + result = [] + for k, v in o.items(): + result.append( + _get_wrapped_element( + v, + exclude_readonly, + { + "name": k, + "ns": parent_meta.get("ns") if parent_meta else None, + "prefix": parent_meta.get("prefix") if parent_meta else None, + }, + ) + ) + return result + + # primitive case need to create element based on parent_meta + if parent_meta: + return _get_wrapped_element( + o, + exclude_readonly, + { + "name": parent_meta.get("itemsName", parent_meta.get("name")), + "prefix": parent_meta.get("itemsPrefix", parent_meta.get("prefix")), + "ns": parent_meta.get("itemsNs", parent_meta.get("ns")), + }, + ) + + raise ValueError("Could not serialize value into xml: " + o) + + +def _get_wrapped_element( + v: typing.Any, + exclude_readonly: bool, + meta: typing.Optional[typing.Dict[str, typing.Any]], +) -> ET.Element: + wrapped_element = _create_xml_element( + meta.get("name") if meta else None, meta.get("prefix") if meta else None, meta.get("ns") if meta else None + ) + if isinstance(v, (dict, list)): + wrapped_element.extend(_get_element(v, exclude_readonly, meta)) + elif _is_model(v): + _get_element(v, exclude_readonly, meta, wrapped_element) + else: + wrapped_element.text = _get_primitive_type_value(v) + return wrapped_element + + +def _get_primitive_type_value(v) -> str: + if v is True: + return "true" + if v is False: + return "false" + if isinstance(v, _Null): + return "" + return str(v) + + +def _create_xml_element(tag, prefix=None, ns=None): + if prefix and ns: + ET.register_namespace(prefix, ns) + if ns: + return ET.Element("{" + ns + "}" + tag) + return ET.Element(tag) + + +def _deserialize_xml( + deserializer: typing.Any, + value: str, +) -> typing.Any: + element = ET.fromstring(value) # nosec + return _deserialize(deserializer, element) + + +def _convert_element(e: ET.Element): + # dict case + if len(e.attrib) > 0 or len({child.tag for child in e}) > 1: + dict_result: typing.Dict[str, typing.Any] = {} + for child in e: + if dict_result.get(child.tag) is not None: + if isinstance(dict_result[child.tag], list): + dict_result[child.tag].append(_convert_element(child)) + else: + dict_result[child.tag] = [dict_result[child.tag], _convert_element(child)] + else: + dict_result[child.tag] = _convert_element(child) + dict_result.update(e.attrib) + return dict_result + # array case + if len(e) > 0: + array_result: typing.List[typing.Any] = [] + for child in e: + array_result.append(_convert_element(child)) + return array_result + # primitive case + return e.text diff --git a/packages/typespec-python/test/azure/generated/versioning-typechangedfrom/versioning/typechangedfrom/_utils/serialization.py b/packages/typespec-python/test/azure/generated/versioning-typechangedfrom/versioning/typechangedfrom/_utils/serialization.py new file mode 100644 index 00000000000..eb86ea23c96 --- /dev/null +++ b/packages/typespec-python/test/azure/generated/versioning-typechangedfrom/versioning/typechangedfrom/_utils/serialization.py @@ -0,0 +1,2032 @@ +# pylint: disable=line-too-long,useless-suppression,too-many-lines +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) Python Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +# pyright: reportUnnecessaryTypeIgnoreComment=false + +from base64 import b64decode, b64encode +import calendar +import datetime +import decimal +import email +from enum import Enum +import json +import logging +import re +import sys +import codecs +from typing import ( + Dict, + Any, + cast, + Optional, + Union, + AnyStr, + IO, + Mapping, + Callable, + MutableMapping, + List, +) + +try: + from urllib import quote # type: ignore +except ImportError: + from urllib.parse import quote +import xml.etree.ElementTree as ET + +import isodate # type: ignore +from typing_extensions import Self + +from azure.core.exceptions import DeserializationError, SerializationError +from azure.core.serialization import NULL as CoreNull + +_BOM = codecs.BOM_UTF8.decode(encoding="utf-8") + +JSON = MutableMapping[str, Any] + + +class RawDeserializer: + + # Accept "text" because we're open minded people... + JSON_REGEXP = re.compile(r"^(application|text)/([a-z+.]+\+)?json$") + + # Name used in context + CONTEXT_NAME = "deserialized_data" + + @classmethod + def deserialize_from_text(cls, data: Optional[Union[AnyStr, IO]], content_type: Optional[str] = None) -> Any: + """Decode data according to content-type. + + Accept a stream of data as well, but will be load at once in memory for now. + + If no content-type, will return the string version (not bytes, not stream) + + :param data: Input, could be bytes or stream (will be decoded with UTF8) or text + :type data: str or bytes or IO + :param str content_type: The content type. + :return: The deserialized data. + :rtype: object + """ + if hasattr(data, "read"): + # Assume a stream + data = cast(IO, data).read() + + if isinstance(data, bytes): + data_as_str = data.decode(encoding="utf-8-sig") + else: + # Explain to mypy the correct type. + data_as_str = cast(str, data) + + # Remove Byte Order Mark if present in string + data_as_str = data_as_str.lstrip(_BOM) + + if content_type is None: + return data + + if cls.JSON_REGEXP.match(content_type): + try: + return json.loads(data_as_str) + except ValueError as err: + raise DeserializationError("JSON is invalid: {}".format(err), err) from err + elif "xml" in (content_type or []): + try: + + try: + if isinstance(data, unicode): # type: ignore + # If I'm Python 2.7 and unicode XML will scream if I try a "fromstring" on unicode string + data_as_str = data_as_str.encode(encoding="utf-8") # type: ignore + except NameError: + pass + + return ET.fromstring(data_as_str) # nosec + except ET.ParseError as err: + # It might be because the server has an issue, and returned JSON with + # content-type XML.... + # So let's try a JSON load, and if it's still broken + # let's flow the initial exception + def _json_attemp(data): + try: + return True, json.loads(data) + except ValueError: + return False, None # Don't care about this one + + success, json_result = _json_attemp(data) + if success: + return json_result + # If i'm here, it's not JSON, it's not XML, let's scream + # and raise the last context in this block (the XML exception) + # The function hack is because Py2.7 messes up with exception + # context otherwise. + _LOGGER.critical("Wasn't XML not JSON, failing") + raise DeserializationError("XML is invalid") from err + elif content_type.startswith("text/"): + return data_as_str + raise DeserializationError("Cannot deserialize content-type: {}".format(content_type)) + + @classmethod + def deserialize_from_http_generics(cls, body_bytes: Optional[Union[AnyStr, IO]], headers: Mapping) -> Any: + """Deserialize from HTTP response. + + Use bytes and headers to NOT use any requests/aiohttp or whatever + specific implementation. + Headers will tested for "content-type" + + :param bytes body_bytes: The body of the response. + :param dict headers: The headers of the response. + :returns: The deserialized data. + :rtype: object + """ + # Try to use content-type from headers if available + content_type = None + if "content-type" in headers: + content_type = headers["content-type"].split(";")[0].strip().lower() + # Ouch, this server did not declare what it sent... + # Let's guess it's JSON... + # Also, since Autorest was considering that an empty body was a valid JSON, + # need that test as well.... + else: + content_type = "application/json" + + if body_bytes: + return cls.deserialize_from_text(body_bytes, content_type) + return None + + +_LOGGER = logging.getLogger(__name__) + +try: + _long_type = long # type: ignore +except NameError: + _long_type = int + +TZ_UTC = datetime.timezone.utc + +_FLATTEN = re.compile(r"(? None: + self.additional_properties: Optional[Dict[str, Any]] = {} + for k in kwargs: # pylint: disable=consider-using-dict-items + if k not in self._attribute_map: + _LOGGER.warning("%s is not a known attribute of class %s and will be ignored", k, self.__class__) + elif k in self._validation and self._validation[k].get("readonly", False): + _LOGGER.warning("Readonly attribute %s will be ignored in class %s", k, self.__class__) + else: + setattr(self, k, kwargs[k]) + + def __eq__(self, other: Any) -> bool: + """Compare objects by comparing all attributes. + + :param object other: The object to compare + :returns: True if objects are equal + :rtype: bool + """ + if isinstance(other, self.__class__): + return self.__dict__ == other.__dict__ + return False + + def __ne__(self, other: Any) -> bool: + """Compare objects by comparing all attributes. + + :param object other: The object to compare + :returns: True if objects are not equal + :rtype: bool + """ + return not self.__eq__(other) + + def __str__(self) -> str: + return str(self.__dict__) + + @classmethod + def enable_additional_properties_sending(cls) -> None: + cls._attribute_map["additional_properties"] = {"key": "", "type": "{object}"} + + @classmethod + def is_xml_model(cls) -> bool: + try: + cls._xml_map # type: ignore + except AttributeError: + return False + return True + + @classmethod + def _create_xml_node(cls): + """Create XML node. + + :returns: The XML node + :rtype: xml.etree.ElementTree.Element + """ + try: + xml_map = cls._xml_map # type: ignore + except AttributeError: + xml_map = {} + + return _create_xml_node(xml_map.get("name", cls.__name__), xml_map.get("prefix", None), xml_map.get("ns", None)) + + def serialize(self, keep_readonly: bool = False, **kwargs: Any) -> JSON: + """Return the JSON that would be sent to server from this model. + + This is an alias to `as_dict(full_restapi_key_transformer, keep_readonly=False)`. + + If you want XML serialization, you can pass the kwargs is_xml=True. + + :param bool keep_readonly: If you want to serialize the readonly attributes + :returns: A dict JSON compatible object + :rtype: dict + """ + serializer = Serializer(self._infer_class_models()) + return serializer._serialize( # type: ignore # pylint: disable=protected-access + self, keep_readonly=keep_readonly, **kwargs + ) + + def as_dict( + self, + keep_readonly: bool = True, + key_transformer: Callable[[str, Dict[str, Any], Any], Any] = attribute_transformer, + **kwargs: Any + ) -> JSON: + """Return a dict that can be serialized using json.dump. + + Advanced usage might optionally use a callback as parameter: + + .. code::python + + def my_key_transformer(key, attr_desc, value): + return key + + Key is the attribute name used in Python. Attr_desc + is a dict of metadata. Currently contains 'type' with the + msrest type and 'key' with the RestAPI encoded key. + Value is the current value in this object. + + The string returned will be used to serialize the key. + If the return type is a list, this is considered hierarchical + result dict. + + See the three examples in this file: + + - attribute_transformer + - full_restapi_key_transformer + - last_restapi_key_transformer + + If you want XML serialization, you can pass the kwargs is_xml=True. + + :param bool keep_readonly: If you want to serialize the readonly attributes + :param function key_transformer: A key transformer function. + :returns: A dict JSON compatible object + :rtype: dict + """ + serializer = Serializer(self._infer_class_models()) + return serializer._serialize( # type: ignore # pylint: disable=protected-access + self, key_transformer=key_transformer, keep_readonly=keep_readonly, **kwargs + ) + + @classmethod + def _infer_class_models(cls): + try: + str_models = cls.__module__.rsplit(".", 1)[0] + models = sys.modules[str_models] + client_models = {k: v for k, v in models.__dict__.items() if isinstance(v, type)} + if cls.__name__ not in client_models: + raise ValueError("Not Autorest generated code") + except Exception: # pylint: disable=broad-exception-caught + # Assume it's not Autorest generated (tests?). Add ourselves as dependencies. + client_models = {cls.__name__: cls} + return client_models + + @classmethod + def deserialize(cls, data: Any, content_type: Optional[str] = None) -> Self: + """Parse a str using the RestAPI syntax and return a model. + + :param str data: A str using RestAPI structure. JSON by default. + :param str content_type: JSON by default, set application/xml if XML. + :returns: An instance of this model + :raises DeserializationError: if something went wrong + :rtype: Self + """ + deserializer = Deserializer(cls._infer_class_models()) + return deserializer(cls.__name__, data, content_type=content_type) # type: ignore + + @classmethod + def from_dict( + cls, + data: Any, + key_extractors: Optional[Callable[[str, Dict[str, Any], Any], Any]] = None, + content_type: Optional[str] = None, + ) -> Self: + """Parse a dict using given key extractor return a model. + + By default consider key + extractors (rest_key_case_insensitive_extractor, attribute_key_case_insensitive_extractor + and last_rest_key_case_insensitive_extractor) + + :param dict data: A dict using RestAPI structure + :param function key_extractors: A key extractor function. + :param str content_type: JSON by default, set application/xml if XML. + :returns: An instance of this model + :raises DeserializationError: if something went wrong + :rtype: Self + """ + deserializer = Deserializer(cls._infer_class_models()) + deserializer.key_extractors = ( # type: ignore + [ # type: ignore + attribute_key_case_insensitive_extractor, + rest_key_case_insensitive_extractor, + last_rest_key_case_insensitive_extractor, + ] + if key_extractors is None + else key_extractors + ) + return deserializer(cls.__name__, data, content_type=content_type) # type: ignore + + @classmethod + def _flatten_subtype(cls, key, objects): + if "_subtype_map" not in cls.__dict__: + return {} + result = dict(cls._subtype_map[key]) + for valuetype in cls._subtype_map[key].values(): + result.update(objects[valuetype]._flatten_subtype(key, objects)) # pylint: disable=protected-access + return result + + @classmethod + def _classify(cls, response, objects): + """Check the class _subtype_map for any child classes. + We want to ignore any inherited _subtype_maps. + + :param dict response: The initial data + :param dict objects: The class objects + :returns: The class to be used + :rtype: class + """ + for subtype_key in cls.__dict__.get("_subtype_map", {}).keys(): + subtype_value = None + + if not isinstance(response, ET.Element): + rest_api_response_key = cls._get_rest_key_parts(subtype_key)[-1] + subtype_value = response.get(rest_api_response_key, None) or response.get(subtype_key, None) + else: + subtype_value = xml_key_extractor(subtype_key, cls._attribute_map[subtype_key], response) + if subtype_value: + # Try to match base class. Can be class name only + # (bug to fix in Autorest to support x-ms-discriminator-name) + if cls.__name__ == subtype_value: + return cls + flatten_mapping_type = cls._flatten_subtype(subtype_key, objects) + try: + return objects[flatten_mapping_type[subtype_value]] # type: ignore + except KeyError: + _LOGGER.warning( + "Subtype value %s has no mapping, use base class %s.", + subtype_value, + cls.__name__, + ) + break + else: + _LOGGER.warning("Discriminator %s is absent or null, use base class %s.", subtype_key, cls.__name__) + break + return cls + + @classmethod + def _get_rest_key_parts(cls, attr_key): + """Get the RestAPI key of this attr, split it and decode part + :param str attr_key: Attribute key must be in attribute_map. + :returns: A list of RestAPI part + :rtype: list + """ + rest_split_key = _FLATTEN.split(cls._attribute_map[attr_key]["key"]) + return [_decode_attribute_map_key(key_part) for key_part in rest_split_key] + + +def _decode_attribute_map_key(key): + """This decode a key in an _attribute_map to the actual key we want to look at + inside the received data. + + :param str key: A key string from the generated code + :returns: The decoded key + :rtype: str + """ + return key.replace("\\.", ".") + + +class Serializer: # pylint: disable=too-many-public-methods + """Request object model serializer.""" + + basic_types = {str: "str", int: "int", bool: "bool", float: "float"} + + _xml_basic_types_serializers = {"bool": lambda x: str(x).lower()} + days = {0: "Mon", 1: "Tue", 2: "Wed", 3: "Thu", 4: "Fri", 5: "Sat", 6: "Sun"} + months = { + 1: "Jan", + 2: "Feb", + 3: "Mar", + 4: "Apr", + 5: "May", + 6: "Jun", + 7: "Jul", + 8: "Aug", + 9: "Sep", + 10: "Oct", + 11: "Nov", + 12: "Dec", + } + validation = { + "min_length": lambda x, y: len(x) < y, + "max_length": lambda x, y: len(x) > y, + "minimum": lambda x, y: x < y, + "maximum": lambda x, y: x > y, + "minimum_ex": lambda x, y: x <= y, + "maximum_ex": lambda x, y: x >= y, + "min_items": lambda x, y: len(x) < y, + "max_items": lambda x, y: len(x) > y, + "pattern": lambda x, y: not re.match(y, x, re.UNICODE), + "unique": lambda x, y: len(x) != len(set(x)), + "multiple": lambda x, y: x % y != 0, + } + + def __init__(self, classes: Optional[Mapping[str, type]] = None) -> None: + self.serialize_type = { + "iso-8601": Serializer.serialize_iso, + "rfc-1123": Serializer.serialize_rfc, + "unix-time": Serializer.serialize_unix, + "duration": Serializer.serialize_duration, + "date": Serializer.serialize_date, + "time": Serializer.serialize_time, + "decimal": Serializer.serialize_decimal, + "long": Serializer.serialize_long, + "bytearray": Serializer.serialize_bytearray, + "base64": Serializer.serialize_base64, + "object": self.serialize_object, + "[]": self.serialize_iter, + "{}": self.serialize_dict, + } + self.dependencies: Dict[str, type] = dict(classes) if classes else {} + self.key_transformer = full_restapi_key_transformer + self.client_side_validation = True + + def _serialize( # pylint: disable=too-many-nested-blocks, too-many-branches, too-many-statements, too-many-locals + self, target_obj, data_type=None, **kwargs + ): + """Serialize data into a string according to type. + + :param object target_obj: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str, dict + :raises SerializationError: if serialization fails. + :returns: The serialized data. + """ + key_transformer = kwargs.get("key_transformer", self.key_transformer) + keep_readonly = kwargs.get("keep_readonly", False) + if target_obj is None: + return None + + attr_name = None + class_name = target_obj.__class__.__name__ + + if data_type: + return self.serialize_data(target_obj, data_type, **kwargs) + + if not hasattr(target_obj, "_attribute_map"): + data_type = type(target_obj).__name__ + if data_type in self.basic_types.values(): + return self.serialize_data(target_obj, data_type, **kwargs) + + # Force "is_xml" kwargs if we detect a XML model + try: + is_xml_model_serialization = kwargs["is_xml"] + except KeyError: + is_xml_model_serialization = kwargs.setdefault("is_xml", target_obj.is_xml_model()) + + serialized = {} + if is_xml_model_serialization: + serialized = target_obj._create_xml_node() # pylint: disable=protected-access + try: + attributes = target_obj._attribute_map # pylint: disable=protected-access + for attr, attr_desc in attributes.items(): + attr_name = attr + if not keep_readonly and target_obj._validation.get( # pylint: disable=protected-access + attr_name, {} + ).get("readonly", False): + continue + + if attr_name == "additional_properties" and attr_desc["key"] == "": + if target_obj.additional_properties is not None: + serialized.update(target_obj.additional_properties) + continue + try: + + orig_attr = getattr(target_obj, attr) + if is_xml_model_serialization: + pass # Don't provide "transformer" for XML for now. Keep "orig_attr" + else: # JSON + keys, orig_attr = key_transformer(attr, attr_desc.copy(), orig_attr) + keys = keys if isinstance(keys, list) else [keys] + + kwargs["serialization_ctxt"] = attr_desc + new_attr = self.serialize_data(orig_attr, attr_desc["type"], **kwargs) + + if is_xml_model_serialization: + xml_desc = attr_desc.get("xml", {}) + xml_name = xml_desc.get("name", attr_desc["key"]) + xml_prefix = xml_desc.get("prefix", None) + xml_ns = xml_desc.get("ns", None) + if xml_desc.get("attr", False): + if xml_ns: + ET.register_namespace(xml_prefix, xml_ns) + xml_name = "{{{}}}{}".format(xml_ns, xml_name) + serialized.set(xml_name, new_attr) # type: ignore + continue + if xml_desc.get("text", False): + serialized.text = new_attr # type: ignore + continue + if isinstance(new_attr, list): + serialized.extend(new_attr) # type: ignore + elif isinstance(new_attr, ET.Element): + # If the down XML has no XML/Name, + # we MUST replace the tag with the local tag. But keeping the namespaces. + if "name" not in getattr(orig_attr, "_xml_map", {}): + splitted_tag = new_attr.tag.split("}") + if len(splitted_tag) == 2: # Namespace + new_attr.tag = "}".join([splitted_tag[0], xml_name]) + else: + new_attr.tag = xml_name + serialized.append(new_attr) # type: ignore + else: # That's a basic type + # Integrate namespace if necessary + local_node = _create_xml_node(xml_name, xml_prefix, xml_ns) + local_node.text = str(new_attr) + serialized.append(local_node) # type: ignore + else: # JSON + for k in reversed(keys): # type: ignore + new_attr = {k: new_attr} + + _new_attr = new_attr + _serialized = serialized + for k in keys: # type: ignore + if k not in _serialized: + _serialized.update(_new_attr) # type: ignore + _new_attr = _new_attr[k] # type: ignore + _serialized = _serialized[k] + except ValueError as err: + if isinstance(err, SerializationError): + raise + + except (AttributeError, KeyError, TypeError) as err: + msg = "Attribute {} in object {} cannot be serialized.\n{}".format(attr_name, class_name, str(target_obj)) + raise SerializationError(msg) from err + return serialized + + def body(self, data, data_type, **kwargs): + """Serialize data intended for a request body. + + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: dict + :raises SerializationError: if serialization fails. + :raises ValueError: if data is None + :returns: The serialized request body + """ + + # Just in case this is a dict + internal_data_type_str = data_type.strip("[]{}") + internal_data_type = self.dependencies.get(internal_data_type_str, None) + try: + is_xml_model_serialization = kwargs["is_xml"] + except KeyError: + if internal_data_type and issubclass(internal_data_type, Model): + is_xml_model_serialization = kwargs.setdefault("is_xml", internal_data_type.is_xml_model()) + else: + is_xml_model_serialization = False + if internal_data_type and not isinstance(internal_data_type, Enum): + try: + deserializer = Deserializer(self.dependencies) + # Since it's on serialization, it's almost sure that format is not JSON REST + # We're not able to deal with additional properties for now. + deserializer.additional_properties_detection = False + if is_xml_model_serialization: + deserializer.key_extractors = [ # type: ignore + attribute_key_case_insensitive_extractor, + ] + else: + deserializer.key_extractors = [ + rest_key_case_insensitive_extractor, + attribute_key_case_insensitive_extractor, + last_rest_key_case_insensitive_extractor, + ] + data = deserializer._deserialize(data_type, data) # pylint: disable=protected-access + except DeserializationError as err: + raise SerializationError("Unable to build a model: " + str(err)) from err + + return self._serialize(data, data_type, **kwargs) + + def url(self, name, data, data_type, **kwargs): + """Serialize data intended for a URL path. + + :param str name: The name of the URL path parameter. + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str + :returns: The serialized URL path + :raises TypeError: if serialization fails. + :raises ValueError: if data is None + """ + try: + output = self.serialize_data(data, data_type, **kwargs) + if data_type == "bool": + output = json.dumps(output) + + if kwargs.get("skip_quote") is True: + output = str(output) + output = output.replace("{", quote("{")).replace("}", quote("}")) + else: + output = quote(str(output), safe="") + except SerializationError as exc: + raise TypeError("{} must be type {}.".format(name, data_type)) from exc + return output + + def query(self, name, data, data_type, **kwargs): + """Serialize data intended for a URL query. + + :param str name: The name of the query parameter. + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str, list + :raises TypeError: if serialization fails. + :raises ValueError: if data is None + :returns: The serialized query parameter + """ + try: + # Treat the list aside, since we don't want to encode the div separator + if data_type.startswith("["): + internal_data_type = data_type[1:-1] + do_quote = not kwargs.get("skip_quote", False) + return self.serialize_iter(data, internal_data_type, do_quote=do_quote, **kwargs) + + # Not a list, regular serialization + output = self.serialize_data(data, data_type, **kwargs) + if data_type == "bool": + output = json.dumps(output) + if kwargs.get("skip_quote") is True: + output = str(output) + else: + output = quote(str(output), safe="") + except SerializationError as exc: + raise TypeError("{} must be type {}.".format(name, data_type)) from exc + return str(output) + + def header(self, name, data, data_type, **kwargs): + """Serialize data intended for a request header. + + :param str name: The name of the header. + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str + :raises TypeError: if serialization fails. + :raises ValueError: if data is None + :returns: The serialized header + """ + try: + if data_type in ["[str]"]: + data = ["" if d is None else d for d in data] + + output = self.serialize_data(data, data_type, **kwargs) + if data_type == "bool": + output = json.dumps(output) + except SerializationError as exc: + raise TypeError("{} must be type {}.".format(name, data_type)) from exc + return str(output) + + def serialize_data(self, data, data_type, **kwargs): + """Serialize generic data according to supplied data type. + + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :raises AttributeError: if required data is None. + :raises ValueError: if data is None + :raises SerializationError: if serialization fails. + :returns: The serialized data. + :rtype: str, int, float, bool, dict, list + """ + if data is None: + raise ValueError("No value for given attribute") + + try: + if data is CoreNull: + return None + if data_type in self.basic_types.values(): + return self.serialize_basic(data, data_type, **kwargs) + + if data_type in self.serialize_type: + return self.serialize_type[data_type](data, **kwargs) + + # If dependencies is empty, try with current data class + # It has to be a subclass of Enum anyway + enum_type = self.dependencies.get(data_type, data.__class__) + if issubclass(enum_type, Enum): + return Serializer.serialize_enum(data, enum_obj=enum_type) + + iter_type = data_type[0] + data_type[-1] + if iter_type in self.serialize_type: + return self.serialize_type[iter_type](data, data_type[1:-1], **kwargs) + + except (ValueError, TypeError) as err: + msg = "Unable to serialize value: {!r} as type: {!r}." + raise SerializationError(msg.format(data, data_type)) from err + return self._serialize(data, **kwargs) + + @classmethod + def _get_custom_serializers(cls, data_type, **kwargs): # pylint: disable=inconsistent-return-statements + custom_serializer = kwargs.get("basic_types_serializers", {}).get(data_type) + if custom_serializer: + return custom_serializer + if kwargs.get("is_xml", False): + return cls._xml_basic_types_serializers.get(data_type) + + @classmethod + def serialize_basic(cls, data, data_type, **kwargs): + """Serialize basic builting data type. + Serializes objects to str, int, float or bool. + + Possible kwargs: + - basic_types_serializers dict[str, callable] : If set, use the callable as serializer + - is_xml bool : If set, use xml_basic_types_serializers + + :param obj data: Object to be serialized. + :param str data_type: Type of object in the iterable. + :rtype: str, int, float, bool + :return: serialized object + """ + custom_serializer = cls._get_custom_serializers(data_type, **kwargs) + if custom_serializer: + return custom_serializer(data) + if data_type == "str": + return cls.serialize_unicode(data) + return eval(data_type)(data) # nosec # pylint: disable=eval-used + + @classmethod + def serialize_unicode(cls, data): + """Special handling for serializing unicode strings in Py2. + Encode to UTF-8 if unicode, otherwise handle as a str. + + :param str data: Object to be serialized. + :rtype: str + :return: serialized object + """ + try: # If I received an enum, return its value + return data.value + except AttributeError: + pass + + try: + if isinstance(data, unicode): # type: ignore + # Don't change it, JSON and XML ElementTree are totally able + # to serialize correctly u'' strings + return data + except NameError: + return str(data) + return str(data) + + def serialize_iter(self, data, iter_type, div=None, **kwargs): + """Serialize iterable. + + Supported kwargs: + - serialization_ctxt dict : The current entry of _attribute_map, or same format. + serialization_ctxt['type'] should be same as data_type. + - is_xml bool : If set, serialize as XML + + :param list data: Object to be serialized. + :param str iter_type: Type of object in the iterable. + :param str div: If set, this str will be used to combine the elements + in the iterable into a combined string. Default is 'None'. + Defaults to False. + :rtype: list, str + :return: serialized iterable + """ + if isinstance(data, str): + raise SerializationError("Refuse str type as a valid iter type.") + + serialization_ctxt = kwargs.get("serialization_ctxt", {}) + is_xml = kwargs.get("is_xml", False) + + serialized = [] + for d in data: + try: + serialized.append(self.serialize_data(d, iter_type, **kwargs)) + except ValueError as err: + if isinstance(err, SerializationError): + raise + serialized.append(None) + + if kwargs.get("do_quote", False): + serialized = ["" if s is None else quote(str(s), safe="") for s in serialized] + + if div: + serialized = ["" if s is None else str(s) for s in serialized] + serialized = div.join(serialized) + + if "xml" in serialization_ctxt or is_xml: + # XML serialization is more complicated + xml_desc = serialization_ctxt.get("xml", {}) + xml_name = xml_desc.get("name") + if not xml_name: + xml_name = serialization_ctxt["key"] + + # Create a wrap node if necessary (use the fact that Element and list have "append") + is_wrapped = xml_desc.get("wrapped", False) + node_name = xml_desc.get("itemsName", xml_name) + if is_wrapped: + final_result = _create_xml_node(xml_name, xml_desc.get("prefix", None), xml_desc.get("ns", None)) + else: + final_result = [] + # All list elements to "local_node" + for el in serialized: + if isinstance(el, ET.Element): + el_node = el + else: + el_node = _create_xml_node(node_name, xml_desc.get("prefix", None), xml_desc.get("ns", None)) + if el is not None: # Otherwise it writes "None" :-p + el_node.text = str(el) + final_result.append(el_node) + return final_result + return serialized + + def serialize_dict(self, attr, dict_type, **kwargs): + """Serialize a dictionary of objects. + + :param dict attr: Object to be serialized. + :param str dict_type: Type of object in the dictionary. + :rtype: dict + :return: serialized dictionary + """ + serialization_ctxt = kwargs.get("serialization_ctxt", {}) + serialized = {} + for key, value in attr.items(): + try: + serialized[self.serialize_unicode(key)] = self.serialize_data(value, dict_type, **kwargs) + except ValueError as err: + if isinstance(err, SerializationError): + raise + serialized[self.serialize_unicode(key)] = None + + if "xml" in serialization_ctxt: + # XML serialization is more complicated + xml_desc = serialization_ctxt["xml"] + xml_name = xml_desc["name"] + + final_result = _create_xml_node(xml_name, xml_desc.get("prefix", None), xml_desc.get("ns", None)) + for key, value in serialized.items(): + ET.SubElement(final_result, key).text = value + return final_result + + return serialized + + def serialize_object(self, attr, **kwargs): # pylint: disable=too-many-return-statements + """Serialize a generic object. + This will be handled as a dictionary. If object passed in is not + a basic type (str, int, float, dict, list) it will simply be + cast to str. + + :param dict attr: Object to be serialized. + :rtype: dict or str + :return: serialized object + """ + if attr is None: + return None + if isinstance(attr, ET.Element): + return attr + obj_type = type(attr) + if obj_type in self.basic_types: + return self.serialize_basic(attr, self.basic_types[obj_type], **kwargs) + if obj_type is _long_type: + return self.serialize_long(attr) + if obj_type is str: + return self.serialize_unicode(attr) + if obj_type is datetime.datetime: + return self.serialize_iso(attr) + if obj_type is datetime.date: + return self.serialize_date(attr) + if obj_type is datetime.time: + return self.serialize_time(attr) + if obj_type is datetime.timedelta: + return self.serialize_duration(attr) + if obj_type is decimal.Decimal: + return self.serialize_decimal(attr) + + # If it's a model or I know this dependency, serialize as a Model + if obj_type in self.dependencies.values() or isinstance(attr, Model): + return self._serialize(attr) + + if obj_type == dict: + serialized = {} + for key, value in attr.items(): + try: + serialized[self.serialize_unicode(key)] = self.serialize_object(value, **kwargs) + except ValueError: + serialized[self.serialize_unicode(key)] = None + return serialized + + if obj_type == list: + serialized = [] + for obj in attr: + try: + serialized.append(self.serialize_object(obj, **kwargs)) + except ValueError: + pass + return serialized + return str(attr) + + @staticmethod + def serialize_enum(attr, enum_obj=None): + try: + result = attr.value + except AttributeError: + result = attr + try: + enum_obj(result) # type: ignore + return result + except ValueError as exc: + for enum_value in enum_obj: # type: ignore + if enum_value.value.lower() == str(attr).lower(): + return enum_value.value + error = "{!r} is not valid value for enum {!r}" + raise SerializationError(error.format(attr, enum_obj)) from exc + + @staticmethod + def serialize_bytearray(attr, **kwargs): # pylint: disable=unused-argument + """Serialize bytearray into base-64 string. + + :param str attr: Object to be serialized. + :rtype: str + :return: serialized base64 + """ + return b64encode(attr).decode() + + @staticmethod + def serialize_base64(attr, **kwargs): # pylint: disable=unused-argument + """Serialize str into base-64 string. + + :param str attr: Object to be serialized. + :rtype: str + :return: serialized base64 + """ + encoded = b64encode(attr).decode("ascii") + return encoded.strip("=").replace("+", "-").replace("/", "_") + + @staticmethod + def serialize_decimal(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Decimal object to float. + + :param decimal attr: Object to be serialized. + :rtype: float + :return: serialized decimal + """ + return float(attr) + + @staticmethod + def serialize_long(attr, **kwargs): # pylint: disable=unused-argument + """Serialize long (Py2) or int (Py3). + + :param int attr: Object to be serialized. + :rtype: int/long + :return: serialized long + """ + return _long_type(attr) + + @staticmethod + def serialize_date(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Date object into ISO-8601 formatted string. + + :param Date attr: Object to be serialized. + :rtype: str + :return: serialized date + """ + if isinstance(attr, str): + attr = isodate.parse_date(attr) + t = "{:04}-{:02}-{:02}".format(attr.year, attr.month, attr.day) + return t + + @staticmethod + def serialize_time(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Time object into ISO-8601 formatted string. + + :param datetime.time attr: Object to be serialized. + :rtype: str + :return: serialized time + """ + if isinstance(attr, str): + attr = isodate.parse_time(attr) + t = "{:02}:{:02}:{:02}".format(attr.hour, attr.minute, attr.second) + if attr.microsecond: + t += ".{:02}".format(attr.microsecond) + return t + + @staticmethod + def serialize_duration(attr, **kwargs): # pylint: disable=unused-argument + """Serialize TimeDelta object into ISO-8601 formatted string. + + :param TimeDelta attr: Object to be serialized. + :rtype: str + :return: serialized duration + """ + if isinstance(attr, str): + attr = isodate.parse_duration(attr) + return isodate.duration_isoformat(attr) + + @staticmethod + def serialize_rfc(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Datetime object into RFC-1123 formatted string. + + :param Datetime attr: Object to be serialized. + :rtype: str + :raises TypeError: if format invalid. + :return: serialized rfc + """ + try: + if not attr.tzinfo: + _LOGGER.warning("Datetime with no tzinfo will be considered UTC.") + utc = attr.utctimetuple() + except AttributeError as exc: + raise TypeError("RFC1123 object must be valid Datetime object.") from exc + + return "{}, {:02} {} {:04} {:02}:{:02}:{:02} GMT".format( + Serializer.days[utc.tm_wday], + utc.tm_mday, + Serializer.months[utc.tm_mon], + utc.tm_year, + utc.tm_hour, + utc.tm_min, + utc.tm_sec, + ) + + @staticmethod + def serialize_iso(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Datetime object into ISO-8601 formatted string. + + :param Datetime attr: Object to be serialized. + :rtype: str + :raises SerializationError: if format invalid. + :return: serialized iso + """ + if isinstance(attr, str): + attr = isodate.parse_datetime(attr) + try: + if not attr.tzinfo: + _LOGGER.warning("Datetime with no tzinfo will be considered UTC.") + utc = attr.utctimetuple() + if utc.tm_year > 9999 or utc.tm_year < 1: + raise OverflowError("Hit max or min date") + + microseconds = str(attr.microsecond).rjust(6, "0").rstrip("0").ljust(3, "0") + if microseconds: + microseconds = "." + microseconds + date = "{:04}-{:02}-{:02}T{:02}:{:02}:{:02}".format( + utc.tm_year, utc.tm_mon, utc.tm_mday, utc.tm_hour, utc.tm_min, utc.tm_sec + ) + return date + microseconds + "Z" + except (ValueError, OverflowError) as err: + msg = "Unable to serialize datetime object." + raise SerializationError(msg) from err + except AttributeError as err: + msg = "ISO-8601 object must be valid Datetime object." + raise TypeError(msg) from err + + @staticmethod + def serialize_unix(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Datetime object into IntTime format. + This is represented as seconds. + + :param Datetime attr: Object to be serialized. + :rtype: int + :raises SerializationError: if format invalid + :return: serialied unix + """ + if isinstance(attr, int): + return attr + try: + if not attr.tzinfo: + _LOGGER.warning("Datetime with no tzinfo will be considered UTC.") + return int(calendar.timegm(attr.utctimetuple())) + except AttributeError as exc: + raise TypeError("Unix time object must be valid Datetime object.") from exc + + +def rest_key_extractor(attr, attr_desc, data): # pylint: disable=unused-argument + key = attr_desc["key"] + working_data = data + + while "." in key: + # Need the cast, as for some reasons "split" is typed as list[str | Any] + dict_keys = cast(List[str], _FLATTEN.split(key)) + if len(dict_keys) == 1: + key = _decode_attribute_map_key(dict_keys[0]) + break + working_key = _decode_attribute_map_key(dict_keys[0]) + working_data = working_data.get(working_key, data) + if working_data is None: + # If at any point while following flatten JSON path see None, it means + # that all properties under are None as well + return None + key = ".".join(dict_keys[1:]) + + return working_data.get(key) + + +def rest_key_case_insensitive_extractor( # pylint: disable=unused-argument, inconsistent-return-statements + attr, attr_desc, data +): + key = attr_desc["key"] + working_data = data + + while "." in key: + dict_keys = _FLATTEN.split(key) + if len(dict_keys) == 1: + key = _decode_attribute_map_key(dict_keys[0]) + break + working_key = _decode_attribute_map_key(dict_keys[0]) + working_data = attribute_key_case_insensitive_extractor(working_key, None, working_data) + if working_data is None: + # If at any point while following flatten JSON path see None, it means + # that all properties under are None as well + return None + key = ".".join(dict_keys[1:]) + + if working_data: + return attribute_key_case_insensitive_extractor(key, None, working_data) + + +def last_rest_key_extractor(attr, attr_desc, data): # pylint: disable=unused-argument + """Extract the attribute in "data" based on the last part of the JSON path key. + + :param str attr: The attribute to extract + :param dict attr_desc: The attribute description + :param dict data: The data to extract from + :rtype: object + :returns: The extracted attribute + """ + key = attr_desc["key"] + dict_keys = _FLATTEN.split(key) + return attribute_key_extractor(dict_keys[-1], None, data) + + +def last_rest_key_case_insensitive_extractor(attr, attr_desc, data): # pylint: disable=unused-argument + """Extract the attribute in "data" based on the last part of the JSON path key. + + This is the case insensitive version of "last_rest_key_extractor" + :param str attr: The attribute to extract + :param dict attr_desc: The attribute description + :param dict data: The data to extract from + :rtype: object + :returns: The extracted attribute + """ + key = attr_desc["key"] + dict_keys = _FLATTEN.split(key) + return attribute_key_case_insensitive_extractor(dict_keys[-1], None, data) + + +def attribute_key_extractor(attr, _, data): + return data.get(attr) + + +def attribute_key_case_insensitive_extractor(attr, _, data): + found_key = None + lower_attr = attr.lower() + for key in data: + if lower_attr == key.lower(): + found_key = key + break + + return data.get(found_key) + + +def _extract_name_from_internal_type(internal_type): + """Given an internal type XML description, extract correct XML name with namespace. + + :param dict internal_type: An model type + :rtype: tuple + :returns: A tuple XML name + namespace dict + """ + internal_type_xml_map = getattr(internal_type, "_xml_map", {}) + xml_name = internal_type_xml_map.get("name", internal_type.__name__) + xml_ns = internal_type_xml_map.get("ns", None) + if xml_ns: + xml_name = "{{{}}}{}".format(xml_ns, xml_name) + return xml_name + + +def xml_key_extractor(attr, attr_desc, data): # pylint: disable=unused-argument,too-many-return-statements + if isinstance(data, dict): + return None + + # Test if this model is XML ready first + if not isinstance(data, ET.Element): + return None + + xml_desc = attr_desc.get("xml", {}) + xml_name = xml_desc.get("name", attr_desc["key"]) + + # Look for a children + is_iter_type = attr_desc["type"].startswith("[") + is_wrapped = xml_desc.get("wrapped", False) + internal_type = attr_desc.get("internalType", None) + internal_type_xml_map = getattr(internal_type, "_xml_map", {}) + + # Integrate namespace if necessary + xml_ns = xml_desc.get("ns", internal_type_xml_map.get("ns", None)) + if xml_ns: + xml_name = "{{{}}}{}".format(xml_ns, xml_name) + + # If it's an attribute, that's simple + if xml_desc.get("attr", False): + return data.get(xml_name) + + # If it's x-ms-text, that's simple too + if xml_desc.get("text", False): + return data.text + + # Scenario where I take the local name: + # - Wrapped node + # - Internal type is an enum (considered basic types) + # - Internal type has no XML/Name node + if is_wrapped or (internal_type and (issubclass(internal_type, Enum) or "name" not in internal_type_xml_map)): + children = data.findall(xml_name) + # If internal type has a local name and it's not a list, I use that name + elif not is_iter_type and internal_type and "name" in internal_type_xml_map: + xml_name = _extract_name_from_internal_type(internal_type) + children = data.findall(xml_name) + # That's an array + else: + if internal_type: # Complex type, ignore itemsName and use the complex type name + items_name = _extract_name_from_internal_type(internal_type) + else: + items_name = xml_desc.get("itemsName", xml_name) + children = data.findall(items_name) + + if len(children) == 0: + if is_iter_type: + if is_wrapped: + return None # is_wrapped no node, we want None + return [] # not wrapped, assume empty list + return None # Assume it's not there, maybe an optional node. + + # If is_iter_type and not wrapped, return all found children + if is_iter_type: + if not is_wrapped: + return children + # Iter and wrapped, should have found one node only (the wrap one) + if len(children) != 1: + raise DeserializationError( + "Tried to deserialize an array not wrapped, and found several nodes '{}'. Maybe you should declare this array as wrapped?".format( + xml_name + ) + ) + return list(children[0]) # Might be empty list and that's ok. + + # Here it's not a itertype, we should have found one element only or empty + if len(children) > 1: + raise DeserializationError("Find several XML '{}' where it was not expected".format(xml_name)) + return children[0] + + +class Deserializer: + """Response object model deserializer. + + :param dict classes: Class type dictionary for deserializing complex types. + :ivar list key_extractors: Ordered list of extractors to be used by this deserializer. + """ + + basic_types = {str: "str", int: "int", bool: "bool", float: "float"} + + valid_date = re.compile(r"\d{4}[-]\d{2}[-]\d{2}T\d{2}:\d{2}:\d{2}\.?\d*Z?[-+]?[\d{2}]?:?[\d{2}]?") + + def __init__(self, classes: Optional[Mapping[str, type]] = None) -> None: + self.deserialize_type = { + "iso-8601": Deserializer.deserialize_iso, + "rfc-1123": Deserializer.deserialize_rfc, + "unix-time": Deserializer.deserialize_unix, + "duration": Deserializer.deserialize_duration, + "date": Deserializer.deserialize_date, + "time": Deserializer.deserialize_time, + "decimal": Deserializer.deserialize_decimal, + "long": Deserializer.deserialize_long, + "bytearray": Deserializer.deserialize_bytearray, + "base64": Deserializer.deserialize_base64, + "object": self.deserialize_object, + "[]": self.deserialize_iter, + "{}": self.deserialize_dict, + } + self.deserialize_expected_types = { + "duration": (isodate.Duration, datetime.timedelta), + "iso-8601": (datetime.datetime), + } + self.dependencies: Dict[str, type] = dict(classes) if classes else {} + self.key_extractors = [rest_key_extractor, xml_key_extractor] + # Additional properties only works if the "rest_key_extractor" is used to + # extract the keys. Making it to work whatever the key extractor is too much + # complicated, with no real scenario for now. + # So adding a flag to disable additional properties detection. This flag should be + # used if your expect the deserialization to NOT come from a JSON REST syntax. + # Otherwise, result are unexpected + self.additional_properties_detection = True + + def __call__(self, target_obj, response_data, content_type=None): + """Call the deserializer to process a REST response. + + :param str target_obj: Target data type to deserialize to. + :param requests.Response response_data: REST response object. + :param str content_type: Swagger "produces" if available. + :raises DeserializationError: if deserialization fails. + :return: Deserialized object. + :rtype: object + """ + data = self._unpack_content(response_data, content_type) + return self._deserialize(target_obj, data) + + def _deserialize(self, target_obj, data): # pylint: disable=inconsistent-return-statements + """Call the deserializer on a model. + + Data needs to be already deserialized as JSON or XML ElementTree + + :param str target_obj: Target data type to deserialize to. + :param object data: Object to deserialize. + :raises DeserializationError: if deserialization fails. + :return: Deserialized object. + :rtype: object + """ + # This is already a model, go recursive just in case + if hasattr(data, "_attribute_map"): + constants = [name for name, config in getattr(data, "_validation", {}).items() if config.get("constant")] + try: + for attr, mapconfig in data._attribute_map.items(): # pylint: disable=protected-access + if attr in constants: + continue + value = getattr(data, attr) + if value is None: + continue + local_type = mapconfig["type"] + internal_data_type = local_type.strip("[]{}") + if internal_data_type not in self.dependencies or isinstance(internal_data_type, Enum): + continue + setattr(data, attr, self._deserialize(local_type, value)) + return data + except AttributeError: + return + + response, class_name = self._classify_target(target_obj, data) + + if isinstance(response, str): + return self.deserialize_data(data, response) + if isinstance(response, type) and issubclass(response, Enum): + return self.deserialize_enum(data, response) + + if data is None or data is CoreNull: + return data + try: + attributes = response._attribute_map # type: ignore # pylint: disable=protected-access + d_attrs = {} + for attr, attr_desc in attributes.items(): + # Check empty string. If it's not empty, someone has a real "additionalProperties"... + if attr == "additional_properties" and attr_desc["key"] == "": + continue + raw_value = None + # Enhance attr_desc with some dynamic data + attr_desc = attr_desc.copy() # Do a copy, do not change the real one + internal_data_type = attr_desc["type"].strip("[]{}") + if internal_data_type in self.dependencies: + attr_desc["internalType"] = self.dependencies[internal_data_type] + + for key_extractor in self.key_extractors: + found_value = key_extractor(attr, attr_desc, data) + if found_value is not None: + if raw_value is not None and raw_value != found_value: + msg = ( + "Ignoring extracted value '%s' from %s for key '%s'" + " (duplicate extraction, follow extractors order)" + ) + _LOGGER.warning(msg, found_value, key_extractor, attr) + continue + raw_value = found_value + + value = self.deserialize_data(raw_value, attr_desc["type"]) + d_attrs[attr] = value + except (AttributeError, TypeError, KeyError) as err: + msg = "Unable to deserialize to object: " + class_name # type: ignore + raise DeserializationError(msg) from err + additional_properties = self._build_additional_properties(attributes, data) + return self._instantiate_model(response, d_attrs, additional_properties) + + def _build_additional_properties(self, attribute_map, data): + if not self.additional_properties_detection: + return None + if "additional_properties" in attribute_map and attribute_map.get("additional_properties", {}).get("key") != "": + # Check empty string. If it's not empty, someone has a real "additionalProperties" + return None + if isinstance(data, ET.Element): + data = {el.tag: el.text for el in data} + + known_keys = { + _decode_attribute_map_key(_FLATTEN.split(desc["key"])[0]) + for desc in attribute_map.values() + if desc["key"] != "" + } + present_keys = set(data.keys()) + missing_keys = present_keys - known_keys + return {key: data[key] for key in missing_keys} + + def _classify_target(self, target, data): + """Check to see whether the deserialization target object can + be classified into a subclass. + Once classification has been determined, initialize object. + + :param str target: The target object type to deserialize to. + :param str/dict data: The response data to deserialize. + :return: The classified target object and its class name. + :rtype: tuple + """ + if target is None: + return None, None + + if isinstance(target, str): + try: + target = self.dependencies[target] + except KeyError: + return target, target + + try: + target = target._classify(data, self.dependencies) # type: ignore # pylint: disable=protected-access + except AttributeError: + pass # Target is not a Model, no classify + return target, target.__class__.__name__ # type: ignore + + def failsafe_deserialize(self, target_obj, data, content_type=None): + """Ignores any errors encountered in deserialization, + and falls back to not deserializing the object. Recommended + for use in error deserialization, as we want to return the + HttpResponseError to users, and not have them deal with + a deserialization error. + + :param str target_obj: The target object type to deserialize to. + :param str/dict data: The response data to deserialize. + :param str content_type: Swagger "produces" if available. + :return: Deserialized object. + :rtype: object + """ + try: + return self(target_obj, data, content_type=content_type) + except: # pylint: disable=bare-except + _LOGGER.debug( + "Ran into a deserialization error. Ignoring since this is failsafe deserialization", exc_info=True + ) + return None + + @staticmethod + def _unpack_content(raw_data, content_type=None): + """Extract the correct structure for deserialization. + + If raw_data is a PipelineResponse, try to extract the result of RawDeserializer. + if we can't, raise. Your Pipeline should have a RawDeserializer. + + If not a pipeline response and raw_data is bytes or string, use content-type + to decode it. If no content-type, try JSON. + + If raw_data is something else, bypass all logic and return it directly. + + :param obj raw_data: Data to be processed. + :param str content_type: How to parse if raw_data is a string/bytes. + :raises JSONDecodeError: If JSON is requested and parsing is impossible. + :raises UnicodeDecodeError: If bytes is not UTF8 + :rtype: object + :return: Unpacked content. + """ + # Assume this is enough to detect a Pipeline Response without importing it + context = getattr(raw_data, "context", {}) + if context: + if RawDeserializer.CONTEXT_NAME in context: + return context[RawDeserializer.CONTEXT_NAME] + raise ValueError("This pipeline didn't have the RawDeserializer policy; can't deserialize") + + # Assume this is enough to recognize universal_http.ClientResponse without importing it + if hasattr(raw_data, "body"): + return RawDeserializer.deserialize_from_http_generics(raw_data.text(), raw_data.headers) + + # Assume this enough to recognize requests.Response without importing it. + if hasattr(raw_data, "_content_consumed"): + return RawDeserializer.deserialize_from_http_generics(raw_data.text, raw_data.headers) + + if isinstance(raw_data, (str, bytes)) or hasattr(raw_data, "read"): + return RawDeserializer.deserialize_from_text(raw_data, content_type) # type: ignore + return raw_data + + def _instantiate_model(self, response, attrs, additional_properties=None): + """Instantiate a response model passing in deserialized args. + + :param Response response: The response model class. + :param dict attrs: The deserialized response attributes. + :param dict additional_properties: Additional properties to be set. + :rtype: Response + :return: The instantiated response model. + """ + if callable(response): + subtype = getattr(response, "_subtype_map", {}) + try: + readonly = [ + k + for k, v in response._validation.items() # pylint: disable=protected-access # type: ignore + if v.get("readonly") + ] + const = [ + k + for k, v in response._validation.items() # pylint: disable=protected-access # type: ignore + if v.get("constant") + ] + kwargs = {k: v for k, v in attrs.items() if k not in subtype and k not in readonly + const} + response_obj = response(**kwargs) + for attr in readonly: + setattr(response_obj, attr, attrs.get(attr)) + if additional_properties: + response_obj.additional_properties = additional_properties # type: ignore + return response_obj + except TypeError as err: + msg = "Unable to deserialize {} into model {}. ".format(kwargs, response) # type: ignore + raise DeserializationError(msg + str(err)) from err + else: + try: + for attr, value in attrs.items(): + setattr(response, attr, value) + return response + except Exception as exp: + msg = "Unable to populate response model. " + msg += "Type: {}, Error: {}".format(type(response), exp) + raise DeserializationError(msg) from exp + + def deserialize_data(self, data, data_type): # pylint: disable=too-many-return-statements + """Process data for deserialization according to data type. + + :param str data: The response string to be deserialized. + :param str data_type: The type to deserialize to. + :raises DeserializationError: if deserialization fails. + :return: Deserialized object. + :rtype: object + """ + if data is None: + return data + + try: + if not data_type: + return data + if data_type in self.basic_types.values(): + return self.deserialize_basic(data, data_type) + if data_type in self.deserialize_type: + if isinstance(data, self.deserialize_expected_types.get(data_type, tuple())): + return data + + is_a_text_parsing_type = lambda x: x not in [ # pylint: disable=unnecessary-lambda-assignment + "object", + "[]", + r"{}", + ] + if isinstance(data, ET.Element) and is_a_text_parsing_type(data_type) and not data.text: + return None + data_val = self.deserialize_type[data_type](data) + return data_val + + iter_type = data_type[0] + data_type[-1] + if iter_type in self.deserialize_type: + return self.deserialize_type[iter_type](data, data_type[1:-1]) + + obj_type = self.dependencies[data_type] + if issubclass(obj_type, Enum): + if isinstance(data, ET.Element): + data = data.text + return self.deserialize_enum(data, obj_type) + + except (ValueError, TypeError, AttributeError) as err: + msg = "Unable to deserialize response data." + msg += " Data: {}, {}".format(data, data_type) + raise DeserializationError(msg) from err + return self._deserialize(obj_type, data) + + def deserialize_iter(self, attr, iter_type): + """Deserialize an iterable. + + :param list attr: Iterable to be deserialized. + :param str iter_type: The type of object in the iterable. + :return: Deserialized iterable. + :rtype: list + """ + if attr is None: + return None + if isinstance(attr, ET.Element): # If I receive an element here, get the children + attr = list(attr) + if not isinstance(attr, (list, set)): + raise DeserializationError("Cannot deserialize as [{}] an object of type {}".format(iter_type, type(attr))) + return [self.deserialize_data(a, iter_type) for a in attr] + + def deserialize_dict(self, attr, dict_type): + """Deserialize a dictionary. + + :param dict/list attr: Dictionary to be deserialized. Also accepts + a list of key, value pairs. + :param str dict_type: The object type of the items in the dictionary. + :return: Deserialized dictionary. + :rtype: dict + """ + if isinstance(attr, list): + return {x["key"]: self.deserialize_data(x["value"], dict_type) for x in attr} + + if isinstance(attr, ET.Element): + # Transform value into {"Key": "value"} + attr = {el.tag: el.text for el in attr} + return {k: self.deserialize_data(v, dict_type) for k, v in attr.items()} + + def deserialize_object(self, attr, **kwargs): # pylint: disable=too-many-return-statements + """Deserialize a generic object. + This will be handled as a dictionary. + + :param dict attr: Dictionary to be deserialized. + :return: Deserialized object. + :rtype: dict + :raises TypeError: if non-builtin datatype encountered. + """ + if attr is None: + return None + if isinstance(attr, ET.Element): + # Do no recurse on XML, just return the tree as-is + return attr + if isinstance(attr, str): + return self.deserialize_basic(attr, "str") + obj_type = type(attr) + if obj_type in self.basic_types: + return self.deserialize_basic(attr, self.basic_types[obj_type]) + if obj_type is _long_type: + return self.deserialize_long(attr) + + if obj_type == dict: + deserialized = {} + for key, value in attr.items(): + try: + deserialized[key] = self.deserialize_object(value, **kwargs) + except ValueError: + deserialized[key] = None + return deserialized + + if obj_type == list: + deserialized = [] + for obj in attr: + try: + deserialized.append(self.deserialize_object(obj, **kwargs)) + except ValueError: + pass + return deserialized + + error = "Cannot deserialize generic object with type: " + raise TypeError(error + str(obj_type)) + + def deserialize_basic(self, attr, data_type): # pylint: disable=too-many-return-statements + """Deserialize basic builtin data type from string. + Will attempt to convert to str, int, float and bool. + This function will also accept '1', '0', 'true' and 'false' as + valid bool values. + + :param str attr: response string to be deserialized. + :param str data_type: deserialization data type. + :return: Deserialized basic type. + :rtype: str, int, float or bool + :raises TypeError: if string format is not valid. + """ + # If we're here, data is supposed to be a basic type. + # If it's still an XML node, take the text + if isinstance(attr, ET.Element): + attr = attr.text + if not attr: + if data_type == "str": + # None or '', node is empty string. + return "" + # None or '', node with a strong type is None. + # Don't try to model "empty bool" or "empty int" + return None + + if data_type == "bool": + if attr in [True, False, 1, 0]: + return bool(attr) + if isinstance(attr, str): + if attr.lower() in ["true", "1"]: + return True + if attr.lower() in ["false", "0"]: + return False + raise TypeError("Invalid boolean value: {}".format(attr)) + + if data_type == "str": + return self.deserialize_unicode(attr) + return eval(data_type)(attr) # nosec # pylint: disable=eval-used + + @staticmethod + def deserialize_unicode(data): + """Preserve unicode objects in Python 2, otherwise return data + as a string. + + :param str data: response string to be deserialized. + :return: Deserialized string. + :rtype: str or unicode + """ + # We might be here because we have an enum modeled as string, + # and we try to deserialize a partial dict with enum inside + if isinstance(data, Enum): + return data + + # Consider this is real string + try: + if isinstance(data, unicode): # type: ignore + return data + except NameError: + return str(data) + return str(data) + + @staticmethod + def deserialize_enum(data, enum_obj): + """Deserialize string into enum object. + + If the string is not a valid enum value it will be returned as-is + and a warning will be logged. + + :param str data: Response string to be deserialized. If this value is + None or invalid it will be returned as-is. + :param Enum enum_obj: Enum object to deserialize to. + :return: Deserialized enum object. + :rtype: Enum + """ + if isinstance(data, enum_obj) or data is None: + return data + if isinstance(data, Enum): + data = data.value + if isinstance(data, int): + # Workaround. We might consider remove it in the future. + try: + return list(enum_obj.__members__.values())[data] + except IndexError as exc: + error = "{!r} is not a valid index for enum {!r}" + raise DeserializationError(error.format(data, enum_obj)) from exc + try: + return enum_obj(str(data)) + except ValueError: + for enum_value in enum_obj: + if enum_value.value.lower() == str(data).lower(): + return enum_value + # We don't fail anymore for unknown value, we deserialize as a string + _LOGGER.warning("Deserializer is not able to find %s as valid enum in %s", data, enum_obj) + return Deserializer.deserialize_unicode(data) + + @staticmethod + def deserialize_bytearray(attr): + """Deserialize string into bytearray. + + :param str attr: response string to be deserialized. + :return: Deserialized bytearray + :rtype: bytearray + :raises TypeError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + return bytearray(b64decode(attr)) # type: ignore + + @staticmethod + def deserialize_base64(attr): + """Deserialize base64 encoded string into string. + + :param str attr: response string to be deserialized. + :return: Deserialized base64 string + :rtype: bytearray + :raises TypeError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + padding = "=" * (3 - (len(attr) + 3) % 4) # type: ignore + attr = attr + padding # type: ignore + encoded = attr.replace("-", "+").replace("_", "/") + return b64decode(encoded) + + @staticmethod + def deserialize_decimal(attr): + """Deserialize string into Decimal object. + + :param str attr: response string to be deserialized. + :return: Deserialized decimal + :raises DeserializationError: if string format invalid. + :rtype: decimal + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + return decimal.Decimal(str(attr)) # type: ignore + except decimal.DecimalException as err: + msg = "Invalid decimal {}".format(attr) + raise DeserializationError(msg) from err + + @staticmethod + def deserialize_long(attr): + """Deserialize string into long (Py2) or int (Py3). + + :param str attr: response string to be deserialized. + :return: Deserialized int + :rtype: long or int + :raises ValueError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + return _long_type(attr) # type: ignore + + @staticmethod + def deserialize_duration(attr): + """Deserialize ISO-8601 formatted string into TimeDelta object. + + :param str attr: response string to be deserialized. + :return: Deserialized duration + :rtype: TimeDelta + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + duration = isodate.parse_duration(attr) + except (ValueError, OverflowError, AttributeError) as err: + msg = "Cannot deserialize duration object." + raise DeserializationError(msg) from err + return duration + + @staticmethod + def deserialize_date(attr): + """Deserialize ISO-8601 formatted string into Date object. + + :param str attr: response string to be deserialized. + :return: Deserialized date + :rtype: Date + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + if re.search(r"[^\W\d_]", attr, re.I + re.U): # type: ignore + raise DeserializationError("Date must have only digits and -. Received: %s" % attr) + # This must NOT use defaultmonth/defaultday. Using None ensure this raises an exception. + return isodate.parse_date(attr, defaultmonth=0, defaultday=0) + + @staticmethod + def deserialize_time(attr): + """Deserialize ISO-8601 formatted string into time object. + + :param str attr: response string to be deserialized. + :return: Deserialized time + :rtype: datetime.time + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + if re.search(r"[^\W\d_]", attr, re.I + re.U): # type: ignore + raise DeserializationError("Date must have only digits and -. Received: %s" % attr) + return isodate.parse_time(attr) + + @staticmethod + def deserialize_rfc(attr): + """Deserialize RFC-1123 formatted string into Datetime object. + + :param str attr: response string to be deserialized. + :return: Deserialized RFC datetime + :rtype: Datetime + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + parsed_date = email.utils.parsedate_tz(attr) # type: ignore + date_obj = datetime.datetime( + *parsed_date[:6], tzinfo=datetime.timezone(datetime.timedelta(minutes=(parsed_date[9] or 0) / 60)) + ) + if not date_obj.tzinfo: + date_obj = date_obj.astimezone(tz=TZ_UTC) + except ValueError as err: + msg = "Cannot deserialize to rfc datetime object." + raise DeserializationError(msg) from err + return date_obj + + @staticmethod + def deserialize_iso(attr): + """Deserialize ISO-8601 formatted string into Datetime object. + + :param str attr: response string to be deserialized. + :return: Deserialized ISO datetime + :rtype: Datetime + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + attr = attr.upper() # type: ignore + match = Deserializer.valid_date.match(attr) + if not match: + raise ValueError("Invalid datetime string: " + attr) + + check_decimal = attr.split(".") + if len(check_decimal) > 1: + decimal_str = "" + for digit in check_decimal[1]: + if digit.isdigit(): + decimal_str += digit + else: + break + if len(decimal_str) > 6: + attr = attr.replace(decimal_str, decimal_str[0:6]) + + date_obj = isodate.parse_datetime(attr) + test_utc = date_obj.utctimetuple() + if test_utc.tm_year > 9999 or test_utc.tm_year < 1: + raise OverflowError("Hit max or min date") + except (ValueError, OverflowError, AttributeError) as err: + msg = "Cannot deserialize datetime object." + raise DeserializationError(msg) from err + return date_obj + + @staticmethod + def deserialize_unix(attr): + """Serialize Datetime object into IntTime format. + This is represented as seconds. + + :param int attr: Object to be serialized. + :return: Deserialized datetime + :rtype: Datetime + :raises DeserializationError: if format invalid + """ + if isinstance(attr, ET.Element): + attr = int(attr.text) # type: ignore + try: + attr = int(attr) + date_obj = datetime.datetime.fromtimestamp(attr, TZ_UTC) + except ValueError as err: + msg = "Cannot deserialize to unix datetime object." + raise DeserializationError(msg) from err + return date_obj diff --git a/packages/typespec-python/test/azure/generated/versioning-typechangedfrom/versioning/typechangedfrom/_utils/utils.py b/packages/typespec-python/test/azure/generated/versioning-typechangedfrom/versioning/typechangedfrom/_utils/utils.py new file mode 100644 index 00000000000..35c9c836f85 --- /dev/null +++ b/packages/typespec-python/test/azure/generated/versioning-typechangedfrom/versioning/typechangedfrom/_utils/utils.py @@ -0,0 +1,25 @@ +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) Python Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from abc import ABC +from typing import Generic, TYPE_CHECKING, TypeVar + +if TYPE_CHECKING: + from .serialization import Deserializer, Serializer + + +TClient = TypeVar("TClient") +TConfig = TypeVar("TConfig") + + +class ClientMixinABC(ABC, Generic[TClient, TConfig]): + """DO NOT use this class. It is for internal typing use only.""" + + _client: TClient + _config: TConfig + _serialize: "Serializer" + _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/azure/generated/versioning-typechangedfrom/versioning/typechangedfrom/_vendor.py b/packages/typespec-python/test/azure/generated/versioning-typechangedfrom/versioning/typechangedfrom/_vendor.py deleted file mode 100644 index ce81fb7ab76..00000000000 --- a/packages/typespec-python/test/azure/generated/versioning-typechangedfrom/versioning/typechangedfrom/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) Python Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import TypeChangedFromClientConfiguration - -if TYPE_CHECKING: - from azure.core import PipelineClient - - from ._serialization import Deserializer, Serializer - - -class TypeChangedFromClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "PipelineClient" - _config: TypeChangedFromClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/azure/generated/versioning-typechangedfrom/versioning/typechangedfrom/aio/_client.py b/packages/typespec-python/test/azure/generated/versioning-typechangedfrom/versioning/typechangedfrom/aio/_client.py index fdd63f29c8d..31334ffbcb5 100644 --- a/packages/typespec-python/test/azure/generated/versioning-typechangedfrom/versioning/typechangedfrom/aio/_client.py +++ b/packages/typespec-python/test/azure/generated/versioning-typechangedfrom/versioning/typechangedfrom/aio/_client.py @@ -15,7 +15,7 @@ from azure.core.rest import AsyncHttpResponse, HttpRequest from .. import models as _models -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import TypeChangedFromClientConfiguration from ._operations import TypeChangedFromClientOperationsMixin diff --git a/packages/typespec-python/test/azure/generated/versioning-typechangedfrom/versioning/typechangedfrom/aio/_operations/_operations.py b/packages/typespec-python/test/azure/generated/versioning-typechangedfrom/versioning/typechangedfrom/aio/_operations/_operations.py index c98e0bad0ec..99d76a5008e 100644 --- a/packages/typespec-python/test/azure/generated/versioning-typechangedfrom/versioning/typechangedfrom/aio/_operations/_operations.py +++ b/packages/typespec-python/test/azure/generated/versioning-typechangedfrom/versioning/typechangedfrom/aio/_operations/_operations.py @@ -11,6 +11,7 @@ import json from typing import Any, Callable, Dict, IO, Optional, TypeVar, Union, overload +from azure.core import AsyncPipelineClient from azure.core.exceptions import ( ClientAuthenticationError, HttpResponseError, @@ -27,16 +28,17 @@ from azure.core.utils import case_insensitive_dict from ... import models as _models -from ..._model_base import SdkJSONEncoder, _deserialize from ..._operations._operations import build_type_changed_from_test_request -from .._vendor import TypeChangedFromClientMixinABC +from ..._utils.model_base import SdkJSONEncoder, _deserialize +from ..._utils.utils import ClientMixinABC +from .._configuration import TypeChangedFromClientConfiguration JSON = MutableMapping[str, Any] T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, AsyncHttpResponse], T, Dict[str, Any]], Any]] -class TypeChangedFromClientOperationsMixin(TypeChangedFromClientMixinABC): +class TypeChangedFromClientOperationsMixin(ClientMixinABC[AsyncPipelineClient, TypeChangedFromClientConfiguration]): @overload async def test( diff --git a/packages/typespec-python/test/azure/generated/versioning-typechangedfrom/versioning/typechangedfrom/aio/_vendor.py b/packages/typespec-python/test/azure/generated/versioning-typechangedfrom/versioning/typechangedfrom/aio/_vendor.py deleted file mode 100644 index ae00688372b..00000000000 --- a/packages/typespec-python/test/azure/generated/versioning-typechangedfrom/versioning/typechangedfrom/aio/_vendor.py +++ /dev/null @@ -1,25 +0,0 @@ -# -------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# Code generated by Microsoft (R) Python Code Generator. -# Changes may cause incorrect behavior and will be lost if the code is regenerated. -# -------------------------------------------------------------------------- - -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import TypeChangedFromClientConfiguration - -if TYPE_CHECKING: - from azure.core import AsyncPipelineClient - - from .._serialization import Deserializer, Serializer - - -class TypeChangedFromClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "AsyncPipelineClient" - _config: TypeChangedFromClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/azure/generated/versioning-typechangedfrom/versioning/typechangedfrom/models/_models.py b/packages/typespec-python/test/azure/generated/versioning-typechangedfrom/versioning/typechangedfrom/models/_models.py index 536b61d8536..888ce1ff6c1 100644 --- a/packages/typespec-python/test/azure/generated/versioning-typechangedfrom/versioning/typechangedfrom/models/_models.py +++ b/packages/typespec-python/test/azure/generated/versioning-typechangedfrom/versioning/typechangedfrom/models/_models.py @@ -9,11 +9,10 @@ from typing import Any, Mapping, overload -from .. import _model_base -from .._model_base import rest_field +from .._utils.model_base import Model as _Model, rest_field -class TestModel(_model_base.Model): +class TestModel(_Model): """TestModel. :ivar prop: Required. diff --git a/packages/typespec-python/test/generic_mock_api_tests/asynctests/test_typetest_property_nullable_async.py b/packages/typespec-python/test/generic_mock_api_tests/asynctests/test_typetest_property_nullable_async.py index 21eaedb1914..142b83f87b6 100644 --- a/packages/typespec-python/test/generic_mock_api_tests/asynctests/test_typetest_property_nullable_async.py +++ b/packages/typespec-python/test/generic_mock_api_tests/asynctests/test_typetest_property_nullable_async.py @@ -7,7 +7,7 @@ import pytest from typetest.property.nullable import models from typetest.property.nullable.aio import NullableClient -from typetest.property.nullable._model_base import ( # pylint: disable=protected-access +from typetest.property.nullable._utils.model_base import ( # pylint: disable=protected-access SdkJSONEncoder, ) diff --git a/packages/typespec-python/test/generic_mock_api_tests/test_typetest_property_nullable.py b/packages/typespec-python/test/generic_mock_api_tests/test_typetest_property_nullable.py index 62c026869f5..663c836e1bd 100644 --- a/packages/typespec-python/test/generic_mock_api_tests/test_typetest_property_nullable.py +++ b/packages/typespec-python/test/generic_mock_api_tests/test_typetest_property_nullable.py @@ -6,7 +6,7 @@ import json import pytest from typetest.property.nullable import NullableClient, models -from typetest.property.nullable._model_base import ( # pylint: disable=protected-access +from typetest.property.nullable._utils.model_base import ( # pylint: disable=protected-access SdkJSONEncoder, ) diff --git a/packages/typespec-python/test/generic_mock_api_tests/unittests/test_model_base_serialization.py b/packages/typespec-python/test/generic_mock_api_tests/unittests/test_model_base_serialization.py index ba2f453fec4..7522a9c23fe 100644 --- a/packages/typespec-python/test/generic_mock_api_tests/unittests/test_model_base_serialization.py +++ b/packages/typespec-python/test/generic_mock_api_tests/unittests/test_model_base_serialization.py @@ -26,7 +26,7 @@ import sys from enum import Enum -from specialwords._model_base import ( +from specialwords._utils.model_base import ( SdkJSONEncoder, Model, rest_field, diff --git a/packages/typespec-python/test/generic_mock_api_tests/unittests/test_model_base_xml_serialization.py b/packages/typespec-python/test/generic_mock_api_tests/unittests/test_model_base_xml_serialization.py index 2337da9d89a..78912e305b1 100644 --- a/packages/typespec-python/test/generic_mock_api_tests/unittests/test_model_base_xml_serialization.py +++ b/packages/typespec-python/test/generic_mock_api_tests/unittests/test_model_base_xml_serialization.py @@ -10,7 +10,7 @@ Dict, ) -from specialwords._model_base import ( +from specialwords._utils.model_base import ( _get_element, Model, rest_field, diff --git a/packages/typespec-python/test/unbranded/generated/authentication-api-key/authentication/apikey/_client.py b/packages/typespec-python/test/unbranded/generated/authentication-api-key/authentication/apikey/_client.py index 7a8301eb4c4..e61a01362ca 100644 --- a/packages/typespec-python/test/unbranded/generated/authentication-api-key/authentication/apikey/_client.py +++ b/packages/typespec-python/test/unbranded/generated/authentication-api-key/authentication/apikey/_client.py @@ -10,7 +10,7 @@ from ._configuration import ApiKeyClientConfiguration from ._operations import ApiKeyClientOperationsMixin -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer class ApiKeyClient(ApiKeyClientOperationsMixin): # pylint: disable=client-accepts-api-version-keyword diff --git a/packages/typespec-python/test/unbranded/generated/authentication-api-key/authentication/apikey/_operations/_operations.py b/packages/typespec-python/test/unbranded/generated/authentication-api-key/authentication/apikey/_operations/_operations.py index b405b8246d7..e44edc80b56 100644 --- a/packages/typespec-python/test/unbranded/generated/authentication-api-key/authentication/apikey/_operations/_operations.py +++ b/packages/typespec-python/test/unbranded/generated/authentication-api-key/authentication/apikey/_operations/_operations.py @@ -11,13 +11,15 @@ map_error, ) from corehttp.rest import HttpRequest, HttpResponse +from corehttp.runtime import PipelineClient from corehttp.runtime.pipeline import PipelineResponse from corehttp.utils import case_insensitive_dict from .. import models as _models -from .._model_base import _failsafe_deserialize -from .._serialization import Serializer -from .._vendor import ApiKeyClientMixinABC +from .._configuration import ApiKeyClientConfiguration +from .._utils.model_base import _failsafe_deserialize +from .._utils.serialization import Serializer +from .._utils.utils import ClientMixinABC T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] @@ -47,7 +49,7 @@ def build_api_key_invalid_request(**kwargs: Any) -> HttpRequest: return HttpRequest(method="GET", url=_url, headers=_headers, **kwargs) -class ApiKeyClientOperationsMixin(ApiKeyClientMixinABC): +class ApiKeyClientOperationsMixin(ClientMixinABC[PipelineClient, ApiKeyClientConfiguration]): def valid(self, **kwargs: Any) -> None: # pylint: disable=inconsistent-return-statements """Check whether client is authenticated. diff --git a/packages/typespec-python/test/unbranded/generated/authentication-api-key/authentication/apikey/_utils/__init__.py b/packages/typespec-python/test/unbranded/generated/authentication-api-key/authentication/apikey/_utils/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/packages/typespec-python/test/unbranded/generated/authentication-api-key/authentication/apikey/_model_base.py b/packages/typespec-python/test/unbranded/generated/authentication-api-key/authentication/apikey/_utils/model_base.py similarity index 100% rename from packages/typespec-python/test/unbranded/generated/authentication-api-key/authentication/apikey/_model_base.py rename to packages/typespec-python/test/unbranded/generated/authentication-api-key/authentication/apikey/_utils/model_base.py diff --git a/packages/typespec-python/test/unbranded/generated/authentication-api-key/authentication/apikey/_serialization.py b/packages/typespec-python/test/unbranded/generated/authentication-api-key/authentication/apikey/_utils/serialization.py similarity index 100% rename from packages/typespec-python/test/unbranded/generated/authentication-api-key/authentication/apikey/_serialization.py rename to packages/typespec-python/test/unbranded/generated/authentication-api-key/authentication/apikey/_utils/serialization.py diff --git a/packages/typespec-python/test/unbranded/generated/authentication-api-key/authentication/apikey/_utils/utils.py b/packages/typespec-python/test/unbranded/generated/authentication-api-key/authentication/apikey/_utils/utils.py new file mode 100644 index 00000000000..02aa2f816ea --- /dev/null +++ b/packages/typespec-python/test/unbranded/generated/authentication-api-key/authentication/apikey/_utils/utils.py @@ -0,0 +1,18 @@ +from abc import ABC +from typing import Generic, TYPE_CHECKING, TypeVar + +if TYPE_CHECKING: + from .serialization import Deserializer, Serializer + + +TClient = TypeVar("TClient") +TConfig = TypeVar("TConfig") + + +class ClientMixinABC(ABC, Generic[TClient, TConfig]): + """DO NOT use this class. It is for internal typing use only.""" + + _client: TClient + _config: TConfig + _serialize: "Serializer" + _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/unbranded/generated/authentication-api-key/authentication/apikey/_vendor.py b/packages/typespec-python/test/unbranded/generated/authentication-api-key/authentication/apikey/_vendor.py deleted file mode 100644 index 65d79d7da18..00000000000 --- a/packages/typespec-python/test/unbranded/generated/authentication-api-key/authentication/apikey/_vendor.py +++ /dev/null @@ -1,18 +0,0 @@ -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import ApiKeyClientConfiguration - -if TYPE_CHECKING: - from corehttp.runtime import PipelineClient - - from ._serialization import Deserializer, Serializer - - -class ApiKeyClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "PipelineClient" - _config: ApiKeyClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/unbranded/generated/authentication-api-key/authentication/apikey/aio/_client.py b/packages/typespec-python/test/unbranded/generated/authentication-api-key/authentication/apikey/aio/_client.py index 1481a663f6c..f31f262eac3 100644 --- a/packages/typespec-python/test/unbranded/generated/authentication-api-key/authentication/apikey/aio/_client.py +++ b/packages/typespec-python/test/unbranded/generated/authentication-api-key/authentication/apikey/aio/_client.py @@ -8,7 +8,7 @@ from corehttp.rest import AsyncHttpResponse, HttpRequest from corehttp.runtime import AsyncPipelineClient, policies -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import ApiKeyClientConfiguration from ._operations import ApiKeyClientOperationsMixin diff --git a/packages/typespec-python/test/unbranded/generated/authentication-api-key/authentication/apikey/aio/_operations/_operations.py b/packages/typespec-python/test/unbranded/generated/authentication-api-key/authentication/apikey/aio/_operations/_operations.py index 98b79305ae1..bb47e3f26d2 100644 --- a/packages/typespec-python/test/unbranded/generated/authentication-api-key/authentication/apikey/aio/_operations/_operations.py +++ b/packages/typespec-python/test/unbranded/generated/authentication-api-key/authentication/apikey/aio/_operations/_operations.py @@ -11,18 +11,20 @@ map_error, ) from corehttp.rest import AsyncHttpResponse, HttpRequest +from corehttp.runtime import AsyncPipelineClient from corehttp.runtime.pipeline import PipelineResponse from ... import models as _models -from ..._model_base import _failsafe_deserialize from ..._operations._operations import build_api_key_invalid_request, build_api_key_valid_request -from .._vendor import ApiKeyClientMixinABC +from ..._utils.model_base import _failsafe_deserialize +from ..._utils.utils import ClientMixinABC +from .._configuration import ApiKeyClientConfiguration T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, AsyncHttpResponse], T, Dict[str, Any]], Any]] -class ApiKeyClientOperationsMixin(ApiKeyClientMixinABC): +class ApiKeyClientOperationsMixin(ClientMixinABC[AsyncPipelineClient, ApiKeyClientConfiguration]): async def valid(self, **kwargs: Any) -> None: """Check whether client is authenticated. diff --git a/packages/typespec-python/test/unbranded/generated/authentication-api-key/authentication/apikey/aio/_vendor.py b/packages/typespec-python/test/unbranded/generated/authentication-api-key/authentication/apikey/aio/_vendor.py deleted file mode 100644 index 8828c8978cb..00000000000 --- a/packages/typespec-python/test/unbranded/generated/authentication-api-key/authentication/apikey/aio/_vendor.py +++ /dev/null @@ -1,18 +0,0 @@ -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import ApiKeyClientConfiguration - -if TYPE_CHECKING: - from corehttp.runtime import AsyncPipelineClient - - from .._serialization import Deserializer, Serializer - - -class ApiKeyClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "AsyncPipelineClient" - _config: ApiKeyClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/unbranded/generated/authentication-api-key/authentication/apikey/models/_models.py b/packages/typespec-python/test/unbranded/generated/authentication-api-key/authentication/apikey/models/_models.py index 11442ef8ed8..74139dbef58 100644 --- a/packages/typespec-python/test/unbranded/generated/authentication-api-key/authentication/apikey/models/_models.py +++ b/packages/typespec-python/test/unbranded/generated/authentication-api-key/authentication/apikey/models/_models.py @@ -3,11 +3,10 @@ from typing import Any, Mapping, overload -from .. import _model_base -from .._model_base import rest_field +from .._utils.model_base import Model as _Model, rest_field -class InvalidAuth(_model_base.Model): +class InvalidAuth(_Model): """InvalidAuth. :ivar error: Required. diff --git a/packages/typespec-python/test/unbranded/generated/authentication-http-custom/authentication/http/custom/_client.py b/packages/typespec-python/test/unbranded/generated/authentication-http-custom/authentication/http/custom/_client.py index 9aac9272e4e..ce811a4f2a9 100644 --- a/packages/typespec-python/test/unbranded/generated/authentication-http-custom/authentication/http/custom/_client.py +++ b/packages/typespec-python/test/unbranded/generated/authentication-http-custom/authentication/http/custom/_client.py @@ -10,7 +10,7 @@ from ._configuration import CustomClientConfiguration from ._operations import CustomClientOperationsMixin -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer class CustomClient(CustomClientOperationsMixin): # pylint: disable=client-accepts-api-version-keyword diff --git a/packages/typespec-python/test/unbranded/generated/authentication-http-custom/authentication/http/custom/_operations/_operations.py b/packages/typespec-python/test/unbranded/generated/authentication-http-custom/authentication/http/custom/_operations/_operations.py index 56f8ec41814..08b12d05b37 100644 --- a/packages/typespec-python/test/unbranded/generated/authentication-http-custom/authentication/http/custom/_operations/_operations.py +++ b/packages/typespec-python/test/unbranded/generated/authentication-http-custom/authentication/http/custom/_operations/_operations.py @@ -11,13 +11,15 @@ map_error, ) from corehttp.rest import HttpRequest, HttpResponse +from corehttp.runtime import PipelineClient from corehttp.runtime.pipeline import PipelineResponse from corehttp.utils import case_insensitive_dict from .. import models as _models -from .._model_base import _failsafe_deserialize -from .._serialization import Serializer -from .._vendor import CustomClientMixinABC +from .._configuration import CustomClientConfiguration +from .._utils.model_base import _failsafe_deserialize +from .._utils.serialization import Serializer +from .._utils.utils import ClientMixinABC T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] @@ -47,7 +49,7 @@ def build_custom_invalid_request(**kwargs: Any) -> HttpRequest: return HttpRequest(method="GET", url=_url, headers=_headers, **kwargs) -class CustomClientOperationsMixin(CustomClientMixinABC): +class CustomClientOperationsMixin(ClientMixinABC[PipelineClient, CustomClientConfiguration]): def valid(self, **kwargs: Any) -> None: # pylint: disable=inconsistent-return-statements """Check whether client is authenticated. diff --git a/packages/typespec-python/test/unbranded/generated/authentication-http-custom/authentication/http/custom/_utils/__init__.py b/packages/typespec-python/test/unbranded/generated/authentication-http-custom/authentication/http/custom/_utils/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/packages/typespec-python/test/unbranded/generated/authentication-http-custom/authentication/http/custom/_model_base.py b/packages/typespec-python/test/unbranded/generated/authentication-http-custom/authentication/http/custom/_utils/model_base.py similarity index 100% rename from packages/typespec-python/test/unbranded/generated/authentication-http-custom/authentication/http/custom/_model_base.py rename to packages/typespec-python/test/unbranded/generated/authentication-http-custom/authentication/http/custom/_utils/model_base.py diff --git a/packages/typespec-python/test/unbranded/generated/authentication-http-custom/authentication/http/custom/_serialization.py b/packages/typespec-python/test/unbranded/generated/authentication-http-custom/authentication/http/custom/_utils/serialization.py similarity index 100% rename from packages/typespec-python/test/unbranded/generated/authentication-http-custom/authentication/http/custom/_serialization.py rename to packages/typespec-python/test/unbranded/generated/authentication-http-custom/authentication/http/custom/_utils/serialization.py diff --git a/packages/typespec-python/test/unbranded/generated/authentication-http-custom/authentication/http/custom/_utils/utils.py b/packages/typespec-python/test/unbranded/generated/authentication-http-custom/authentication/http/custom/_utils/utils.py new file mode 100644 index 00000000000..02aa2f816ea --- /dev/null +++ b/packages/typespec-python/test/unbranded/generated/authentication-http-custom/authentication/http/custom/_utils/utils.py @@ -0,0 +1,18 @@ +from abc import ABC +from typing import Generic, TYPE_CHECKING, TypeVar + +if TYPE_CHECKING: + from .serialization import Deserializer, Serializer + + +TClient = TypeVar("TClient") +TConfig = TypeVar("TConfig") + + +class ClientMixinABC(ABC, Generic[TClient, TConfig]): + """DO NOT use this class. It is for internal typing use only.""" + + _client: TClient + _config: TConfig + _serialize: "Serializer" + _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/unbranded/generated/authentication-http-custom/authentication/http/custom/_vendor.py b/packages/typespec-python/test/unbranded/generated/authentication-http-custom/authentication/http/custom/_vendor.py deleted file mode 100644 index 80a22dc1ee2..00000000000 --- a/packages/typespec-python/test/unbranded/generated/authentication-http-custom/authentication/http/custom/_vendor.py +++ /dev/null @@ -1,18 +0,0 @@ -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import CustomClientConfiguration - -if TYPE_CHECKING: - from corehttp.runtime import PipelineClient - - from ._serialization import Deserializer, Serializer - - -class CustomClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "PipelineClient" - _config: CustomClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/unbranded/generated/authentication-http-custom/authentication/http/custom/aio/_client.py b/packages/typespec-python/test/unbranded/generated/authentication-http-custom/authentication/http/custom/aio/_client.py index 85a31b48d12..fd4627b369f 100644 --- a/packages/typespec-python/test/unbranded/generated/authentication-http-custom/authentication/http/custom/aio/_client.py +++ b/packages/typespec-python/test/unbranded/generated/authentication-http-custom/authentication/http/custom/aio/_client.py @@ -8,7 +8,7 @@ from corehttp.rest import AsyncHttpResponse, HttpRequest from corehttp.runtime import AsyncPipelineClient, policies -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import CustomClientConfiguration from ._operations import CustomClientOperationsMixin diff --git a/packages/typespec-python/test/unbranded/generated/authentication-http-custom/authentication/http/custom/aio/_operations/_operations.py b/packages/typespec-python/test/unbranded/generated/authentication-http-custom/authentication/http/custom/aio/_operations/_operations.py index 5de3321791f..b169306c0ff 100644 --- a/packages/typespec-python/test/unbranded/generated/authentication-http-custom/authentication/http/custom/aio/_operations/_operations.py +++ b/packages/typespec-python/test/unbranded/generated/authentication-http-custom/authentication/http/custom/aio/_operations/_operations.py @@ -11,18 +11,20 @@ map_error, ) from corehttp.rest import AsyncHttpResponse, HttpRequest +from corehttp.runtime import AsyncPipelineClient from corehttp.runtime.pipeline import PipelineResponse from ... import models as _models -from ..._model_base import _failsafe_deserialize from ..._operations._operations import build_custom_invalid_request, build_custom_valid_request -from .._vendor import CustomClientMixinABC +from ..._utils.model_base import _failsafe_deserialize +from ..._utils.utils import ClientMixinABC +from .._configuration import CustomClientConfiguration T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, AsyncHttpResponse], T, Dict[str, Any]], Any]] -class CustomClientOperationsMixin(CustomClientMixinABC): +class CustomClientOperationsMixin(ClientMixinABC[AsyncPipelineClient, CustomClientConfiguration]): async def valid(self, **kwargs: Any) -> None: """Check whether client is authenticated. diff --git a/packages/typespec-python/test/unbranded/generated/authentication-http-custom/authentication/http/custom/aio/_vendor.py b/packages/typespec-python/test/unbranded/generated/authentication-http-custom/authentication/http/custom/aio/_vendor.py deleted file mode 100644 index c83ac2d7daa..00000000000 --- a/packages/typespec-python/test/unbranded/generated/authentication-http-custom/authentication/http/custom/aio/_vendor.py +++ /dev/null @@ -1,18 +0,0 @@ -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import CustomClientConfiguration - -if TYPE_CHECKING: - from corehttp.runtime import AsyncPipelineClient - - from .._serialization import Deserializer, Serializer - - -class CustomClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "AsyncPipelineClient" - _config: CustomClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/unbranded/generated/authentication-http-custom/authentication/http/custom/models/_models.py b/packages/typespec-python/test/unbranded/generated/authentication-http-custom/authentication/http/custom/models/_models.py index 11442ef8ed8..74139dbef58 100644 --- a/packages/typespec-python/test/unbranded/generated/authentication-http-custom/authentication/http/custom/models/_models.py +++ b/packages/typespec-python/test/unbranded/generated/authentication-http-custom/authentication/http/custom/models/_models.py @@ -3,11 +3,10 @@ from typing import Any, Mapping, overload -from .. import _model_base -from .._model_base import rest_field +from .._utils.model_base import Model as _Model, rest_field -class InvalidAuth(_model_base.Model): +class InvalidAuth(_Model): """InvalidAuth. :ivar error: Required. diff --git a/packages/typespec-python/test/unbranded/generated/authentication-oauth2/authentication/oauth2/_client.py b/packages/typespec-python/test/unbranded/generated/authentication-oauth2/authentication/oauth2/_client.py index 6f6afce834b..3d0f5eadeb1 100644 --- a/packages/typespec-python/test/unbranded/generated/authentication-oauth2/authentication/oauth2/_client.py +++ b/packages/typespec-python/test/unbranded/generated/authentication-oauth2/authentication/oauth2/_client.py @@ -9,7 +9,7 @@ from ._configuration import OAuth2ClientConfiguration from ._operations import OAuth2ClientOperationsMixin -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer if TYPE_CHECKING: from corehttp.credentials import TokenCredential diff --git a/packages/typespec-python/test/unbranded/generated/authentication-oauth2/authentication/oauth2/_operations/_operations.py b/packages/typespec-python/test/unbranded/generated/authentication-oauth2/authentication/oauth2/_operations/_operations.py index f1a1c298611..93f1a9d4e63 100644 --- a/packages/typespec-python/test/unbranded/generated/authentication-oauth2/authentication/oauth2/_operations/_operations.py +++ b/packages/typespec-python/test/unbranded/generated/authentication-oauth2/authentication/oauth2/_operations/_operations.py @@ -11,13 +11,15 @@ map_error, ) from corehttp.rest import HttpRequest, HttpResponse +from corehttp.runtime import PipelineClient from corehttp.runtime.pipeline import PipelineResponse from corehttp.utils import case_insensitive_dict from .. import models as _models -from .._model_base import _failsafe_deserialize -from .._serialization import Serializer -from .._vendor import OAuth2ClientMixinABC +from .._configuration import OAuth2ClientConfiguration +from .._utils.model_base import _failsafe_deserialize +from .._utils.serialization import Serializer +from .._utils.utils import ClientMixinABC T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] @@ -47,7 +49,7 @@ def build_oauth2_invalid_request(**kwargs: Any) -> HttpRequest: return HttpRequest(method="GET", url=_url, headers=_headers, **kwargs) -class OAuth2ClientOperationsMixin(OAuth2ClientMixinABC): +class OAuth2ClientOperationsMixin(ClientMixinABC[PipelineClient, OAuth2ClientConfiguration]): def valid(self, **kwargs: Any) -> None: # pylint: disable=inconsistent-return-statements """Check whether client is authenticated. diff --git a/packages/typespec-python/test/unbranded/generated/authentication-oauth2/authentication/oauth2/_utils/__init__.py b/packages/typespec-python/test/unbranded/generated/authentication-oauth2/authentication/oauth2/_utils/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/packages/typespec-python/test/unbranded/generated/authentication-oauth2/authentication/oauth2/_model_base.py b/packages/typespec-python/test/unbranded/generated/authentication-oauth2/authentication/oauth2/_utils/model_base.py similarity index 100% rename from packages/typespec-python/test/unbranded/generated/authentication-oauth2/authentication/oauth2/_model_base.py rename to packages/typespec-python/test/unbranded/generated/authentication-oauth2/authentication/oauth2/_utils/model_base.py diff --git a/packages/typespec-python/test/unbranded/generated/authentication-oauth2/authentication/oauth2/_serialization.py b/packages/typespec-python/test/unbranded/generated/authentication-oauth2/authentication/oauth2/_utils/serialization.py similarity index 100% rename from packages/typespec-python/test/unbranded/generated/authentication-oauth2/authentication/oauth2/_serialization.py rename to packages/typespec-python/test/unbranded/generated/authentication-oauth2/authentication/oauth2/_utils/serialization.py diff --git a/packages/typespec-python/test/unbranded/generated/authentication-oauth2/authentication/oauth2/_utils/utils.py b/packages/typespec-python/test/unbranded/generated/authentication-oauth2/authentication/oauth2/_utils/utils.py new file mode 100644 index 00000000000..02aa2f816ea --- /dev/null +++ b/packages/typespec-python/test/unbranded/generated/authentication-oauth2/authentication/oauth2/_utils/utils.py @@ -0,0 +1,18 @@ +from abc import ABC +from typing import Generic, TYPE_CHECKING, TypeVar + +if TYPE_CHECKING: + from .serialization import Deserializer, Serializer + + +TClient = TypeVar("TClient") +TConfig = TypeVar("TConfig") + + +class ClientMixinABC(ABC, Generic[TClient, TConfig]): + """DO NOT use this class. It is for internal typing use only.""" + + _client: TClient + _config: TConfig + _serialize: "Serializer" + _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/unbranded/generated/authentication-oauth2/authentication/oauth2/_vendor.py b/packages/typespec-python/test/unbranded/generated/authentication-oauth2/authentication/oauth2/_vendor.py deleted file mode 100644 index c8c2c733717..00000000000 --- a/packages/typespec-python/test/unbranded/generated/authentication-oauth2/authentication/oauth2/_vendor.py +++ /dev/null @@ -1,18 +0,0 @@ -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import OAuth2ClientConfiguration - -if TYPE_CHECKING: - from corehttp.runtime import PipelineClient - - from ._serialization import Deserializer, Serializer - - -class OAuth2ClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "PipelineClient" - _config: OAuth2ClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/unbranded/generated/authentication-oauth2/authentication/oauth2/aio/_client.py b/packages/typespec-python/test/unbranded/generated/authentication-oauth2/authentication/oauth2/aio/_client.py index 6a1e146b31d..960ed15f710 100644 --- a/packages/typespec-python/test/unbranded/generated/authentication-oauth2/authentication/oauth2/aio/_client.py +++ b/packages/typespec-python/test/unbranded/generated/authentication-oauth2/authentication/oauth2/aio/_client.py @@ -7,7 +7,7 @@ from corehttp.rest import AsyncHttpResponse, HttpRequest from corehttp.runtime import AsyncPipelineClient, policies -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import OAuth2ClientConfiguration from ._operations import OAuth2ClientOperationsMixin diff --git a/packages/typespec-python/test/unbranded/generated/authentication-oauth2/authentication/oauth2/aio/_operations/_operations.py b/packages/typespec-python/test/unbranded/generated/authentication-oauth2/authentication/oauth2/aio/_operations/_operations.py index 59b1fa9e5d9..bdd6864cf33 100644 --- a/packages/typespec-python/test/unbranded/generated/authentication-oauth2/authentication/oauth2/aio/_operations/_operations.py +++ b/packages/typespec-python/test/unbranded/generated/authentication-oauth2/authentication/oauth2/aio/_operations/_operations.py @@ -11,18 +11,20 @@ map_error, ) from corehttp.rest import AsyncHttpResponse, HttpRequest +from corehttp.runtime import AsyncPipelineClient from corehttp.runtime.pipeline import PipelineResponse from ... import models as _models -from ..._model_base import _failsafe_deserialize from ..._operations._operations import build_oauth2_invalid_request, build_oauth2_valid_request -from .._vendor import OAuth2ClientMixinABC +from ..._utils.model_base import _failsafe_deserialize +from ..._utils.utils import ClientMixinABC +from .._configuration import OAuth2ClientConfiguration T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, AsyncHttpResponse], T, Dict[str, Any]], Any]] -class OAuth2ClientOperationsMixin(OAuth2ClientMixinABC): +class OAuth2ClientOperationsMixin(ClientMixinABC[AsyncPipelineClient, OAuth2ClientConfiguration]): async def valid(self, **kwargs: Any) -> None: """Check whether client is authenticated. diff --git a/packages/typespec-python/test/unbranded/generated/authentication-oauth2/authentication/oauth2/aio/_vendor.py b/packages/typespec-python/test/unbranded/generated/authentication-oauth2/authentication/oauth2/aio/_vendor.py deleted file mode 100644 index 8452b813ad4..00000000000 --- a/packages/typespec-python/test/unbranded/generated/authentication-oauth2/authentication/oauth2/aio/_vendor.py +++ /dev/null @@ -1,18 +0,0 @@ -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import OAuth2ClientConfiguration - -if TYPE_CHECKING: - from corehttp.runtime import AsyncPipelineClient - - from .._serialization import Deserializer, Serializer - - -class OAuth2ClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "AsyncPipelineClient" - _config: OAuth2ClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/unbranded/generated/authentication-oauth2/authentication/oauth2/models/_models.py b/packages/typespec-python/test/unbranded/generated/authentication-oauth2/authentication/oauth2/models/_models.py index 11442ef8ed8..74139dbef58 100644 --- a/packages/typespec-python/test/unbranded/generated/authentication-oauth2/authentication/oauth2/models/_models.py +++ b/packages/typespec-python/test/unbranded/generated/authentication-oauth2/authentication/oauth2/models/_models.py @@ -3,11 +3,10 @@ from typing import Any, Mapping, overload -from .. import _model_base -from .._model_base import rest_field +from .._utils.model_base import Model as _Model, rest_field -class InvalidAuth(_model_base.Model): +class InvalidAuth(_Model): """InvalidAuth. :ivar error: Required. diff --git a/packages/typespec-python/test/unbranded/generated/authentication-union/authentication/union/_client.py b/packages/typespec-python/test/unbranded/generated/authentication-union/authentication/union/_client.py index 896549e7540..c7d590f28d0 100644 --- a/packages/typespec-python/test/unbranded/generated/authentication-union/authentication/union/_client.py +++ b/packages/typespec-python/test/unbranded/generated/authentication-union/authentication/union/_client.py @@ -10,7 +10,7 @@ from ._configuration import UnionClientConfiguration from ._operations import UnionClientOperationsMixin -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer if TYPE_CHECKING: from corehttp.credentials import TokenCredential diff --git a/packages/typespec-python/test/unbranded/generated/authentication-union/authentication/union/_operations/_operations.py b/packages/typespec-python/test/unbranded/generated/authentication-union/authentication/union/_operations/_operations.py index bfb07705722..e72fb41e693 100644 --- a/packages/typespec-python/test/unbranded/generated/authentication-union/authentication/union/_operations/_operations.py +++ b/packages/typespec-python/test/unbranded/generated/authentication-union/authentication/union/_operations/_operations.py @@ -11,10 +11,12 @@ map_error, ) from corehttp.rest import HttpRequest, HttpResponse +from corehttp.runtime import PipelineClient from corehttp.runtime.pipeline import PipelineResponse -from .._serialization import Serializer -from .._vendor import UnionClientMixinABC +from .._configuration import UnionClientConfiguration +from .._utils.serialization import Serializer +from .._utils.utils import ClientMixinABC T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] @@ -37,7 +39,7 @@ def build_union_valid_token_request(**kwargs: Any) -> HttpRequest: return HttpRequest(method="GET", url=_url, **kwargs) -class UnionClientOperationsMixin(UnionClientMixinABC): +class UnionClientOperationsMixin(ClientMixinABC[PipelineClient, UnionClientConfiguration]): def valid_key(self, **kwargs: Any) -> None: # pylint: disable=inconsistent-return-statements """Check whether client is authenticated. diff --git a/packages/typespec-python/test/unbranded/generated/authentication-union/authentication/union/_utils/__init__.py b/packages/typespec-python/test/unbranded/generated/authentication-union/authentication/union/_utils/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/packages/typespec-python/test/unbranded/generated/authentication-union/authentication/union/_model_base.py b/packages/typespec-python/test/unbranded/generated/authentication-union/authentication/union/_utils/model_base.py similarity index 100% rename from packages/typespec-python/test/unbranded/generated/authentication-union/authentication/union/_model_base.py rename to packages/typespec-python/test/unbranded/generated/authentication-union/authentication/union/_utils/model_base.py diff --git a/packages/typespec-python/test/unbranded/generated/authentication-union/authentication/union/_serialization.py b/packages/typespec-python/test/unbranded/generated/authentication-union/authentication/union/_utils/serialization.py similarity index 100% rename from packages/typespec-python/test/unbranded/generated/authentication-union/authentication/union/_serialization.py rename to packages/typespec-python/test/unbranded/generated/authentication-union/authentication/union/_utils/serialization.py diff --git a/packages/typespec-python/test/unbranded/generated/authentication-union/authentication/union/_utils/utils.py b/packages/typespec-python/test/unbranded/generated/authentication-union/authentication/union/_utils/utils.py new file mode 100644 index 00000000000..02aa2f816ea --- /dev/null +++ b/packages/typespec-python/test/unbranded/generated/authentication-union/authentication/union/_utils/utils.py @@ -0,0 +1,18 @@ +from abc import ABC +from typing import Generic, TYPE_CHECKING, TypeVar + +if TYPE_CHECKING: + from .serialization import Deserializer, Serializer + + +TClient = TypeVar("TClient") +TConfig = TypeVar("TConfig") + + +class ClientMixinABC(ABC, Generic[TClient, TConfig]): + """DO NOT use this class. It is for internal typing use only.""" + + _client: TClient + _config: TConfig + _serialize: "Serializer" + _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/unbranded/generated/authentication-union/authentication/union/_vendor.py b/packages/typespec-python/test/unbranded/generated/authentication-union/authentication/union/_vendor.py deleted file mode 100644 index f76fe46a383..00000000000 --- a/packages/typespec-python/test/unbranded/generated/authentication-union/authentication/union/_vendor.py +++ /dev/null @@ -1,18 +0,0 @@ -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import UnionClientConfiguration - -if TYPE_CHECKING: - from corehttp.runtime import PipelineClient - - from ._serialization import Deserializer, Serializer - - -class UnionClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "PipelineClient" - _config: UnionClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/unbranded/generated/authentication-union/authentication/union/aio/_client.py b/packages/typespec-python/test/unbranded/generated/authentication-union/authentication/union/aio/_client.py index aad356c9e63..7156ca6d0f2 100644 --- a/packages/typespec-python/test/unbranded/generated/authentication-union/authentication/union/aio/_client.py +++ b/packages/typespec-python/test/unbranded/generated/authentication-union/authentication/union/aio/_client.py @@ -8,7 +8,7 @@ from corehttp.rest import AsyncHttpResponse, HttpRequest from corehttp.runtime import AsyncPipelineClient, policies -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import UnionClientConfiguration from ._operations import UnionClientOperationsMixin diff --git a/packages/typespec-python/test/unbranded/generated/authentication-union/authentication/union/aio/_operations/_operations.py b/packages/typespec-python/test/unbranded/generated/authentication-union/authentication/union/aio/_operations/_operations.py index 1f8e44422b1..77a4b7ce2ce 100644 --- a/packages/typespec-python/test/unbranded/generated/authentication-union/authentication/union/aio/_operations/_operations.py +++ b/packages/typespec-python/test/unbranded/generated/authentication-union/authentication/union/aio/_operations/_operations.py @@ -11,16 +11,18 @@ map_error, ) from corehttp.rest import AsyncHttpResponse, HttpRequest +from corehttp.runtime import AsyncPipelineClient from corehttp.runtime.pipeline import PipelineResponse from ..._operations._operations import build_union_valid_key_request, build_union_valid_token_request -from .._vendor import UnionClientMixinABC +from ..._utils.utils import ClientMixinABC +from .._configuration import UnionClientConfiguration T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, AsyncHttpResponse], T, Dict[str, Any]], Any]] -class UnionClientOperationsMixin(UnionClientMixinABC): +class UnionClientOperationsMixin(ClientMixinABC[AsyncPipelineClient, UnionClientConfiguration]): async def valid_key(self, **kwargs: Any) -> None: """Check whether client is authenticated. diff --git a/packages/typespec-python/test/unbranded/generated/authentication-union/authentication/union/aio/_vendor.py b/packages/typespec-python/test/unbranded/generated/authentication-union/authentication/union/aio/_vendor.py deleted file mode 100644 index 480a144ee0e..00000000000 --- a/packages/typespec-python/test/unbranded/generated/authentication-union/authentication/union/aio/_vendor.py +++ /dev/null @@ -1,18 +0,0 @@ -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import UnionClientConfiguration - -if TYPE_CHECKING: - from corehttp.runtime import AsyncPipelineClient - - from .._serialization import Deserializer, Serializer - - -class UnionClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "AsyncPipelineClient" - _config: UnionClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/unbranded/generated/encode-bytes/encode/bytes/_client.py b/packages/typespec-python/test/unbranded/generated/encode-bytes/encode/bytes/_client.py index 89df2bc1bb3..b3ef7174677 100644 --- a/packages/typespec-python/test/unbranded/generated/encode-bytes/encode/bytes/_client.py +++ b/packages/typespec-python/test/unbranded/generated/encode-bytes/encode/bytes/_client.py @@ -8,7 +8,7 @@ from corehttp.runtime import PipelineClient, policies from ._configuration import BytesClientConfiguration -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer from .header.operations import HeaderOperations from .property.operations import PropertyOperations from .query.operations import QueryOperations diff --git a/packages/typespec-python/test/unbranded/generated/encode-bytes/encode/bytes/_utils/__init__.py b/packages/typespec-python/test/unbranded/generated/encode-bytes/encode/bytes/_utils/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/packages/typespec-python/test/unbranded/generated/encode-bytes/encode/bytes/_model_base.py b/packages/typespec-python/test/unbranded/generated/encode-bytes/encode/bytes/_utils/model_base.py similarity index 100% rename from packages/typespec-python/test/unbranded/generated/encode-bytes/encode/bytes/_model_base.py rename to packages/typespec-python/test/unbranded/generated/encode-bytes/encode/bytes/_utils/model_base.py diff --git a/packages/typespec-python/test/unbranded/generated/encode-bytes/encode/bytes/_serialization.py b/packages/typespec-python/test/unbranded/generated/encode-bytes/encode/bytes/_utils/serialization.py similarity index 100% rename from packages/typespec-python/test/unbranded/generated/encode-bytes/encode/bytes/_serialization.py rename to packages/typespec-python/test/unbranded/generated/encode-bytes/encode/bytes/_utils/serialization.py diff --git a/packages/typespec-python/test/unbranded/generated/encode-bytes/encode/bytes/aio/_client.py b/packages/typespec-python/test/unbranded/generated/encode-bytes/encode/bytes/aio/_client.py index 8a8d0ed2077..0ddad29adb4 100644 --- a/packages/typespec-python/test/unbranded/generated/encode-bytes/encode/bytes/aio/_client.py +++ b/packages/typespec-python/test/unbranded/generated/encode-bytes/encode/bytes/aio/_client.py @@ -7,7 +7,7 @@ from corehttp.rest import AsyncHttpResponse, HttpRequest from corehttp.runtime import AsyncPipelineClient, policies -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ..header.aio.operations import HeaderOperations from ..property.aio.operations import PropertyOperations from ..query.aio.operations import QueryOperations diff --git a/packages/typespec-python/test/unbranded/generated/encode-bytes/encode/bytes/header/aio/operations/_operations.py b/packages/typespec-python/test/unbranded/generated/encode-bytes/encode/bytes/header/aio/operations/_operations.py index 5dc65042f77..2d5265d8f75 100644 --- a/packages/typespec-python/test/unbranded/generated/encode-bytes/encode/bytes/header/aio/operations/_operations.py +++ b/packages/typespec-python/test/unbranded/generated/encode-bytes/encode/bytes/header/aio/operations/_operations.py @@ -14,7 +14,7 @@ from corehttp.runtime import AsyncPipelineClient from corehttp.runtime.pipeline import PipelineResponse -from ...._serialization import Deserializer, Serializer +from ...._utils.serialization import Deserializer, Serializer from ....aio._configuration import BytesClientConfiguration from ...operations._operations import ( build_header_base64_request, diff --git a/packages/typespec-python/test/unbranded/generated/encode-bytes/encode/bytes/header/operations/_operations.py b/packages/typespec-python/test/unbranded/generated/encode-bytes/encode/bytes/header/operations/_operations.py index 0c537ebe2e7..f7da0b9e3d7 100644 --- a/packages/typespec-python/test/unbranded/generated/encode-bytes/encode/bytes/header/operations/_operations.py +++ b/packages/typespec-python/test/unbranded/generated/encode-bytes/encode/bytes/header/operations/_operations.py @@ -16,7 +16,7 @@ from corehttp.utils import case_insensitive_dict from ..._configuration import BytesClientConfiguration -from ..._serialization import Deserializer, Serializer +from ..._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/typespec-python/test/unbranded/generated/encode-bytes/encode/bytes/models/_models.py b/packages/typespec-python/test/unbranded/generated/encode-bytes/encode/bytes/models/_models.py index 8ab10f18323..60d768b9988 100644 --- a/packages/typespec-python/test/unbranded/generated/encode-bytes/encode/bytes/models/_models.py +++ b/packages/typespec-python/test/unbranded/generated/encode-bytes/encode/bytes/models/_models.py @@ -3,11 +3,10 @@ from typing import Any, List, Mapping, overload -from .. import _model_base -from .._model_base import rest_field +from .._utils.model_base import Model as _Model, rest_field -class Base64BytesProperty(_model_base.Model): +class Base64BytesProperty(_Model): """Base64BytesProperty. :ivar value: Required. @@ -35,7 +34,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class Base64urlArrayBytesProperty(_model_base.Model): +class Base64urlArrayBytesProperty(_Model): """Base64urlArrayBytesProperty. :ivar value: Required. @@ -63,7 +62,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class Base64urlBytesProperty(_model_base.Model): +class Base64urlBytesProperty(_Model): """Base64urlBytesProperty. :ivar value: Required. @@ -91,7 +90,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class DefaultBytesProperty(_model_base.Model): +class DefaultBytesProperty(_Model): """DefaultBytesProperty. :ivar value: Required. diff --git a/packages/typespec-python/test/unbranded/generated/encode-bytes/encode/bytes/property/aio/operations/_operations.py b/packages/typespec-python/test/unbranded/generated/encode-bytes/encode/bytes/property/aio/operations/_operations.py index c3f28894855..93da111ee87 100644 --- a/packages/typespec-python/test/unbranded/generated/encode-bytes/encode/bytes/property/aio/operations/_operations.py +++ b/packages/typespec-python/test/unbranded/generated/encode-bytes/encode/bytes/property/aio/operations/_operations.py @@ -20,8 +20,8 @@ from corehttp.utils import case_insensitive_dict from .... import models as _models3 -from ...._model_base import SdkJSONEncoder, _deserialize -from ...._serialization import Deserializer, Serializer +from ...._utils.model_base import SdkJSONEncoder, _deserialize +from ...._utils.serialization import Deserializer, Serializer from ....aio._configuration import BytesClientConfiguration from ...operations._operations import ( build_property_base64_request, diff --git a/packages/typespec-python/test/unbranded/generated/encode-bytes/encode/bytes/property/operations/_operations.py b/packages/typespec-python/test/unbranded/generated/encode-bytes/encode/bytes/property/operations/_operations.py index 9e35c714e46..f3a10b711c8 100644 --- a/packages/typespec-python/test/unbranded/generated/encode-bytes/encode/bytes/property/operations/_operations.py +++ b/packages/typespec-python/test/unbranded/generated/encode-bytes/encode/bytes/property/operations/_operations.py @@ -21,8 +21,8 @@ from ... import models as _models2 from ..._configuration import BytesClientConfiguration -from ..._model_base import SdkJSONEncoder, _deserialize -from ..._serialization import Deserializer, Serializer +from ..._utils.model_base import SdkJSONEncoder, _deserialize +from ..._utils.serialization import Deserializer, Serializer JSON = MutableMapping[str, Any] T = TypeVar("T") diff --git a/packages/typespec-python/test/unbranded/generated/encode-bytes/encode/bytes/query/aio/operations/_operations.py b/packages/typespec-python/test/unbranded/generated/encode-bytes/encode/bytes/query/aio/operations/_operations.py index 1ce932065b5..b532a9ff27e 100644 --- a/packages/typespec-python/test/unbranded/generated/encode-bytes/encode/bytes/query/aio/operations/_operations.py +++ b/packages/typespec-python/test/unbranded/generated/encode-bytes/encode/bytes/query/aio/operations/_operations.py @@ -14,7 +14,7 @@ from corehttp.runtime import AsyncPipelineClient from corehttp.runtime.pipeline import PipelineResponse -from ...._serialization import Deserializer, Serializer +from ...._utils.serialization import Deserializer, Serializer from ....aio._configuration import BytesClientConfiguration from ...operations._operations import ( build_query_base64_request, diff --git a/packages/typespec-python/test/unbranded/generated/encode-bytes/encode/bytes/query/operations/_operations.py b/packages/typespec-python/test/unbranded/generated/encode-bytes/encode/bytes/query/operations/_operations.py index 803875fbb13..88a1187999d 100644 --- a/packages/typespec-python/test/unbranded/generated/encode-bytes/encode/bytes/query/operations/_operations.py +++ b/packages/typespec-python/test/unbranded/generated/encode-bytes/encode/bytes/query/operations/_operations.py @@ -16,7 +16,7 @@ from corehttp.utils import case_insensitive_dict from ..._configuration import BytesClientConfiguration -from ..._serialization import Deserializer, Serializer +from ..._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/typespec-python/test/unbranded/generated/encode-bytes/encode/bytes/requestbody/aio/operations/_operations.py b/packages/typespec-python/test/unbranded/generated/encode-bytes/encode/bytes/requestbody/aio/operations/_operations.py index e3c71a0f426..4fe987932f1 100644 --- a/packages/typespec-python/test/unbranded/generated/encode-bytes/encode/bytes/requestbody/aio/operations/_operations.py +++ b/packages/typespec-python/test/unbranded/generated/encode-bytes/encode/bytes/requestbody/aio/operations/_operations.py @@ -16,8 +16,8 @@ from corehttp.runtime.pipeline import PipelineResponse from corehttp.utils import case_insensitive_dict -from ...._model_base import SdkJSONEncoder -from ...._serialization import Deserializer, Serializer +from ...._utils.model_base import SdkJSONEncoder +from ...._utils.serialization import Deserializer, Serializer from ....aio._configuration import BytesClientConfiguration from ...operations._operations import ( build_request_body_base64_request, diff --git a/packages/typespec-python/test/unbranded/generated/encode-bytes/encode/bytes/requestbody/operations/_operations.py b/packages/typespec-python/test/unbranded/generated/encode-bytes/encode/bytes/requestbody/operations/_operations.py index 29c87e9a371..1e362e92d4c 100644 --- a/packages/typespec-python/test/unbranded/generated/encode-bytes/encode/bytes/requestbody/operations/_operations.py +++ b/packages/typespec-python/test/unbranded/generated/encode-bytes/encode/bytes/requestbody/operations/_operations.py @@ -17,8 +17,8 @@ from corehttp.utils import case_insensitive_dict from ..._configuration import BytesClientConfiguration -from ..._model_base import SdkJSONEncoder -from ..._serialization import Deserializer, Serializer +from ..._utils.model_base import SdkJSONEncoder +from ..._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/typespec-python/test/unbranded/generated/encode-bytes/encode/bytes/responsebody/aio/operations/_operations.py b/packages/typespec-python/test/unbranded/generated/encode-bytes/encode/bytes/responsebody/aio/operations/_operations.py index 51f1d907f31..1d71273a17d 100644 --- a/packages/typespec-python/test/unbranded/generated/encode-bytes/encode/bytes/responsebody/aio/operations/_operations.py +++ b/packages/typespec-python/test/unbranded/generated/encode-bytes/encode/bytes/responsebody/aio/operations/_operations.py @@ -16,8 +16,8 @@ from corehttp.runtime import AsyncPipelineClient from corehttp.runtime.pipeline import PipelineResponse -from ...._model_base import _deserialize -from ...._serialization import Deserializer, Serializer +from ...._utils.model_base import _deserialize +from ...._utils.serialization import Deserializer, Serializer from ....aio._configuration import BytesClientConfiguration from ...operations._operations import ( build_response_body_base64_request, diff --git a/packages/typespec-python/test/unbranded/generated/encode-bytes/encode/bytes/responsebody/operations/_operations.py b/packages/typespec-python/test/unbranded/generated/encode-bytes/encode/bytes/responsebody/operations/_operations.py index 7e59b886adb..96db45239fa 100644 --- a/packages/typespec-python/test/unbranded/generated/encode-bytes/encode/bytes/responsebody/operations/_operations.py +++ b/packages/typespec-python/test/unbranded/generated/encode-bytes/encode/bytes/responsebody/operations/_operations.py @@ -18,8 +18,8 @@ from corehttp.utils import case_insensitive_dict from ..._configuration import BytesClientConfiguration -from ..._model_base import _deserialize -from ..._serialization import Deserializer, Serializer +from ..._utils.model_base import _deserialize +from ..._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/typespec-python/test/unbranded/generated/encode-datetime/encode/datetime/_client.py b/packages/typespec-python/test/unbranded/generated/encode-datetime/encode/datetime/_client.py index b4c2f01bf18..e30653f26a2 100644 --- a/packages/typespec-python/test/unbranded/generated/encode-datetime/encode/datetime/_client.py +++ b/packages/typespec-python/test/unbranded/generated/encode-datetime/encode/datetime/_client.py @@ -8,7 +8,7 @@ from corehttp.runtime import PipelineClient, policies from ._configuration import DatetimeClientConfiguration -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer from .header.operations import HeaderOperations from .property.operations import PropertyOperations from .query.operations import QueryOperations diff --git a/packages/typespec-python/test/unbranded/generated/encode-datetime/encode/datetime/_utils/__init__.py b/packages/typespec-python/test/unbranded/generated/encode-datetime/encode/datetime/_utils/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/packages/typespec-python/test/unbranded/generated/encode-datetime/encode/datetime/_model_base.py b/packages/typespec-python/test/unbranded/generated/encode-datetime/encode/datetime/_utils/model_base.py similarity index 100% rename from packages/typespec-python/test/unbranded/generated/encode-datetime/encode/datetime/_model_base.py rename to packages/typespec-python/test/unbranded/generated/encode-datetime/encode/datetime/_utils/model_base.py diff --git a/packages/typespec-python/test/unbranded/generated/encode-datetime/encode/datetime/_serialization.py b/packages/typespec-python/test/unbranded/generated/encode-datetime/encode/datetime/_utils/serialization.py similarity index 100% rename from packages/typespec-python/test/unbranded/generated/encode-datetime/encode/datetime/_serialization.py rename to packages/typespec-python/test/unbranded/generated/encode-datetime/encode/datetime/_utils/serialization.py diff --git a/packages/typespec-python/test/unbranded/generated/encode-datetime/encode/datetime/aio/_client.py b/packages/typespec-python/test/unbranded/generated/encode-datetime/encode/datetime/aio/_client.py index 5c0e12bfc24..9cc99d98c7e 100644 --- a/packages/typespec-python/test/unbranded/generated/encode-datetime/encode/datetime/aio/_client.py +++ b/packages/typespec-python/test/unbranded/generated/encode-datetime/encode/datetime/aio/_client.py @@ -7,7 +7,7 @@ from corehttp.rest import AsyncHttpResponse, HttpRequest from corehttp.runtime import AsyncPipelineClient, policies -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ..header.aio.operations import HeaderOperations from ..property.aio.operations import PropertyOperations from ..query.aio.operations import QueryOperations diff --git a/packages/typespec-python/test/unbranded/generated/encode-datetime/encode/datetime/header/aio/operations/_operations.py b/packages/typespec-python/test/unbranded/generated/encode-datetime/encode/datetime/header/aio/operations/_operations.py index 4bc2e51b23b..66c04673ed3 100644 --- a/packages/typespec-python/test/unbranded/generated/encode-datetime/encode/datetime/header/aio/operations/_operations.py +++ b/packages/typespec-python/test/unbranded/generated/encode-datetime/encode/datetime/header/aio/operations/_operations.py @@ -15,7 +15,7 @@ from corehttp.runtime import AsyncPipelineClient from corehttp.runtime.pipeline import PipelineResponse -from ...._serialization import Deserializer, Serializer +from ...._utils.serialization import Deserializer, Serializer from ....aio._configuration import DatetimeClientConfiguration from ...operations._operations import ( build_header_default_request, diff --git a/packages/typespec-python/test/unbranded/generated/encode-datetime/encode/datetime/header/operations/_operations.py b/packages/typespec-python/test/unbranded/generated/encode-datetime/encode/datetime/header/operations/_operations.py index bf90e0028f0..316d5930083 100644 --- a/packages/typespec-python/test/unbranded/generated/encode-datetime/encode/datetime/header/operations/_operations.py +++ b/packages/typespec-python/test/unbranded/generated/encode-datetime/encode/datetime/header/operations/_operations.py @@ -17,7 +17,7 @@ from corehttp.utils import case_insensitive_dict from ..._configuration import DatetimeClientConfiguration -from ..._serialization import Deserializer, Serializer +from ..._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/typespec-python/test/unbranded/generated/encode-datetime/encode/datetime/models/_models.py b/packages/typespec-python/test/unbranded/generated/encode-datetime/encode/datetime/models/_models.py index 5a62bacae29..6f6d921182a 100644 --- a/packages/typespec-python/test/unbranded/generated/encode-datetime/encode/datetime/models/_models.py +++ b/packages/typespec-python/test/unbranded/generated/encode-datetime/encode/datetime/models/_models.py @@ -4,11 +4,10 @@ import datetime from typing import Any, List, Mapping, overload -from .. import _model_base -from .._model_base import rest_field +from .._utils.model_base import Model as _Model, rest_field -class DefaultDatetimeProperty(_model_base.Model): +class DefaultDatetimeProperty(_Model): """DefaultDatetimeProperty. :ivar value: Required. @@ -36,7 +35,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class Rfc3339DatetimeProperty(_model_base.Model): +class Rfc3339DatetimeProperty(_Model): """Rfc3339DatetimeProperty. :ivar value: Required. @@ -64,7 +63,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class Rfc7231DatetimeProperty(_model_base.Model): +class Rfc7231DatetimeProperty(_Model): """Rfc7231DatetimeProperty. :ivar value: Required. @@ -92,7 +91,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class UnixTimestampArrayDatetimeProperty(_model_base.Model): +class UnixTimestampArrayDatetimeProperty(_Model): """UnixTimestampArrayDatetimeProperty. :ivar value: Required. @@ -122,7 +121,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class UnixTimestampDatetimeProperty(_model_base.Model): +class UnixTimestampDatetimeProperty(_Model): """UnixTimestampDatetimeProperty. :ivar value: Required. diff --git a/packages/typespec-python/test/unbranded/generated/encode-datetime/encode/datetime/property/aio/operations/_operations.py b/packages/typespec-python/test/unbranded/generated/encode-datetime/encode/datetime/property/aio/operations/_operations.py index ec6bafc83aa..90b1101c54a 100644 --- a/packages/typespec-python/test/unbranded/generated/encode-datetime/encode/datetime/property/aio/operations/_operations.py +++ b/packages/typespec-python/test/unbranded/generated/encode-datetime/encode/datetime/property/aio/operations/_operations.py @@ -20,8 +20,8 @@ from corehttp.utils import case_insensitive_dict from .... import models as _models3 -from ...._model_base import SdkJSONEncoder, _deserialize -from ...._serialization import Deserializer, Serializer +from ...._utils.model_base import SdkJSONEncoder, _deserialize +from ...._utils.serialization import Deserializer, Serializer from ....aio._configuration import DatetimeClientConfiguration from ...operations._operations import ( build_property_default_request, diff --git a/packages/typespec-python/test/unbranded/generated/encode-datetime/encode/datetime/property/operations/_operations.py b/packages/typespec-python/test/unbranded/generated/encode-datetime/encode/datetime/property/operations/_operations.py index 9445f2c708f..68b90c0c920 100644 --- a/packages/typespec-python/test/unbranded/generated/encode-datetime/encode/datetime/property/operations/_operations.py +++ b/packages/typespec-python/test/unbranded/generated/encode-datetime/encode/datetime/property/operations/_operations.py @@ -21,8 +21,8 @@ from ... import models as _models2 from ..._configuration import DatetimeClientConfiguration -from ..._model_base import SdkJSONEncoder, _deserialize -from ..._serialization import Deserializer, Serializer +from ..._utils.model_base import SdkJSONEncoder, _deserialize +from ..._utils.serialization import Deserializer, Serializer JSON = MutableMapping[str, Any] T = TypeVar("T") diff --git a/packages/typespec-python/test/unbranded/generated/encode-datetime/encode/datetime/query/aio/operations/_operations.py b/packages/typespec-python/test/unbranded/generated/encode-datetime/encode/datetime/query/aio/operations/_operations.py index 200ab2bd5d8..836c2b504fd 100644 --- a/packages/typespec-python/test/unbranded/generated/encode-datetime/encode/datetime/query/aio/operations/_operations.py +++ b/packages/typespec-python/test/unbranded/generated/encode-datetime/encode/datetime/query/aio/operations/_operations.py @@ -15,7 +15,7 @@ from corehttp.runtime import AsyncPipelineClient from corehttp.runtime.pipeline import PipelineResponse -from ...._serialization import Deserializer, Serializer +from ...._utils.serialization import Deserializer, Serializer from ....aio._configuration import DatetimeClientConfiguration from ...operations._operations import ( build_query_default_request, diff --git a/packages/typespec-python/test/unbranded/generated/encode-datetime/encode/datetime/query/operations/_operations.py b/packages/typespec-python/test/unbranded/generated/encode-datetime/encode/datetime/query/operations/_operations.py index 8e773a77e65..22fb47a528b 100644 --- a/packages/typespec-python/test/unbranded/generated/encode-datetime/encode/datetime/query/operations/_operations.py +++ b/packages/typespec-python/test/unbranded/generated/encode-datetime/encode/datetime/query/operations/_operations.py @@ -17,7 +17,7 @@ from corehttp.utils import case_insensitive_dict from ..._configuration import DatetimeClientConfiguration -from ..._serialization import Deserializer, Serializer +from ..._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/typespec-python/test/unbranded/generated/encode-datetime/encode/datetime/responseheader/aio/operations/_operations.py b/packages/typespec-python/test/unbranded/generated/encode-datetime/encode/datetime/responseheader/aio/operations/_operations.py index 59bad618ee2..6582dec6d11 100644 --- a/packages/typespec-python/test/unbranded/generated/encode-datetime/encode/datetime/responseheader/aio/operations/_operations.py +++ b/packages/typespec-python/test/unbranded/generated/encode-datetime/encode/datetime/responseheader/aio/operations/_operations.py @@ -14,7 +14,7 @@ from corehttp.runtime import AsyncPipelineClient from corehttp.runtime.pipeline import PipelineResponse -from ...._serialization import Deserializer, Serializer +from ...._utils.serialization import Deserializer, Serializer from ....aio._configuration import DatetimeClientConfiguration from ...operations._operations import ( build_response_header_default_request, diff --git a/packages/typespec-python/test/unbranded/generated/encode-datetime/encode/datetime/responseheader/operations/_operations.py b/packages/typespec-python/test/unbranded/generated/encode-datetime/encode/datetime/responseheader/operations/_operations.py index 9a9c1df050e..f61792e3152 100644 --- a/packages/typespec-python/test/unbranded/generated/encode-datetime/encode/datetime/responseheader/operations/_operations.py +++ b/packages/typespec-python/test/unbranded/generated/encode-datetime/encode/datetime/responseheader/operations/_operations.py @@ -15,7 +15,7 @@ from corehttp.runtime.pipeline import PipelineResponse from ..._configuration import DatetimeClientConfiguration -from ..._serialization import Deserializer, Serializer +from ..._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/typespec-python/test/unbranded/generated/encode-duration/encode/duration/_client.py b/packages/typespec-python/test/unbranded/generated/encode-duration/encode/duration/_client.py index f19b70ef614..10feef8b77d 100644 --- a/packages/typespec-python/test/unbranded/generated/encode-duration/encode/duration/_client.py +++ b/packages/typespec-python/test/unbranded/generated/encode-duration/encode/duration/_client.py @@ -8,7 +8,7 @@ from corehttp.runtime import PipelineClient, policies from ._configuration import DurationClientConfiguration -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer from .header.operations import HeaderOperations from .property.operations import PropertyOperations from .query.operations import QueryOperations diff --git a/packages/typespec-python/test/unbranded/generated/encode-duration/encode/duration/_utils/__init__.py b/packages/typespec-python/test/unbranded/generated/encode-duration/encode/duration/_utils/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/packages/typespec-python/test/unbranded/generated/encode-duration/encode/duration/_model_base.py b/packages/typespec-python/test/unbranded/generated/encode-duration/encode/duration/_utils/model_base.py similarity index 100% rename from packages/typespec-python/test/unbranded/generated/encode-duration/encode/duration/_model_base.py rename to packages/typespec-python/test/unbranded/generated/encode-duration/encode/duration/_utils/model_base.py diff --git a/packages/typespec-python/test/unbranded/generated/encode-duration/encode/duration/_serialization.py b/packages/typespec-python/test/unbranded/generated/encode-duration/encode/duration/_utils/serialization.py similarity index 100% rename from packages/typespec-python/test/unbranded/generated/encode-duration/encode/duration/_serialization.py rename to packages/typespec-python/test/unbranded/generated/encode-duration/encode/duration/_utils/serialization.py diff --git a/packages/typespec-python/test/unbranded/generated/encode-duration/encode/duration/aio/_client.py b/packages/typespec-python/test/unbranded/generated/encode-duration/encode/duration/aio/_client.py index 971a0a28d13..b24a09c6f34 100644 --- a/packages/typespec-python/test/unbranded/generated/encode-duration/encode/duration/aio/_client.py +++ b/packages/typespec-python/test/unbranded/generated/encode-duration/encode/duration/aio/_client.py @@ -7,7 +7,7 @@ from corehttp.rest import AsyncHttpResponse, HttpRequest from corehttp.runtime import AsyncPipelineClient, policies -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ..header.aio.operations import HeaderOperations from ..property.aio.operations import PropertyOperations from ..query.aio.operations import QueryOperations diff --git a/packages/typespec-python/test/unbranded/generated/encode-duration/encode/duration/header/aio/operations/_operations.py b/packages/typespec-python/test/unbranded/generated/encode-duration/encode/duration/header/aio/operations/_operations.py index ec057b8082a..0d2076c997a 100644 --- a/packages/typespec-python/test/unbranded/generated/encode-duration/encode/duration/header/aio/operations/_operations.py +++ b/packages/typespec-python/test/unbranded/generated/encode-duration/encode/duration/header/aio/operations/_operations.py @@ -15,7 +15,7 @@ from corehttp.runtime import AsyncPipelineClient from corehttp.runtime.pipeline import PipelineResponse -from ...._serialization import Deserializer, Serializer +from ...._utils.serialization import Deserializer, Serializer from ....aio._configuration import DurationClientConfiguration from ...operations._operations import ( build_header_default_request, diff --git a/packages/typespec-python/test/unbranded/generated/encode-duration/encode/duration/header/operations/_operations.py b/packages/typespec-python/test/unbranded/generated/encode-duration/encode/duration/header/operations/_operations.py index d6c2a969544..ac08eb67aaf 100644 --- a/packages/typespec-python/test/unbranded/generated/encode-duration/encode/duration/header/operations/_operations.py +++ b/packages/typespec-python/test/unbranded/generated/encode-duration/encode/duration/header/operations/_operations.py @@ -17,7 +17,7 @@ from corehttp.utils import case_insensitive_dict from ..._configuration import DurationClientConfiguration -from ..._serialization import Deserializer, Serializer +from ..._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/typespec-python/test/unbranded/generated/encode-duration/encode/duration/property/aio/operations/_operations.py b/packages/typespec-python/test/unbranded/generated/encode-duration/encode/duration/property/aio/operations/_operations.py index 2ad35b755fe..10615c7043b 100644 --- a/packages/typespec-python/test/unbranded/generated/encode-duration/encode/duration/property/aio/operations/_operations.py +++ b/packages/typespec-python/test/unbranded/generated/encode-duration/encode/duration/property/aio/operations/_operations.py @@ -20,8 +20,8 @@ from corehttp.utils import case_insensitive_dict from ... import models as _models2 -from ...._model_base import SdkJSONEncoder, _deserialize -from ...._serialization import Deserializer, Serializer +from ...._utils.model_base import SdkJSONEncoder, _deserialize +from ...._utils.serialization import Deserializer, Serializer from ....aio._configuration import DurationClientConfiguration from ...operations._operations import ( build_property_default_request, diff --git a/packages/typespec-python/test/unbranded/generated/encode-duration/encode/duration/property/models/_models.py b/packages/typespec-python/test/unbranded/generated/encode-duration/encode/duration/property/models/_models.py index cedea8815c4..52bdb2bbbb9 100644 --- a/packages/typespec-python/test/unbranded/generated/encode-duration/encode/duration/property/models/_models.py +++ b/packages/typespec-python/test/unbranded/generated/encode-duration/encode/duration/property/models/_models.py @@ -4,11 +4,10 @@ import datetime from typing import Any, List, Mapping, overload -from ... import _model_base -from ..._model_base import rest_field +from ..._utils.model_base import Model as _Model, rest_field -class DefaultDurationProperty(_model_base.Model): +class DefaultDurationProperty(_Model): """DefaultDurationProperty. :ivar value: Required. @@ -36,7 +35,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class Float64SecondsDurationProperty(_model_base.Model): +class Float64SecondsDurationProperty(_Model): """Float64SecondsDurationProperty. :ivar value: Required. @@ -64,7 +63,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class FloatSecondsDurationArrayProperty(_model_base.Model): +class FloatSecondsDurationArrayProperty(_Model): """FloatSecondsDurationArrayProperty. :ivar value: Required. @@ -92,7 +91,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class FloatSecondsDurationProperty(_model_base.Model): +class FloatSecondsDurationProperty(_Model): """FloatSecondsDurationProperty. :ivar value: Required. @@ -120,7 +119,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class Int32SecondsDurationProperty(_model_base.Model): +class Int32SecondsDurationProperty(_Model): """Int32SecondsDurationProperty. :ivar value: Required. @@ -148,7 +147,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class ISO8601DurationProperty(_model_base.Model): +class ISO8601DurationProperty(_Model): """ISO8601DurationProperty. :ivar value: Required. diff --git a/packages/typespec-python/test/unbranded/generated/encode-duration/encode/duration/property/operations/_operations.py b/packages/typespec-python/test/unbranded/generated/encode-duration/encode/duration/property/operations/_operations.py index e447aeda464..e682ea4816d 100644 --- a/packages/typespec-python/test/unbranded/generated/encode-duration/encode/duration/property/operations/_operations.py +++ b/packages/typespec-python/test/unbranded/generated/encode-duration/encode/duration/property/operations/_operations.py @@ -21,8 +21,8 @@ from .. import models as _models1 from ..._configuration import DurationClientConfiguration -from ..._model_base import SdkJSONEncoder, _deserialize -from ..._serialization import Deserializer, Serializer +from ..._utils.model_base import SdkJSONEncoder, _deserialize +from ..._utils.serialization import Deserializer, Serializer JSON = MutableMapping[str, Any] T = TypeVar("T") diff --git a/packages/typespec-python/test/unbranded/generated/encode-duration/encode/duration/query/aio/operations/_operations.py b/packages/typespec-python/test/unbranded/generated/encode-duration/encode/duration/query/aio/operations/_operations.py index d2084a003d2..ca9e6457e23 100644 --- a/packages/typespec-python/test/unbranded/generated/encode-duration/encode/duration/query/aio/operations/_operations.py +++ b/packages/typespec-python/test/unbranded/generated/encode-duration/encode/duration/query/aio/operations/_operations.py @@ -15,7 +15,7 @@ from corehttp.runtime import AsyncPipelineClient from corehttp.runtime.pipeline import PipelineResponse -from ...._serialization import Deserializer, Serializer +from ...._utils.serialization import Deserializer, Serializer from ....aio._configuration import DurationClientConfiguration from ...operations._operations import ( build_query_default_request, diff --git a/packages/typespec-python/test/unbranded/generated/encode-duration/encode/duration/query/operations/_operations.py b/packages/typespec-python/test/unbranded/generated/encode-duration/encode/duration/query/operations/_operations.py index 0967afc6038..90282d2c49f 100644 --- a/packages/typespec-python/test/unbranded/generated/encode-duration/encode/duration/query/operations/_operations.py +++ b/packages/typespec-python/test/unbranded/generated/encode-duration/encode/duration/query/operations/_operations.py @@ -17,7 +17,7 @@ from corehttp.utils import case_insensitive_dict from ..._configuration import DurationClientConfiguration -from ..._serialization import Deserializer, Serializer +from ..._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/typespec-python/test/unbranded/generated/encode-numeric/encode/numeric/_client.py b/packages/typespec-python/test/unbranded/generated/encode-numeric/encode/numeric/_client.py index d1a7a1cdd9e..ae39adff41e 100644 --- a/packages/typespec-python/test/unbranded/generated/encode-numeric/encode/numeric/_client.py +++ b/packages/typespec-python/test/unbranded/generated/encode-numeric/encode/numeric/_client.py @@ -8,7 +8,7 @@ from corehttp.runtime import PipelineClient, policies from ._configuration import NumericClientConfiguration -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer from .property.operations import PropertyOperations diff --git a/packages/typespec-python/test/unbranded/generated/encode-numeric/encode/numeric/_utils/__init__.py b/packages/typespec-python/test/unbranded/generated/encode-numeric/encode/numeric/_utils/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/packages/typespec-python/test/unbranded/generated/encode-numeric/encode/numeric/_model_base.py b/packages/typespec-python/test/unbranded/generated/encode-numeric/encode/numeric/_utils/model_base.py similarity index 100% rename from packages/typespec-python/test/unbranded/generated/encode-numeric/encode/numeric/_model_base.py rename to packages/typespec-python/test/unbranded/generated/encode-numeric/encode/numeric/_utils/model_base.py diff --git a/packages/typespec-python/test/unbranded/generated/encode-numeric/encode/numeric/_serialization.py b/packages/typespec-python/test/unbranded/generated/encode-numeric/encode/numeric/_utils/serialization.py similarity index 100% rename from packages/typespec-python/test/unbranded/generated/encode-numeric/encode/numeric/_serialization.py rename to packages/typespec-python/test/unbranded/generated/encode-numeric/encode/numeric/_utils/serialization.py diff --git a/packages/typespec-python/test/unbranded/generated/encode-numeric/encode/numeric/aio/_client.py b/packages/typespec-python/test/unbranded/generated/encode-numeric/encode/numeric/aio/_client.py index 9ba07793ed9..0afca9d0198 100644 --- a/packages/typespec-python/test/unbranded/generated/encode-numeric/encode/numeric/aio/_client.py +++ b/packages/typespec-python/test/unbranded/generated/encode-numeric/encode/numeric/aio/_client.py @@ -7,7 +7,7 @@ from corehttp.rest import AsyncHttpResponse, HttpRequest from corehttp.runtime import AsyncPipelineClient, policies -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ..property.aio.operations import PropertyOperations from ._configuration import NumericClientConfiguration diff --git a/packages/typespec-python/test/unbranded/generated/encode-numeric/encode/numeric/property/aio/operations/_operations.py b/packages/typespec-python/test/unbranded/generated/encode-numeric/encode/numeric/property/aio/operations/_operations.py index 88cf13a3bd0..e2f6f51366f 100644 --- a/packages/typespec-python/test/unbranded/generated/encode-numeric/encode/numeric/property/aio/operations/_operations.py +++ b/packages/typespec-python/test/unbranded/generated/encode-numeric/encode/numeric/property/aio/operations/_operations.py @@ -20,8 +20,8 @@ from corehttp.utils import case_insensitive_dict from ... import models as _models2 -from ...._model_base import SdkJSONEncoder, _deserialize -from ...._serialization import Deserializer, Serializer +from ...._utils.model_base import SdkJSONEncoder, _deserialize +from ...._utils.serialization import Deserializer, Serializer from ....aio._configuration import NumericClientConfiguration from ...operations._operations import ( build_property_safeint_as_string_request, diff --git a/packages/typespec-python/test/unbranded/generated/encode-numeric/encode/numeric/property/models/_models.py b/packages/typespec-python/test/unbranded/generated/encode-numeric/encode/numeric/property/models/_models.py index a837a062f4f..0e13e85ea1a 100644 --- a/packages/typespec-python/test/unbranded/generated/encode-numeric/encode/numeric/property/models/_models.py +++ b/packages/typespec-python/test/unbranded/generated/encode-numeric/encode/numeric/property/models/_models.py @@ -3,11 +3,10 @@ from typing import Any, Mapping, Optional, overload -from ... import _model_base -from ..._model_base import rest_field +from ..._utils.model_base import Model as _Model, rest_field -class SafeintAsStringProperty(_model_base.Model): +class SafeintAsStringProperty(_Model): """SafeintAsStringProperty. :ivar value: Required. @@ -35,7 +34,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class Uint32AsStringProperty(_model_base.Model): +class Uint32AsStringProperty(_Model): """Uint32AsStringProperty. :ivar value: @@ -62,7 +61,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class Uint8AsStringProperty(_model_base.Model): +class Uint8AsStringProperty(_Model): """Uint8AsStringProperty. :ivar value: Required. diff --git a/packages/typespec-python/test/unbranded/generated/encode-numeric/encode/numeric/property/operations/_operations.py b/packages/typespec-python/test/unbranded/generated/encode-numeric/encode/numeric/property/operations/_operations.py index 220e257c83b..1d8f97924ca 100644 --- a/packages/typespec-python/test/unbranded/generated/encode-numeric/encode/numeric/property/operations/_operations.py +++ b/packages/typespec-python/test/unbranded/generated/encode-numeric/encode/numeric/property/operations/_operations.py @@ -21,8 +21,8 @@ from .. import models as _models1 from ..._configuration import NumericClientConfiguration -from ..._model_base import SdkJSONEncoder, _deserialize -from ..._serialization import Deserializer, Serializer +from ..._utils.model_base import SdkJSONEncoder, _deserialize +from ..._utils.serialization import Deserializer, Serializer JSON = MutableMapping[str, Any] T = TypeVar("T") diff --git a/packages/typespec-python/test/unbranded/generated/headasbooleanfalse/headasbooleanfalse/_client.py b/packages/typespec-python/test/unbranded/generated/headasbooleanfalse/headasbooleanfalse/_client.py index 5af8c176484..2eb2697b7a0 100644 --- a/packages/typespec-python/test/unbranded/generated/headasbooleanfalse/headasbooleanfalse/_client.py +++ b/packages/typespec-python/test/unbranded/generated/headasbooleanfalse/headasbooleanfalse/_client.py @@ -9,7 +9,7 @@ from ._configuration import VisibilityClientConfiguration from ._operations import VisibilityClientOperationsMixin -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer class VisibilityClient(VisibilityClientOperationsMixin): # pylint: disable=client-accepts-api-version-keyword diff --git a/packages/typespec-python/test/unbranded/generated/headasbooleanfalse/headasbooleanfalse/_operations/_operations.py b/packages/typespec-python/test/unbranded/generated/headasbooleanfalse/headasbooleanfalse/_operations/_operations.py index a9d0e411f64..e4a2a342416 100644 --- a/packages/typespec-python/test/unbranded/generated/headasbooleanfalse/headasbooleanfalse/_operations/_operations.py +++ b/packages/typespec-python/test/unbranded/generated/headasbooleanfalse/headasbooleanfalse/_operations/_operations.py @@ -15,13 +15,15 @@ map_error, ) from corehttp.rest import HttpRequest, HttpResponse +from corehttp.runtime import PipelineClient from corehttp.runtime.pipeline import PipelineResponse from corehttp.utils import case_insensitive_dict from .. import models as _models -from .._model_base import SdkJSONEncoder, _deserialize -from .._serialization import Serializer -from .._vendor import VisibilityClientMixinABC +from .._configuration import VisibilityClientConfiguration +from .._utils.model_base import SdkJSONEncoder, _deserialize +from .._utils.serialization import Serializer +from .._utils.utils import ClientMixinABC JSON = MutableMapping[str, Any] T = TypeVar("T") @@ -143,7 +145,7 @@ def build_visibility_put_read_only_model_request(**kwargs: Any) -> HttpRequest: return HttpRequest(method="PUT", url=_url, headers=_headers, **kwargs) -class VisibilityClientOperationsMixin(VisibilityClientMixinABC): +class VisibilityClientOperationsMixin(ClientMixinABC[PipelineClient, VisibilityClientConfiguration]): @overload def get_model( diff --git a/packages/typespec-python/test/unbranded/generated/headasbooleanfalse/headasbooleanfalse/_utils/__init__.py b/packages/typespec-python/test/unbranded/generated/headasbooleanfalse/headasbooleanfalse/_utils/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/packages/typespec-python/test/unbranded/generated/headasbooleanfalse/headasbooleanfalse/_model_base.py b/packages/typespec-python/test/unbranded/generated/headasbooleanfalse/headasbooleanfalse/_utils/model_base.py similarity index 100% rename from packages/typespec-python/test/unbranded/generated/headasbooleanfalse/headasbooleanfalse/_model_base.py rename to packages/typespec-python/test/unbranded/generated/headasbooleanfalse/headasbooleanfalse/_utils/model_base.py diff --git a/packages/typespec-python/test/unbranded/generated/headasbooleanfalse/headasbooleanfalse/_serialization.py b/packages/typespec-python/test/unbranded/generated/headasbooleanfalse/headasbooleanfalse/_utils/serialization.py similarity index 100% rename from packages/typespec-python/test/unbranded/generated/headasbooleanfalse/headasbooleanfalse/_serialization.py rename to packages/typespec-python/test/unbranded/generated/headasbooleanfalse/headasbooleanfalse/_utils/serialization.py diff --git a/packages/typespec-python/test/unbranded/generated/headasbooleanfalse/headasbooleanfalse/_utils/utils.py b/packages/typespec-python/test/unbranded/generated/headasbooleanfalse/headasbooleanfalse/_utils/utils.py new file mode 100644 index 00000000000..02aa2f816ea --- /dev/null +++ b/packages/typespec-python/test/unbranded/generated/headasbooleanfalse/headasbooleanfalse/_utils/utils.py @@ -0,0 +1,18 @@ +from abc import ABC +from typing import Generic, TYPE_CHECKING, TypeVar + +if TYPE_CHECKING: + from .serialization import Deserializer, Serializer + + +TClient = TypeVar("TClient") +TConfig = TypeVar("TConfig") + + +class ClientMixinABC(ABC, Generic[TClient, TConfig]): + """DO NOT use this class. It is for internal typing use only.""" + + _client: TClient + _config: TConfig + _serialize: "Serializer" + _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/unbranded/generated/headasbooleanfalse/headasbooleanfalse/_vendor.py b/packages/typespec-python/test/unbranded/generated/headasbooleanfalse/headasbooleanfalse/_vendor.py deleted file mode 100644 index 68cde436eed..00000000000 --- a/packages/typespec-python/test/unbranded/generated/headasbooleanfalse/headasbooleanfalse/_vendor.py +++ /dev/null @@ -1,18 +0,0 @@ -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import VisibilityClientConfiguration - -if TYPE_CHECKING: - from corehttp.runtime import PipelineClient - - from ._serialization import Deserializer, Serializer - - -class VisibilityClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "PipelineClient" - _config: VisibilityClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/unbranded/generated/headasbooleanfalse/headasbooleanfalse/aio/_client.py b/packages/typespec-python/test/unbranded/generated/headasbooleanfalse/headasbooleanfalse/aio/_client.py index e551c484690..231c07fd58f 100644 --- a/packages/typespec-python/test/unbranded/generated/headasbooleanfalse/headasbooleanfalse/aio/_client.py +++ b/packages/typespec-python/test/unbranded/generated/headasbooleanfalse/headasbooleanfalse/aio/_client.py @@ -7,7 +7,7 @@ from corehttp.rest import AsyncHttpResponse, HttpRequest from corehttp.runtime import AsyncPipelineClient, policies -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import VisibilityClientConfiguration from ._operations import VisibilityClientOperationsMixin diff --git a/packages/typespec-python/test/unbranded/generated/headasbooleanfalse/headasbooleanfalse/aio/_operations/_operations.py b/packages/typespec-python/test/unbranded/generated/headasbooleanfalse/headasbooleanfalse/aio/_operations/_operations.py index 67f7bd8d375..5c2e572e860 100644 --- a/packages/typespec-python/test/unbranded/generated/headasbooleanfalse/headasbooleanfalse/aio/_operations/_operations.py +++ b/packages/typespec-python/test/unbranded/generated/headasbooleanfalse/headasbooleanfalse/aio/_operations/_operations.py @@ -15,11 +15,11 @@ map_error, ) from corehttp.rest import AsyncHttpResponse, HttpRequest +from corehttp.runtime import AsyncPipelineClient from corehttp.runtime.pipeline import PipelineResponse from corehttp.utils import case_insensitive_dict from ... import models as _models -from ..._model_base import SdkJSONEncoder, _deserialize from ..._operations._operations import ( build_visibility_delete_model_request, build_visibility_get_model_request, @@ -29,14 +29,16 @@ build_visibility_put_model_request, build_visibility_put_read_only_model_request, ) -from .._vendor import VisibilityClientMixinABC +from ..._utils.model_base import SdkJSONEncoder, _deserialize +from ..._utils.utils import ClientMixinABC +from .._configuration import VisibilityClientConfiguration JSON = MutableMapping[str, Any] T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, AsyncHttpResponse], T, Dict[str, Any]], Any]] -class VisibilityClientOperationsMixin(VisibilityClientMixinABC): +class VisibilityClientOperationsMixin(ClientMixinABC[AsyncPipelineClient, VisibilityClientConfiguration]): @overload async def get_model( diff --git a/packages/typespec-python/test/unbranded/generated/headasbooleanfalse/headasbooleanfalse/aio/_vendor.py b/packages/typespec-python/test/unbranded/generated/headasbooleanfalse/headasbooleanfalse/aio/_vendor.py deleted file mode 100644 index 408dc6b99ca..00000000000 --- a/packages/typespec-python/test/unbranded/generated/headasbooleanfalse/headasbooleanfalse/aio/_vendor.py +++ /dev/null @@ -1,18 +0,0 @@ -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import VisibilityClientConfiguration - -if TYPE_CHECKING: - from corehttp.runtime import AsyncPipelineClient - - from .._serialization import Deserializer, Serializer - - -class VisibilityClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "AsyncPipelineClient" - _config: VisibilityClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/unbranded/generated/headasbooleanfalse/headasbooleanfalse/models/_models.py b/packages/typespec-python/test/unbranded/generated/headasbooleanfalse/headasbooleanfalse/models/_models.py index a302369b8a6..8afead9dc15 100644 --- a/packages/typespec-python/test/unbranded/generated/headasbooleanfalse/headasbooleanfalse/models/_models.py +++ b/packages/typespec-python/test/unbranded/generated/headasbooleanfalse/headasbooleanfalse/models/_models.py @@ -3,11 +3,10 @@ from typing import Any, Dict, List, Mapping, Optional, overload -from .. import _model_base -from .._model_base import rest_field +from .._utils.model_base import Model as _Model, rest_field -class ReadOnlyModel(_model_base.Model): +class ReadOnlyModel(_Model): """RoundTrip model with readonly optional properties. :ivar optional_nullable_int_list: Optional readonly nullable int list. @@ -22,7 +21,7 @@ class ReadOnlyModel(_model_base.Model): """Optional readonly string dictionary.""" -class VisibilityModel(_model_base.Model): +class VisibilityModel(_Model): """Output model with visibility properties. :ivar read_prop: Required string, illustrating a readonly property. Required. diff --git a/packages/typespec-python/test/unbranded/generated/headasbooleantrue/headasbooleantrue/_client.py b/packages/typespec-python/test/unbranded/generated/headasbooleantrue/headasbooleantrue/_client.py index 5af8c176484..2eb2697b7a0 100644 --- a/packages/typespec-python/test/unbranded/generated/headasbooleantrue/headasbooleantrue/_client.py +++ b/packages/typespec-python/test/unbranded/generated/headasbooleantrue/headasbooleantrue/_client.py @@ -9,7 +9,7 @@ from ._configuration import VisibilityClientConfiguration from ._operations import VisibilityClientOperationsMixin -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer class VisibilityClient(VisibilityClientOperationsMixin): # pylint: disable=client-accepts-api-version-keyword diff --git a/packages/typespec-python/test/unbranded/generated/headasbooleantrue/headasbooleantrue/_operations/_operations.py b/packages/typespec-python/test/unbranded/generated/headasbooleantrue/headasbooleantrue/_operations/_operations.py index 552308f87ed..0d346fdd3a9 100644 --- a/packages/typespec-python/test/unbranded/generated/headasbooleantrue/headasbooleantrue/_operations/_operations.py +++ b/packages/typespec-python/test/unbranded/generated/headasbooleantrue/headasbooleantrue/_operations/_operations.py @@ -15,13 +15,15 @@ map_error, ) from corehttp.rest import HttpRequest, HttpResponse +from corehttp.runtime import PipelineClient from corehttp.runtime.pipeline import PipelineResponse from corehttp.utils import case_insensitive_dict from .. import models as _models -from .._model_base import SdkJSONEncoder, _deserialize -from .._serialization import Serializer -from .._vendor import VisibilityClientMixinABC +from .._configuration import VisibilityClientConfiguration +from .._utils.model_base import SdkJSONEncoder, _deserialize +from .._utils.serialization import Serializer +from .._utils.utils import ClientMixinABC JSON = MutableMapping[str, Any] T = TypeVar("T") @@ -143,7 +145,7 @@ def build_visibility_put_read_only_model_request(**kwargs: Any) -> HttpRequest: return HttpRequest(method="PUT", url=_url, headers=_headers, **kwargs) -class VisibilityClientOperationsMixin(VisibilityClientMixinABC): +class VisibilityClientOperationsMixin(ClientMixinABC[PipelineClient, VisibilityClientConfiguration]): @overload def get_model( diff --git a/packages/typespec-python/test/unbranded/generated/headasbooleantrue/headasbooleantrue/_utils/__init__.py b/packages/typespec-python/test/unbranded/generated/headasbooleantrue/headasbooleantrue/_utils/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/packages/typespec-python/test/unbranded/generated/headasbooleantrue/headasbooleantrue/_model_base.py b/packages/typespec-python/test/unbranded/generated/headasbooleantrue/headasbooleantrue/_utils/model_base.py similarity index 100% rename from packages/typespec-python/test/unbranded/generated/headasbooleantrue/headasbooleantrue/_model_base.py rename to packages/typespec-python/test/unbranded/generated/headasbooleantrue/headasbooleantrue/_utils/model_base.py diff --git a/packages/typespec-python/test/unbranded/generated/headasbooleantrue/headasbooleantrue/_serialization.py b/packages/typespec-python/test/unbranded/generated/headasbooleantrue/headasbooleantrue/_utils/serialization.py similarity index 100% rename from packages/typespec-python/test/unbranded/generated/headasbooleantrue/headasbooleantrue/_serialization.py rename to packages/typespec-python/test/unbranded/generated/headasbooleantrue/headasbooleantrue/_utils/serialization.py diff --git a/packages/typespec-python/test/unbranded/generated/headasbooleantrue/headasbooleantrue/_utils/utils.py b/packages/typespec-python/test/unbranded/generated/headasbooleantrue/headasbooleantrue/_utils/utils.py new file mode 100644 index 00000000000..02aa2f816ea --- /dev/null +++ b/packages/typespec-python/test/unbranded/generated/headasbooleantrue/headasbooleantrue/_utils/utils.py @@ -0,0 +1,18 @@ +from abc import ABC +from typing import Generic, TYPE_CHECKING, TypeVar + +if TYPE_CHECKING: + from .serialization import Deserializer, Serializer + + +TClient = TypeVar("TClient") +TConfig = TypeVar("TConfig") + + +class ClientMixinABC(ABC, Generic[TClient, TConfig]): + """DO NOT use this class. It is for internal typing use only.""" + + _client: TClient + _config: TConfig + _serialize: "Serializer" + _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/unbranded/generated/headasbooleantrue/headasbooleantrue/_vendor.py b/packages/typespec-python/test/unbranded/generated/headasbooleantrue/headasbooleantrue/_vendor.py deleted file mode 100644 index 68cde436eed..00000000000 --- a/packages/typespec-python/test/unbranded/generated/headasbooleantrue/headasbooleantrue/_vendor.py +++ /dev/null @@ -1,18 +0,0 @@ -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import VisibilityClientConfiguration - -if TYPE_CHECKING: - from corehttp.runtime import PipelineClient - - from ._serialization import Deserializer, Serializer - - -class VisibilityClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "PipelineClient" - _config: VisibilityClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/unbranded/generated/headasbooleantrue/headasbooleantrue/aio/_client.py b/packages/typespec-python/test/unbranded/generated/headasbooleantrue/headasbooleantrue/aio/_client.py index e551c484690..231c07fd58f 100644 --- a/packages/typespec-python/test/unbranded/generated/headasbooleantrue/headasbooleantrue/aio/_client.py +++ b/packages/typespec-python/test/unbranded/generated/headasbooleantrue/headasbooleantrue/aio/_client.py @@ -7,7 +7,7 @@ from corehttp.rest import AsyncHttpResponse, HttpRequest from corehttp.runtime import AsyncPipelineClient, policies -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import VisibilityClientConfiguration from ._operations import VisibilityClientOperationsMixin diff --git a/packages/typespec-python/test/unbranded/generated/headasbooleantrue/headasbooleantrue/aio/_operations/_operations.py b/packages/typespec-python/test/unbranded/generated/headasbooleantrue/headasbooleantrue/aio/_operations/_operations.py index cf9935beadf..936997ceee4 100644 --- a/packages/typespec-python/test/unbranded/generated/headasbooleantrue/headasbooleantrue/aio/_operations/_operations.py +++ b/packages/typespec-python/test/unbranded/generated/headasbooleantrue/headasbooleantrue/aio/_operations/_operations.py @@ -15,11 +15,11 @@ map_error, ) from corehttp.rest import AsyncHttpResponse, HttpRequest +from corehttp.runtime import AsyncPipelineClient from corehttp.runtime.pipeline import PipelineResponse from corehttp.utils import case_insensitive_dict from ... import models as _models -from ..._model_base import SdkJSONEncoder, _deserialize from ..._operations._operations import ( build_visibility_delete_model_request, build_visibility_get_model_request, @@ -29,14 +29,16 @@ build_visibility_put_model_request, build_visibility_put_read_only_model_request, ) -from .._vendor import VisibilityClientMixinABC +from ..._utils.model_base import SdkJSONEncoder, _deserialize +from ..._utils.utils import ClientMixinABC +from .._configuration import VisibilityClientConfiguration JSON = MutableMapping[str, Any] T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, AsyncHttpResponse], T, Dict[str, Any]], Any]] -class VisibilityClientOperationsMixin(VisibilityClientMixinABC): +class VisibilityClientOperationsMixin(ClientMixinABC[AsyncPipelineClient, VisibilityClientConfiguration]): @overload async def get_model( diff --git a/packages/typespec-python/test/unbranded/generated/headasbooleantrue/headasbooleantrue/aio/_vendor.py b/packages/typespec-python/test/unbranded/generated/headasbooleantrue/headasbooleantrue/aio/_vendor.py deleted file mode 100644 index 408dc6b99ca..00000000000 --- a/packages/typespec-python/test/unbranded/generated/headasbooleantrue/headasbooleantrue/aio/_vendor.py +++ /dev/null @@ -1,18 +0,0 @@ -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import VisibilityClientConfiguration - -if TYPE_CHECKING: - from corehttp.runtime import AsyncPipelineClient - - from .._serialization import Deserializer, Serializer - - -class VisibilityClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "AsyncPipelineClient" - _config: VisibilityClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/unbranded/generated/headasbooleantrue/headasbooleantrue/models/_models.py b/packages/typespec-python/test/unbranded/generated/headasbooleantrue/headasbooleantrue/models/_models.py index a302369b8a6..8afead9dc15 100644 --- a/packages/typespec-python/test/unbranded/generated/headasbooleantrue/headasbooleantrue/models/_models.py +++ b/packages/typespec-python/test/unbranded/generated/headasbooleantrue/headasbooleantrue/models/_models.py @@ -3,11 +3,10 @@ from typing import Any, Dict, List, Mapping, Optional, overload -from .. import _model_base -from .._model_base import rest_field +from .._utils.model_base import Model as _Model, rest_field -class ReadOnlyModel(_model_base.Model): +class ReadOnlyModel(_Model): """RoundTrip model with readonly optional properties. :ivar optional_nullable_int_list: Optional readonly nullable int list. @@ -22,7 +21,7 @@ class ReadOnlyModel(_model_base.Model): """Optional readonly string dictionary.""" -class VisibilityModel(_model_base.Model): +class VisibilityModel(_Model): """Output model with visibility properties. :ivar read_prop: Required string, illustrating a readonly property. Required. diff --git a/packages/typespec-python/test/unbranded/generated/parameters-basic/parameters/basic/_client.py b/packages/typespec-python/test/unbranded/generated/parameters-basic/parameters/basic/_client.py index 68c098262a5..c6f0c505e86 100644 --- a/packages/typespec-python/test/unbranded/generated/parameters-basic/parameters/basic/_client.py +++ b/packages/typespec-python/test/unbranded/generated/parameters-basic/parameters/basic/_client.py @@ -8,7 +8,7 @@ from corehttp.runtime import PipelineClient, policies from ._configuration import BasicClientConfiguration -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer from .explicitbody.operations import ExplicitBodyOperations from .implicitbody.operations import ImplicitBodyOperations diff --git a/packages/typespec-python/test/unbranded/generated/parameters-basic/parameters/basic/_utils/__init__.py b/packages/typespec-python/test/unbranded/generated/parameters-basic/parameters/basic/_utils/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/packages/typespec-python/test/unbranded/generated/parameters-basic/parameters/basic/_model_base.py b/packages/typespec-python/test/unbranded/generated/parameters-basic/parameters/basic/_utils/model_base.py similarity index 100% rename from packages/typespec-python/test/unbranded/generated/parameters-basic/parameters/basic/_model_base.py rename to packages/typespec-python/test/unbranded/generated/parameters-basic/parameters/basic/_utils/model_base.py diff --git a/packages/typespec-python/test/unbranded/generated/parameters-basic/parameters/basic/_serialization.py b/packages/typespec-python/test/unbranded/generated/parameters-basic/parameters/basic/_utils/serialization.py similarity index 100% rename from packages/typespec-python/test/unbranded/generated/parameters-basic/parameters/basic/_serialization.py rename to packages/typespec-python/test/unbranded/generated/parameters-basic/parameters/basic/_utils/serialization.py diff --git a/packages/typespec-python/test/unbranded/generated/parameters-basic/parameters/basic/aio/_client.py b/packages/typespec-python/test/unbranded/generated/parameters-basic/parameters/basic/aio/_client.py index 9f960fd9c18..129562a9cf5 100644 --- a/packages/typespec-python/test/unbranded/generated/parameters-basic/parameters/basic/aio/_client.py +++ b/packages/typespec-python/test/unbranded/generated/parameters-basic/parameters/basic/aio/_client.py @@ -7,7 +7,7 @@ from corehttp.rest import AsyncHttpResponse, HttpRequest from corehttp.runtime import AsyncPipelineClient, policies -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ..explicitbody.aio.operations import ExplicitBodyOperations from ..implicitbody.aio.operations import ImplicitBodyOperations from ._configuration import BasicClientConfiguration diff --git a/packages/typespec-python/test/unbranded/generated/parameters-basic/parameters/basic/explicitbody/aio/operations/_operations.py b/packages/typespec-python/test/unbranded/generated/parameters-basic/parameters/basic/explicitbody/aio/operations/_operations.py index dee7549c1e8..efff84de8c8 100644 --- a/packages/typespec-python/test/unbranded/generated/parameters-basic/parameters/basic/explicitbody/aio/operations/_operations.py +++ b/packages/typespec-python/test/unbranded/generated/parameters-basic/parameters/basic/explicitbody/aio/operations/_operations.py @@ -18,8 +18,8 @@ from corehttp.utils import case_insensitive_dict from ... import models as _models2 -from ...._model_base import SdkJSONEncoder -from ...._serialization import Deserializer, Serializer +from ...._utils.model_base import SdkJSONEncoder +from ...._utils.serialization import Deserializer, Serializer from ....aio._configuration import BasicClientConfiguration from ...operations._operations import build_explicit_body_simple_request diff --git a/packages/typespec-python/test/unbranded/generated/parameters-basic/parameters/basic/explicitbody/models/_models.py b/packages/typespec-python/test/unbranded/generated/parameters-basic/parameters/basic/explicitbody/models/_models.py index 330ddbac97c..838255d521d 100644 --- a/packages/typespec-python/test/unbranded/generated/parameters-basic/parameters/basic/explicitbody/models/_models.py +++ b/packages/typespec-python/test/unbranded/generated/parameters-basic/parameters/basic/explicitbody/models/_models.py @@ -3,11 +3,10 @@ from typing import Any, Mapping, overload -from ... import _model_base -from ..._model_base import rest_field +from ..._utils.model_base import Model as _Model, rest_field -class User(_model_base.Model): +class User(_Model): """This is a simple model. :ivar name: Required. diff --git a/packages/typespec-python/test/unbranded/generated/parameters-basic/parameters/basic/explicitbody/operations/_operations.py b/packages/typespec-python/test/unbranded/generated/parameters-basic/parameters/basic/explicitbody/operations/_operations.py index 815ed398329..db447370456 100644 --- a/packages/typespec-python/test/unbranded/generated/parameters-basic/parameters/basic/explicitbody/operations/_operations.py +++ b/packages/typespec-python/test/unbranded/generated/parameters-basic/parameters/basic/explicitbody/operations/_operations.py @@ -19,8 +19,8 @@ from .. import models as _models1 from ..._configuration import BasicClientConfiguration -from ..._model_base import SdkJSONEncoder -from ..._serialization import Deserializer, Serializer +from ..._utils.model_base import SdkJSONEncoder +from ..._utils.serialization import Deserializer, Serializer JSON = MutableMapping[str, Any] T = TypeVar("T") diff --git a/packages/typespec-python/test/unbranded/generated/parameters-basic/parameters/basic/implicitbody/aio/operations/_operations.py b/packages/typespec-python/test/unbranded/generated/parameters-basic/parameters/basic/implicitbody/aio/operations/_operations.py index 01046f0339f..44daea59d33 100644 --- a/packages/typespec-python/test/unbranded/generated/parameters-basic/parameters/basic/implicitbody/aio/operations/_operations.py +++ b/packages/typespec-python/test/unbranded/generated/parameters-basic/parameters/basic/implicitbody/aio/operations/_operations.py @@ -17,8 +17,8 @@ from corehttp.runtime.pipeline import PipelineResponse from corehttp.utils import case_insensitive_dict -from ...._model_base import SdkJSONEncoder -from ...._serialization import Deserializer, Serializer +from ...._utils.model_base import SdkJSONEncoder +from ...._utils.serialization import Deserializer, Serializer from ....aio._configuration import BasicClientConfiguration from ...operations._operations import build_implicit_body_simple_request diff --git a/packages/typespec-python/test/unbranded/generated/parameters-basic/parameters/basic/implicitbody/operations/_operations.py b/packages/typespec-python/test/unbranded/generated/parameters-basic/parameters/basic/implicitbody/operations/_operations.py index 47ca527036e..6e83f40c682 100644 --- a/packages/typespec-python/test/unbranded/generated/parameters-basic/parameters/basic/implicitbody/operations/_operations.py +++ b/packages/typespec-python/test/unbranded/generated/parameters-basic/parameters/basic/implicitbody/operations/_operations.py @@ -18,8 +18,8 @@ from corehttp.utils import case_insensitive_dict from ..._configuration import BasicClientConfiguration -from ..._model_base import SdkJSONEncoder -from ..._serialization import Deserializer, Serializer +from ..._utils.model_base import SdkJSONEncoder +from ..._utils.serialization import Deserializer, Serializer JSON = MutableMapping[str, Any] _Unset: Any = object() diff --git a/packages/typespec-python/test/unbranded/generated/parameters-body-optionality/parameters/bodyoptionality/_client.py b/packages/typespec-python/test/unbranded/generated/parameters-body-optionality/parameters/bodyoptionality/_client.py index 2f86cf19e48..7b78ec9d2ca 100644 --- a/packages/typespec-python/test/unbranded/generated/parameters-body-optionality/parameters/bodyoptionality/_client.py +++ b/packages/typespec-python/test/unbranded/generated/parameters-body-optionality/parameters/bodyoptionality/_client.py @@ -9,7 +9,7 @@ from ._configuration import BodyOptionalityClientConfiguration from ._operations import BodyOptionalityClientOperationsMixin -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer from .optionalexplicit.operations import OptionalExplicitOperations diff --git a/packages/typespec-python/test/unbranded/generated/parameters-body-optionality/parameters/bodyoptionality/_operations/_operations.py b/packages/typespec-python/test/unbranded/generated/parameters-body-optionality/parameters/bodyoptionality/_operations/_operations.py index 47268585ed7..cd75f831678 100644 --- a/packages/typespec-python/test/unbranded/generated/parameters-body-optionality/parameters/bodyoptionality/_operations/_operations.py +++ b/packages/typespec-python/test/unbranded/generated/parameters-body-optionality/parameters/bodyoptionality/_operations/_operations.py @@ -13,13 +13,15 @@ map_error, ) from corehttp.rest import HttpRequest, HttpResponse +from corehttp.runtime import PipelineClient from corehttp.runtime.pipeline import PipelineResponse from corehttp.utils import case_insensitive_dict from .. import models as _models1 -from .._model_base import SdkJSONEncoder -from .._serialization import Serializer -from .._vendor import BodyOptionalityClientMixinABC +from .._configuration import BodyOptionalityClientConfiguration +from .._utils.model_base import SdkJSONEncoder +from .._utils.serialization import Serializer +from .._utils.utils import ClientMixinABC JSON = MutableMapping[str, Any] _Unset: Any = object() @@ -58,7 +60,7 @@ def build_body_optionality_required_implicit_request(**kwargs: Any) -> HttpReque return HttpRequest(method="POST", url=_url, headers=_headers, **kwargs) -class BodyOptionalityClientOperationsMixin(BodyOptionalityClientMixinABC): +class BodyOptionalityClientOperationsMixin(ClientMixinABC[PipelineClient, BodyOptionalityClientConfiguration]): @overload def required_explicit( diff --git a/packages/typespec-python/test/unbranded/generated/parameters-body-optionality/parameters/bodyoptionality/_utils/__init__.py b/packages/typespec-python/test/unbranded/generated/parameters-body-optionality/parameters/bodyoptionality/_utils/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/packages/typespec-python/test/unbranded/generated/parameters-body-optionality/parameters/bodyoptionality/_model_base.py b/packages/typespec-python/test/unbranded/generated/parameters-body-optionality/parameters/bodyoptionality/_utils/model_base.py similarity index 100% rename from packages/typespec-python/test/unbranded/generated/parameters-body-optionality/parameters/bodyoptionality/_model_base.py rename to packages/typespec-python/test/unbranded/generated/parameters-body-optionality/parameters/bodyoptionality/_utils/model_base.py diff --git a/packages/typespec-python/test/unbranded/generated/parameters-body-optionality/parameters/bodyoptionality/_serialization.py b/packages/typespec-python/test/unbranded/generated/parameters-body-optionality/parameters/bodyoptionality/_utils/serialization.py similarity index 100% rename from packages/typespec-python/test/unbranded/generated/parameters-body-optionality/parameters/bodyoptionality/_serialization.py rename to packages/typespec-python/test/unbranded/generated/parameters-body-optionality/parameters/bodyoptionality/_utils/serialization.py diff --git a/packages/typespec-python/test/unbranded/generated/parameters-body-optionality/parameters/bodyoptionality/_utils/utils.py b/packages/typespec-python/test/unbranded/generated/parameters-body-optionality/parameters/bodyoptionality/_utils/utils.py new file mode 100644 index 00000000000..02aa2f816ea --- /dev/null +++ b/packages/typespec-python/test/unbranded/generated/parameters-body-optionality/parameters/bodyoptionality/_utils/utils.py @@ -0,0 +1,18 @@ +from abc import ABC +from typing import Generic, TYPE_CHECKING, TypeVar + +if TYPE_CHECKING: + from .serialization import Deserializer, Serializer + + +TClient = TypeVar("TClient") +TConfig = TypeVar("TConfig") + + +class ClientMixinABC(ABC, Generic[TClient, TConfig]): + """DO NOT use this class. It is for internal typing use only.""" + + _client: TClient + _config: TConfig + _serialize: "Serializer" + _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/unbranded/generated/parameters-body-optionality/parameters/bodyoptionality/_vendor.py b/packages/typespec-python/test/unbranded/generated/parameters-body-optionality/parameters/bodyoptionality/_vendor.py deleted file mode 100644 index fb875c07a39..00000000000 --- a/packages/typespec-python/test/unbranded/generated/parameters-body-optionality/parameters/bodyoptionality/_vendor.py +++ /dev/null @@ -1,18 +0,0 @@ -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import BodyOptionalityClientConfiguration - -if TYPE_CHECKING: - from corehttp.runtime import PipelineClient - - from ._serialization import Deserializer, Serializer - - -class BodyOptionalityClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "PipelineClient" - _config: BodyOptionalityClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/unbranded/generated/parameters-body-optionality/parameters/bodyoptionality/aio/_client.py b/packages/typespec-python/test/unbranded/generated/parameters-body-optionality/parameters/bodyoptionality/aio/_client.py index f63715d953a..7244b5011ab 100644 --- a/packages/typespec-python/test/unbranded/generated/parameters-body-optionality/parameters/bodyoptionality/aio/_client.py +++ b/packages/typespec-python/test/unbranded/generated/parameters-body-optionality/parameters/bodyoptionality/aio/_client.py @@ -7,7 +7,7 @@ from corehttp.rest import AsyncHttpResponse, HttpRequest from corehttp.runtime import AsyncPipelineClient, policies -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ..optionalexplicit.aio.operations import OptionalExplicitOperations from ._configuration import BodyOptionalityClientConfiguration from ._operations import BodyOptionalityClientOperationsMixin diff --git a/packages/typespec-python/test/unbranded/generated/parameters-body-optionality/parameters/bodyoptionality/aio/_operations/_operations.py b/packages/typespec-python/test/unbranded/generated/parameters-body-optionality/parameters/bodyoptionality/aio/_operations/_operations.py index 08eb564786b..c3e1c415dc5 100644 --- a/packages/typespec-python/test/unbranded/generated/parameters-body-optionality/parameters/bodyoptionality/aio/_operations/_operations.py +++ b/packages/typespec-python/test/unbranded/generated/parameters-body-optionality/parameters/bodyoptionality/aio/_operations/_operations.py @@ -13,16 +13,18 @@ map_error, ) from corehttp.rest import AsyncHttpResponse, HttpRequest +from corehttp.runtime import AsyncPipelineClient from corehttp.runtime.pipeline import PipelineResponse from corehttp.utils import case_insensitive_dict from ... import models as _models2 -from ..._model_base import SdkJSONEncoder from ..._operations._operations import ( build_body_optionality_required_explicit_request, build_body_optionality_required_implicit_request, ) -from .._vendor import BodyOptionalityClientMixinABC +from ..._utils.model_base import SdkJSONEncoder +from ..._utils.utils import ClientMixinABC +from .._configuration import BodyOptionalityClientConfiguration JSON = MutableMapping[str, Any] _Unset: Any = object() @@ -30,7 +32,7 @@ ClsType = Optional[Callable[[PipelineResponse[HttpRequest, AsyncHttpResponse], T, Dict[str, Any]], Any]] -class BodyOptionalityClientOperationsMixin(BodyOptionalityClientMixinABC): +class BodyOptionalityClientOperationsMixin(ClientMixinABC[AsyncPipelineClient, BodyOptionalityClientConfiguration]): @overload async def required_explicit( diff --git a/packages/typespec-python/test/unbranded/generated/parameters-body-optionality/parameters/bodyoptionality/aio/_vendor.py b/packages/typespec-python/test/unbranded/generated/parameters-body-optionality/parameters/bodyoptionality/aio/_vendor.py deleted file mode 100644 index 20977545af7..00000000000 --- a/packages/typespec-python/test/unbranded/generated/parameters-body-optionality/parameters/bodyoptionality/aio/_vendor.py +++ /dev/null @@ -1,18 +0,0 @@ -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import BodyOptionalityClientConfiguration - -if TYPE_CHECKING: - from corehttp.runtime import AsyncPipelineClient - - from .._serialization import Deserializer, Serializer - - -class BodyOptionalityClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "AsyncPipelineClient" - _config: BodyOptionalityClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/unbranded/generated/parameters-body-optionality/parameters/bodyoptionality/models/_models.py b/packages/typespec-python/test/unbranded/generated/parameters-body-optionality/parameters/bodyoptionality/models/_models.py index f8491da3201..9cdc33500e7 100644 --- a/packages/typespec-python/test/unbranded/generated/parameters-body-optionality/parameters/bodyoptionality/models/_models.py +++ b/packages/typespec-python/test/unbranded/generated/parameters-body-optionality/parameters/bodyoptionality/models/_models.py @@ -3,11 +3,10 @@ from typing import Any, Mapping, overload -from .. import _model_base -from .._model_base import rest_field +from .._utils.model_base import Model as _Model, rest_field -class BodyModel(_model_base.Model): +class BodyModel(_Model): """BodyModel. :ivar name: Required. diff --git a/packages/typespec-python/test/unbranded/generated/parameters-body-optionality/parameters/bodyoptionality/optionalexplicit/aio/operations/_operations.py b/packages/typespec-python/test/unbranded/generated/parameters-body-optionality/parameters/bodyoptionality/optionalexplicit/aio/operations/_operations.py index 8fc9b7a2b9d..5f14765fdd3 100644 --- a/packages/typespec-python/test/unbranded/generated/parameters-body-optionality/parameters/bodyoptionality/optionalexplicit/aio/operations/_operations.py +++ b/packages/typespec-python/test/unbranded/generated/parameters-body-optionality/parameters/bodyoptionality/optionalexplicit/aio/operations/_operations.py @@ -18,8 +18,8 @@ from corehttp.utils import case_insensitive_dict from .... import models as _models3 -from ...._model_base import SdkJSONEncoder -from ...._serialization import Deserializer, Serializer +from ...._utils.model_base import SdkJSONEncoder +from ...._utils.serialization import Deserializer, Serializer from ....aio._configuration import BodyOptionalityClientConfiguration from ...operations._operations import build_optional_explicit_omit_request, build_optional_explicit_set_request diff --git a/packages/typespec-python/test/unbranded/generated/parameters-body-optionality/parameters/bodyoptionality/optionalexplicit/operations/_operations.py b/packages/typespec-python/test/unbranded/generated/parameters-body-optionality/parameters/bodyoptionality/optionalexplicit/operations/_operations.py index 6036554b61b..6334f1aa120 100644 --- a/packages/typespec-python/test/unbranded/generated/parameters-body-optionality/parameters/bodyoptionality/optionalexplicit/operations/_operations.py +++ b/packages/typespec-python/test/unbranded/generated/parameters-body-optionality/parameters/bodyoptionality/optionalexplicit/operations/_operations.py @@ -19,8 +19,8 @@ from ... import models as _models2 from ..._configuration import BodyOptionalityClientConfiguration -from ..._model_base import SdkJSONEncoder -from ..._serialization import Deserializer, Serializer +from ..._utils.model_base import SdkJSONEncoder +from ..._utils.serialization import Deserializer, Serializer JSON = MutableMapping[str, Any] T = TypeVar("T") diff --git a/packages/typespec-python/test/unbranded/generated/parameters-collection-format/parameters/collectionformat/_client.py b/packages/typespec-python/test/unbranded/generated/parameters-collection-format/parameters/collectionformat/_client.py index a95933bce95..11a2623f9bb 100644 --- a/packages/typespec-python/test/unbranded/generated/parameters-collection-format/parameters/collectionformat/_client.py +++ b/packages/typespec-python/test/unbranded/generated/parameters-collection-format/parameters/collectionformat/_client.py @@ -8,7 +8,7 @@ from corehttp.runtime import PipelineClient, policies from ._configuration import CollectionFormatClientConfiguration -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer from .header.operations import HeaderOperations from .query.operations import QueryOperations diff --git a/packages/typespec-python/test/unbranded/generated/parameters-collection-format/parameters/collectionformat/_utils/__init__.py b/packages/typespec-python/test/unbranded/generated/parameters-collection-format/parameters/collectionformat/_utils/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/packages/typespec-python/test/unbranded/generated/parameters-collection-format/parameters/collectionformat/_model_base.py b/packages/typespec-python/test/unbranded/generated/parameters-collection-format/parameters/collectionformat/_utils/model_base.py similarity index 100% rename from packages/typespec-python/test/unbranded/generated/parameters-collection-format/parameters/collectionformat/_model_base.py rename to packages/typespec-python/test/unbranded/generated/parameters-collection-format/parameters/collectionformat/_utils/model_base.py diff --git a/packages/typespec-python/test/unbranded/generated/parameters-collection-format/parameters/collectionformat/_serialization.py b/packages/typespec-python/test/unbranded/generated/parameters-collection-format/parameters/collectionformat/_utils/serialization.py similarity index 100% rename from packages/typespec-python/test/unbranded/generated/parameters-collection-format/parameters/collectionformat/_serialization.py rename to packages/typespec-python/test/unbranded/generated/parameters-collection-format/parameters/collectionformat/_utils/serialization.py diff --git a/packages/typespec-python/test/unbranded/generated/parameters-collection-format/parameters/collectionformat/aio/_client.py b/packages/typespec-python/test/unbranded/generated/parameters-collection-format/parameters/collectionformat/aio/_client.py index 4bb85fdaf2c..e58a9c21575 100644 --- a/packages/typespec-python/test/unbranded/generated/parameters-collection-format/parameters/collectionformat/aio/_client.py +++ b/packages/typespec-python/test/unbranded/generated/parameters-collection-format/parameters/collectionformat/aio/_client.py @@ -7,7 +7,7 @@ from corehttp.rest import AsyncHttpResponse, HttpRequest from corehttp.runtime import AsyncPipelineClient, policies -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ..header.aio.operations import HeaderOperations from ..query.aio.operations import QueryOperations from ._configuration import CollectionFormatClientConfiguration diff --git a/packages/typespec-python/test/unbranded/generated/parameters-collection-format/parameters/collectionformat/header/aio/operations/_operations.py b/packages/typespec-python/test/unbranded/generated/parameters-collection-format/parameters/collectionformat/header/aio/operations/_operations.py index 2ebb3209bc1..f59ec2bec73 100644 --- a/packages/typespec-python/test/unbranded/generated/parameters-collection-format/parameters/collectionformat/header/aio/operations/_operations.py +++ b/packages/typespec-python/test/unbranded/generated/parameters-collection-format/parameters/collectionformat/header/aio/operations/_operations.py @@ -14,7 +14,7 @@ from corehttp.runtime import AsyncPipelineClient from corehttp.runtime.pipeline import PipelineResponse -from ...._serialization import Deserializer, Serializer +from ...._utils.serialization import Deserializer, Serializer from ....aio._configuration import CollectionFormatClientConfiguration from ...operations._operations import build_header_csv_request diff --git a/packages/typespec-python/test/unbranded/generated/parameters-collection-format/parameters/collectionformat/header/operations/_operations.py b/packages/typespec-python/test/unbranded/generated/parameters-collection-format/parameters/collectionformat/header/operations/_operations.py index dbf01037c5c..a5d536c40b9 100644 --- a/packages/typespec-python/test/unbranded/generated/parameters-collection-format/parameters/collectionformat/header/operations/_operations.py +++ b/packages/typespec-python/test/unbranded/generated/parameters-collection-format/parameters/collectionformat/header/operations/_operations.py @@ -16,7 +16,7 @@ from corehttp.utils import case_insensitive_dict from ..._configuration import CollectionFormatClientConfiguration -from ..._serialization import Deserializer, Serializer +from ..._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/typespec-python/test/unbranded/generated/parameters-collection-format/parameters/collectionformat/query/aio/operations/_operations.py b/packages/typespec-python/test/unbranded/generated/parameters-collection-format/parameters/collectionformat/query/aio/operations/_operations.py index 82048fa764f..a46ab7e6699 100644 --- a/packages/typespec-python/test/unbranded/generated/parameters-collection-format/parameters/collectionformat/query/aio/operations/_operations.py +++ b/packages/typespec-python/test/unbranded/generated/parameters-collection-format/parameters/collectionformat/query/aio/operations/_operations.py @@ -14,7 +14,7 @@ from corehttp.runtime import AsyncPipelineClient from corehttp.runtime.pipeline import PipelineResponse -from ...._serialization import Deserializer, Serializer +from ...._utils.serialization import Deserializer, Serializer from ....aio._configuration import CollectionFormatClientConfiguration from ...operations._operations import ( build_query_csv_request, diff --git a/packages/typespec-python/test/unbranded/generated/parameters-collection-format/parameters/collectionformat/query/operations/_operations.py b/packages/typespec-python/test/unbranded/generated/parameters-collection-format/parameters/collectionformat/query/operations/_operations.py index cf799396337..2bf73c9bcc3 100644 --- a/packages/typespec-python/test/unbranded/generated/parameters-collection-format/parameters/collectionformat/query/operations/_operations.py +++ b/packages/typespec-python/test/unbranded/generated/parameters-collection-format/parameters/collectionformat/query/operations/_operations.py @@ -16,7 +16,7 @@ from corehttp.utils import case_insensitive_dict from ..._configuration import CollectionFormatClientConfiguration -from ..._serialization import Deserializer, Serializer +from ..._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/typespec-python/test/unbranded/generated/parameters-path/parameters/path/_client.py b/packages/typespec-python/test/unbranded/generated/parameters-path/parameters/path/_client.py index c1d582d471d..c72b58a8fb8 100644 --- a/packages/typespec-python/test/unbranded/generated/parameters-path/parameters/path/_client.py +++ b/packages/typespec-python/test/unbranded/generated/parameters-path/parameters/path/_client.py @@ -9,7 +9,7 @@ from ._configuration import PathClientConfiguration from ._operations import PathClientOperationsMixin -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer class PathClient(PathClientOperationsMixin): # pylint: disable=client-accepts-api-version-keyword diff --git a/packages/typespec-python/test/unbranded/generated/parameters-path/parameters/path/_operations/_operations.py b/packages/typespec-python/test/unbranded/generated/parameters-path/parameters/path/_operations/_operations.py index 8d2afe8cb9c..2a849568084 100644 --- a/packages/typespec-python/test/unbranded/generated/parameters-path/parameters/path/_operations/_operations.py +++ b/packages/typespec-python/test/unbranded/generated/parameters-path/parameters/path/_operations/_operations.py @@ -11,10 +11,12 @@ map_error, ) from corehttp.rest import HttpRequest, HttpResponse +from corehttp.runtime import PipelineClient from corehttp.runtime.pipeline import PipelineResponse -from .._serialization import Serializer -from .._vendor import PathClientMixinABC +from .._configuration import PathClientConfiguration +from .._utils.serialization import Serializer +from .._utils.utils import ClientMixinABC T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] @@ -47,7 +49,7 @@ def build_path_optional_request(*, name: Optional[str] = None, **kwargs: Any) -> return HttpRequest(method="GET", url=_url, **kwargs) -class PathClientOperationsMixin(PathClientMixinABC): +class PathClientOperationsMixin(ClientMixinABC[PipelineClient, PathClientConfiguration]): def normal(self, name: str, **kwargs: Any) -> None: # pylint: disable=inconsistent-return-statements """normal. diff --git a/packages/typespec-python/test/unbranded/generated/parameters-path/parameters/path/_utils/__init__.py b/packages/typespec-python/test/unbranded/generated/parameters-path/parameters/path/_utils/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/packages/typespec-python/test/unbranded/generated/parameters-path/parameters/path/_model_base.py b/packages/typespec-python/test/unbranded/generated/parameters-path/parameters/path/_utils/model_base.py similarity index 100% rename from packages/typespec-python/test/unbranded/generated/parameters-path/parameters/path/_model_base.py rename to packages/typespec-python/test/unbranded/generated/parameters-path/parameters/path/_utils/model_base.py diff --git a/packages/typespec-python/test/unbranded/generated/parameters-path/parameters/path/_serialization.py b/packages/typespec-python/test/unbranded/generated/parameters-path/parameters/path/_utils/serialization.py similarity index 100% rename from packages/typespec-python/test/unbranded/generated/parameters-path/parameters/path/_serialization.py rename to packages/typespec-python/test/unbranded/generated/parameters-path/parameters/path/_utils/serialization.py diff --git a/packages/typespec-python/test/unbranded/generated/parameters-path/parameters/path/_utils/utils.py b/packages/typespec-python/test/unbranded/generated/parameters-path/parameters/path/_utils/utils.py new file mode 100644 index 00000000000..02aa2f816ea --- /dev/null +++ b/packages/typespec-python/test/unbranded/generated/parameters-path/parameters/path/_utils/utils.py @@ -0,0 +1,18 @@ +from abc import ABC +from typing import Generic, TYPE_CHECKING, TypeVar + +if TYPE_CHECKING: + from .serialization import Deserializer, Serializer + + +TClient = TypeVar("TClient") +TConfig = TypeVar("TConfig") + + +class ClientMixinABC(ABC, Generic[TClient, TConfig]): + """DO NOT use this class. It is for internal typing use only.""" + + _client: TClient + _config: TConfig + _serialize: "Serializer" + _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/unbranded/generated/parameters-path/parameters/path/_vendor.py b/packages/typespec-python/test/unbranded/generated/parameters-path/parameters/path/_vendor.py deleted file mode 100644 index 8a31b59a1ef..00000000000 --- a/packages/typespec-python/test/unbranded/generated/parameters-path/parameters/path/_vendor.py +++ /dev/null @@ -1,18 +0,0 @@ -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import PathClientConfiguration - -if TYPE_CHECKING: - from corehttp.runtime import PipelineClient - - from ._serialization import Deserializer, Serializer - - -class PathClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "PipelineClient" - _config: PathClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/unbranded/generated/parameters-path/parameters/path/aio/_client.py b/packages/typespec-python/test/unbranded/generated/parameters-path/parameters/path/aio/_client.py index 52b7d74c20e..e0a87814eb1 100644 --- a/packages/typespec-python/test/unbranded/generated/parameters-path/parameters/path/aio/_client.py +++ b/packages/typespec-python/test/unbranded/generated/parameters-path/parameters/path/aio/_client.py @@ -7,7 +7,7 @@ from corehttp.rest import AsyncHttpResponse, HttpRequest from corehttp.runtime import AsyncPipelineClient, policies -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import PathClientConfiguration from ._operations import PathClientOperationsMixin diff --git a/packages/typespec-python/test/unbranded/generated/parameters-path/parameters/path/aio/_operations/_operations.py b/packages/typespec-python/test/unbranded/generated/parameters-path/parameters/path/aio/_operations/_operations.py index 4fc66347426..8bb8ada4b7d 100644 --- a/packages/typespec-python/test/unbranded/generated/parameters-path/parameters/path/aio/_operations/_operations.py +++ b/packages/typespec-python/test/unbranded/generated/parameters-path/parameters/path/aio/_operations/_operations.py @@ -11,16 +11,18 @@ map_error, ) from corehttp.rest import AsyncHttpResponse, HttpRequest +from corehttp.runtime import AsyncPipelineClient from corehttp.runtime.pipeline import PipelineResponse from ..._operations._operations import build_path_normal_request, build_path_optional_request -from .._vendor import PathClientMixinABC +from ..._utils.utils import ClientMixinABC +from .._configuration import PathClientConfiguration T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, AsyncHttpResponse], T, Dict[str, Any]], Any]] -class PathClientOperationsMixin(PathClientMixinABC): +class PathClientOperationsMixin(ClientMixinABC[AsyncPipelineClient, PathClientConfiguration]): async def normal(self, name: str, **kwargs: Any) -> None: """normal. diff --git a/packages/typespec-python/test/unbranded/generated/parameters-path/parameters/path/aio/_vendor.py b/packages/typespec-python/test/unbranded/generated/parameters-path/parameters/path/aio/_vendor.py deleted file mode 100644 index a5607590621..00000000000 --- a/packages/typespec-python/test/unbranded/generated/parameters-path/parameters/path/aio/_vendor.py +++ /dev/null @@ -1,18 +0,0 @@ -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import PathClientConfiguration - -if TYPE_CHECKING: - from corehttp.runtime import AsyncPipelineClient - - from .._serialization import Deserializer, Serializer - - -class PathClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "AsyncPipelineClient" - _config: PathClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/unbranded/generated/parameters-spread/parameters/spread/_client.py b/packages/typespec-python/test/unbranded/generated/parameters-spread/parameters/spread/_client.py index d4a9157962b..65ea2614906 100644 --- a/packages/typespec-python/test/unbranded/generated/parameters-spread/parameters/spread/_client.py +++ b/packages/typespec-python/test/unbranded/generated/parameters-spread/parameters/spread/_client.py @@ -8,7 +8,7 @@ from corehttp.runtime import PipelineClient, policies from ._configuration import SpreadClientConfiguration -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer from .alias.operations import AliasOperations from .model.operations import ModelOperations diff --git a/packages/typespec-python/test/unbranded/generated/parameters-spread/parameters/spread/_utils/__init__.py b/packages/typespec-python/test/unbranded/generated/parameters-spread/parameters/spread/_utils/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/packages/typespec-python/test/unbranded/generated/parameters-spread/parameters/spread/_model_base.py b/packages/typespec-python/test/unbranded/generated/parameters-spread/parameters/spread/_utils/model_base.py similarity index 100% rename from packages/typespec-python/test/unbranded/generated/parameters-spread/parameters/spread/_model_base.py rename to packages/typespec-python/test/unbranded/generated/parameters-spread/parameters/spread/_utils/model_base.py diff --git a/packages/typespec-python/test/unbranded/generated/parameters-spread/parameters/spread/_serialization.py b/packages/typespec-python/test/unbranded/generated/parameters-spread/parameters/spread/_utils/serialization.py similarity index 100% rename from packages/typespec-python/test/unbranded/generated/parameters-spread/parameters/spread/_serialization.py rename to packages/typespec-python/test/unbranded/generated/parameters-spread/parameters/spread/_utils/serialization.py diff --git a/packages/typespec-python/test/unbranded/generated/parameters-spread/parameters/spread/aio/_client.py b/packages/typespec-python/test/unbranded/generated/parameters-spread/parameters/spread/aio/_client.py index 6c462d7ad3a..fd96b553be6 100644 --- a/packages/typespec-python/test/unbranded/generated/parameters-spread/parameters/spread/aio/_client.py +++ b/packages/typespec-python/test/unbranded/generated/parameters-spread/parameters/spread/aio/_client.py @@ -7,7 +7,7 @@ from corehttp.rest import AsyncHttpResponse, HttpRequest from corehttp.runtime import AsyncPipelineClient, policies -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ..alias.aio.operations import AliasOperations from ..model.aio.operations import ModelOperations from ._configuration import SpreadClientConfiguration diff --git a/packages/typespec-python/test/unbranded/generated/parameters-spread/parameters/spread/alias/aio/operations/_operations.py b/packages/typespec-python/test/unbranded/generated/parameters-spread/parameters/spread/alias/aio/operations/_operations.py index ac07386f368..f06e06d2379 100644 --- a/packages/typespec-python/test/unbranded/generated/parameters-spread/parameters/spread/alias/aio/operations/_operations.py +++ b/packages/typespec-python/test/unbranded/generated/parameters-spread/parameters/spread/alias/aio/operations/_operations.py @@ -17,8 +17,8 @@ from corehttp.runtime.pipeline import PipelineResponse from corehttp.utils import case_insensitive_dict -from ...._model_base import SdkJSONEncoder -from ...._serialization import Deserializer, Serializer +from ...._utils.model_base import SdkJSONEncoder +from ...._utils.serialization import Deserializer, Serializer from ....aio._configuration import SpreadClientConfiguration from ...operations._operations import ( build_alias_spread_as_request_body_request, diff --git a/packages/typespec-python/test/unbranded/generated/parameters-spread/parameters/spread/alias/operations/_operations.py b/packages/typespec-python/test/unbranded/generated/parameters-spread/parameters/spread/alias/operations/_operations.py index b020b9cf210..dedc7d159c3 100644 --- a/packages/typespec-python/test/unbranded/generated/parameters-spread/parameters/spread/alias/operations/_operations.py +++ b/packages/typespec-python/test/unbranded/generated/parameters-spread/parameters/spread/alias/operations/_operations.py @@ -18,8 +18,8 @@ from corehttp.utils import case_insensitive_dict from ..._configuration import SpreadClientConfiguration -from ..._model_base import SdkJSONEncoder -from ..._serialization import Deserializer, Serializer +from ..._utils.model_base import SdkJSONEncoder +from ..._utils.serialization import Deserializer, Serializer JSON = MutableMapping[str, Any] _Unset: Any = object() diff --git a/packages/typespec-python/test/unbranded/generated/parameters-spread/parameters/spread/model/aio/operations/_operations.py b/packages/typespec-python/test/unbranded/generated/parameters-spread/parameters/spread/model/aio/operations/_operations.py index 2b0c3371b45..40936e4979c 100644 --- a/packages/typespec-python/test/unbranded/generated/parameters-spread/parameters/spread/model/aio/operations/_operations.py +++ b/packages/typespec-python/test/unbranded/generated/parameters-spread/parameters/spread/model/aio/operations/_operations.py @@ -18,8 +18,8 @@ from corehttp.utils import case_insensitive_dict from ... import models as _models2 -from ...._model_base import SdkJSONEncoder -from ...._serialization import Deserializer, Serializer +from ...._utils.model_base import SdkJSONEncoder +from ...._utils.serialization import Deserializer, Serializer from ....aio._configuration import SpreadClientConfiguration from ...operations._operations import ( build_model_spread_as_request_body_request, diff --git a/packages/typespec-python/test/unbranded/generated/parameters-spread/parameters/spread/model/models/_models.py b/packages/typespec-python/test/unbranded/generated/parameters-spread/parameters/spread/model/models/_models.py index 987e1214cb8..fe299db67e3 100644 --- a/packages/typespec-python/test/unbranded/generated/parameters-spread/parameters/spread/model/models/_models.py +++ b/packages/typespec-python/test/unbranded/generated/parameters-spread/parameters/spread/model/models/_models.py @@ -3,11 +3,10 @@ from typing import Any, Mapping, overload -from ... import _model_base -from ..._model_base import rest_field +from ..._utils.model_base import Model as _Model, rest_field -class BodyParameter(_model_base.Model): +class BodyParameter(_Model): """This is a simple model. :ivar name: Required. diff --git a/packages/typespec-python/test/unbranded/generated/parameters-spread/parameters/spread/model/operations/_operations.py b/packages/typespec-python/test/unbranded/generated/parameters-spread/parameters/spread/model/operations/_operations.py index 31a5c278c3d..cd9bceaec23 100644 --- a/packages/typespec-python/test/unbranded/generated/parameters-spread/parameters/spread/model/operations/_operations.py +++ b/packages/typespec-python/test/unbranded/generated/parameters-spread/parameters/spread/model/operations/_operations.py @@ -19,8 +19,8 @@ from .. import models as _models1 from ..._configuration import SpreadClientConfiguration -from ..._model_base import SdkJSONEncoder -from ..._serialization import Deserializer, Serializer +from ..._utils.model_base import SdkJSONEncoder +from ..._utils.serialization import Deserializer, Serializer JSON = MutableMapping[str, Any] _Unset: Any = object() diff --git a/packages/typespec-python/test/unbranded/generated/payload-content-negotiation/payload/contentnegotiation/_client.py b/packages/typespec-python/test/unbranded/generated/payload-content-negotiation/payload/contentnegotiation/_client.py index 3fdb5344804..3dc6c6dc511 100644 --- a/packages/typespec-python/test/unbranded/generated/payload-content-negotiation/payload/contentnegotiation/_client.py +++ b/packages/typespec-python/test/unbranded/generated/payload-content-negotiation/payload/contentnegotiation/_client.py @@ -8,7 +8,7 @@ from corehttp.runtime import PipelineClient, policies from ._configuration import ContentNegotiationClientConfiguration -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer from .differentbody.operations import DifferentBodyOperations from .samebody.operations import SameBodyOperations diff --git a/packages/typespec-python/test/unbranded/generated/payload-content-negotiation/payload/contentnegotiation/_utils/__init__.py b/packages/typespec-python/test/unbranded/generated/payload-content-negotiation/payload/contentnegotiation/_utils/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/packages/typespec-python/test/unbranded/generated/payload-content-negotiation/payload/contentnegotiation/_model_base.py b/packages/typespec-python/test/unbranded/generated/payload-content-negotiation/payload/contentnegotiation/_utils/model_base.py similarity index 100% rename from packages/typespec-python/test/unbranded/generated/payload-content-negotiation/payload/contentnegotiation/_model_base.py rename to packages/typespec-python/test/unbranded/generated/payload-content-negotiation/payload/contentnegotiation/_utils/model_base.py diff --git a/packages/typespec-python/test/unbranded/generated/payload-content-negotiation/payload/contentnegotiation/_serialization.py b/packages/typespec-python/test/unbranded/generated/payload-content-negotiation/payload/contentnegotiation/_utils/serialization.py similarity index 100% rename from packages/typespec-python/test/unbranded/generated/payload-content-negotiation/payload/contentnegotiation/_serialization.py rename to packages/typespec-python/test/unbranded/generated/payload-content-negotiation/payload/contentnegotiation/_utils/serialization.py diff --git a/packages/typespec-python/test/unbranded/generated/payload-content-negotiation/payload/contentnegotiation/aio/_client.py b/packages/typespec-python/test/unbranded/generated/payload-content-negotiation/payload/contentnegotiation/aio/_client.py index 94b1810769a..46f3edf4408 100644 --- a/packages/typespec-python/test/unbranded/generated/payload-content-negotiation/payload/contentnegotiation/aio/_client.py +++ b/packages/typespec-python/test/unbranded/generated/payload-content-negotiation/payload/contentnegotiation/aio/_client.py @@ -7,7 +7,7 @@ from corehttp.rest import AsyncHttpResponse, HttpRequest from corehttp.runtime import AsyncPipelineClient, policies -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ..differentbody.aio.operations import DifferentBodyOperations from ..samebody.aio.operations import SameBodyOperations from ._configuration import ContentNegotiationClientConfiguration diff --git a/packages/typespec-python/test/unbranded/generated/payload-content-negotiation/payload/contentnegotiation/differentbody/aio/operations/_operations.py b/packages/typespec-python/test/unbranded/generated/payload-content-negotiation/payload/contentnegotiation/differentbody/aio/operations/_operations.py index 1254e3ec95f..4466631aabe 100644 --- a/packages/typespec-python/test/unbranded/generated/payload-content-negotiation/payload/contentnegotiation/differentbody/aio/operations/_operations.py +++ b/packages/typespec-python/test/unbranded/generated/payload-content-negotiation/payload/contentnegotiation/differentbody/aio/operations/_operations.py @@ -18,8 +18,8 @@ from corehttp.utils import case_insensitive_dict from ... import models as _models2 -from ...._model_base import _deserialize -from ...._serialization import Deserializer, Serializer +from ...._utils.model_base import _deserialize +from ...._utils.serialization import Deserializer, Serializer from ....aio._configuration import ContentNegotiationClientConfiguration from ...operations._operations import ( build_different_body_get_avatar_as_json_request, diff --git a/packages/typespec-python/test/unbranded/generated/payload-content-negotiation/payload/contentnegotiation/differentbody/models/_models.py b/packages/typespec-python/test/unbranded/generated/payload-content-negotiation/payload/contentnegotiation/differentbody/models/_models.py index 67fc3da8c4e..60eacb31f90 100644 --- a/packages/typespec-python/test/unbranded/generated/payload-content-negotiation/payload/contentnegotiation/differentbody/models/_models.py +++ b/packages/typespec-python/test/unbranded/generated/payload-content-negotiation/payload/contentnegotiation/differentbody/models/_models.py @@ -3,11 +3,10 @@ from typing import Any, Mapping, overload -from ... import _model_base -from ..._model_base import rest_field +from ..._utils.model_base import Model as _Model, rest_field -class PngImageAsJson(_model_base.Model): +class PngImageAsJson(_Model): """PngImageAsJson. :ivar content: Required. diff --git a/packages/typespec-python/test/unbranded/generated/payload-content-negotiation/payload/contentnegotiation/differentbody/operations/_operations.py b/packages/typespec-python/test/unbranded/generated/payload-content-negotiation/payload/contentnegotiation/differentbody/operations/_operations.py index 22053099db1..c4d16818686 100644 --- a/packages/typespec-python/test/unbranded/generated/payload-content-negotiation/payload/contentnegotiation/differentbody/operations/_operations.py +++ b/packages/typespec-python/test/unbranded/generated/payload-content-negotiation/payload/contentnegotiation/differentbody/operations/_operations.py @@ -19,8 +19,8 @@ from .. import models as _models1 from ..._configuration import ContentNegotiationClientConfiguration -from ..._model_base import _deserialize -from ..._serialization import Deserializer, Serializer +from ..._utils.model_base import _deserialize +from ..._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/typespec-python/test/unbranded/generated/payload-content-negotiation/payload/contentnegotiation/samebody/aio/operations/_operations.py b/packages/typespec-python/test/unbranded/generated/payload-content-negotiation/payload/contentnegotiation/samebody/aio/operations/_operations.py index c0d720df7de..4cdbde26b42 100644 --- a/packages/typespec-python/test/unbranded/generated/payload-content-negotiation/payload/contentnegotiation/samebody/aio/operations/_operations.py +++ b/packages/typespec-python/test/unbranded/generated/payload-content-negotiation/payload/contentnegotiation/samebody/aio/operations/_operations.py @@ -17,7 +17,7 @@ from corehttp.runtime.pipeline import PipelineResponse from corehttp.utils import case_insensitive_dict -from ...._serialization import Deserializer, Serializer +from ...._utils.serialization import Deserializer, Serializer from ....aio._configuration import ContentNegotiationClientConfiguration from ...operations._operations import ( build_same_body_get_avatar_as_jpeg_request, diff --git a/packages/typespec-python/test/unbranded/generated/payload-content-negotiation/payload/contentnegotiation/samebody/operations/_operations.py b/packages/typespec-python/test/unbranded/generated/payload-content-negotiation/payload/contentnegotiation/samebody/operations/_operations.py index c59d4a732e6..b95cd746a7e 100644 --- a/packages/typespec-python/test/unbranded/generated/payload-content-negotiation/payload/contentnegotiation/samebody/operations/_operations.py +++ b/packages/typespec-python/test/unbranded/generated/payload-content-negotiation/payload/contentnegotiation/samebody/operations/_operations.py @@ -18,7 +18,7 @@ from corehttp.utils import case_insensitive_dict from ..._configuration import ContentNegotiationClientConfiguration -from ..._serialization import Deserializer, Serializer +from ..._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/typespec-python/test/unbranded/generated/payload-json-merge-patch/payload/jsonmergepatch/_client.py b/packages/typespec-python/test/unbranded/generated/payload-json-merge-patch/payload/jsonmergepatch/_client.py index b66a3ba7b90..8631f6e82d4 100644 --- a/packages/typespec-python/test/unbranded/generated/payload-json-merge-patch/payload/jsonmergepatch/_client.py +++ b/packages/typespec-python/test/unbranded/generated/payload-json-merge-patch/payload/jsonmergepatch/_client.py @@ -9,7 +9,7 @@ from ._configuration import JsonMergePatchClientConfiguration from ._operations import JsonMergePatchClientOperationsMixin -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer class JsonMergePatchClient(JsonMergePatchClientOperationsMixin): # pylint: disable=client-accepts-api-version-keyword diff --git a/packages/typespec-python/test/unbranded/generated/payload-json-merge-patch/payload/jsonmergepatch/_operations/_operations.py b/packages/typespec-python/test/unbranded/generated/payload-json-merge-patch/payload/jsonmergepatch/_operations/_operations.py index d784035f75d..1aa2a77aa86 100644 --- a/packages/typespec-python/test/unbranded/generated/payload-json-merge-patch/payload/jsonmergepatch/_operations/_operations.py +++ b/packages/typespec-python/test/unbranded/generated/payload-json-merge-patch/payload/jsonmergepatch/_operations/_operations.py @@ -15,13 +15,15 @@ map_error, ) from corehttp.rest import HttpRequest, HttpResponse +from corehttp.runtime import PipelineClient from corehttp.runtime.pipeline import PipelineResponse from corehttp.utils import case_insensitive_dict from .. import models as _models -from .._model_base import SdkJSONEncoder, _deserialize -from .._serialization import Serializer -from .._vendor import JsonMergePatchClientMixinABC +from .._configuration import JsonMergePatchClientConfiguration +from .._utils.model_base import SdkJSONEncoder, _deserialize +from .._utils.serialization import Serializer +from .._utils.utils import ClientMixinABC JSON = MutableMapping[str, Any] T = TypeVar("T") @@ -84,7 +86,7 @@ def build_json_merge_patch_update_optional_resource_request( # pylint: disable= return HttpRequest(method="PATCH", url=_url, headers=_headers, **kwargs) -class JsonMergePatchClientOperationsMixin(JsonMergePatchClientMixinABC): +class JsonMergePatchClientOperationsMixin(ClientMixinABC[PipelineClient, JsonMergePatchClientConfiguration]): @overload def create_resource( diff --git a/packages/typespec-python/test/unbranded/generated/payload-json-merge-patch/payload/jsonmergepatch/_utils/__init__.py b/packages/typespec-python/test/unbranded/generated/payload-json-merge-patch/payload/jsonmergepatch/_utils/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/packages/typespec-python/test/unbranded/generated/payload-json-merge-patch/payload/jsonmergepatch/_model_base.py b/packages/typespec-python/test/unbranded/generated/payload-json-merge-patch/payload/jsonmergepatch/_utils/model_base.py similarity index 100% rename from packages/typespec-python/test/unbranded/generated/payload-json-merge-patch/payload/jsonmergepatch/_model_base.py rename to packages/typespec-python/test/unbranded/generated/payload-json-merge-patch/payload/jsonmergepatch/_utils/model_base.py diff --git a/packages/typespec-python/test/unbranded/generated/payload-json-merge-patch/payload/jsonmergepatch/_serialization.py b/packages/typespec-python/test/unbranded/generated/payload-json-merge-patch/payload/jsonmergepatch/_utils/serialization.py similarity index 100% rename from packages/typespec-python/test/unbranded/generated/payload-json-merge-patch/payload/jsonmergepatch/_serialization.py rename to packages/typespec-python/test/unbranded/generated/payload-json-merge-patch/payload/jsonmergepatch/_utils/serialization.py diff --git a/packages/typespec-python/test/unbranded/generated/payload-json-merge-patch/payload/jsonmergepatch/_utils/utils.py b/packages/typespec-python/test/unbranded/generated/payload-json-merge-patch/payload/jsonmergepatch/_utils/utils.py new file mode 100644 index 00000000000..02aa2f816ea --- /dev/null +++ b/packages/typespec-python/test/unbranded/generated/payload-json-merge-patch/payload/jsonmergepatch/_utils/utils.py @@ -0,0 +1,18 @@ +from abc import ABC +from typing import Generic, TYPE_CHECKING, TypeVar + +if TYPE_CHECKING: + from .serialization import Deserializer, Serializer + + +TClient = TypeVar("TClient") +TConfig = TypeVar("TConfig") + + +class ClientMixinABC(ABC, Generic[TClient, TConfig]): + """DO NOT use this class. It is for internal typing use only.""" + + _client: TClient + _config: TConfig + _serialize: "Serializer" + _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/unbranded/generated/payload-json-merge-patch/payload/jsonmergepatch/_vendor.py b/packages/typespec-python/test/unbranded/generated/payload-json-merge-patch/payload/jsonmergepatch/_vendor.py deleted file mode 100644 index 8bed8022867..00000000000 --- a/packages/typespec-python/test/unbranded/generated/payload-json-merge-patch/payload/jsonmergepatch/_vendor.py +++ /dev/null @@ -1,18 +0,0 @@ -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import JsonMergePatchClientConfiguration - -if TYPE_CHECKING: - from corehttp.runtime import PipelineClient - - from ._serialization import Deserializer, Serializer - - -class JsonMergePatchClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "PipelineClient" - _config: JsonMergePatchClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/unbranded/generated/payload-json-merge-patch/payload/jsonmergepatch/aio/_client.py b/packages/typespec-python/test/unbranded/generated/payload-json-merge-patch/payload/jsonmergepatch/aio/_client.py index a21727f9f00..08ddddcb63e 100644 --- a/packages/typespec-python/test/unbranded/generated/payload-json-merge-patch/payload/jsonmergepatch/aio/_client.py +++ b/packages/typespec-python/test/unbranded/generated/payload-json-merge-patch/payload/jsonmergepatch/aio/_client.py @@ -7,7 +7,7 @@ from corehttp.rest import AsyncHttpResponse, HttpRequest from corehttp.runtime import AsyncPipelineClient, policies -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import JsonMergePatchClientConfiguration from ._operations import JsonMergePatchClientOperationsMixin diff --git a/packages/typespec-python/test/unbranded/generated/payload-json-merge-patch/payload/jsonmergepatch/aio/_operations/_operations.py b/packages/typespec-python/test/unbranded/generated/payload-json-merge-patch/payload/jsonmergepatch/aio/_operations/_operations.py index b0bb300828e..1f86384131a 100644 --- a/packages/typespec-python/test/unbranded/generated/payload-json-merge-patch/payload/jsonmergepatch/aio/_operations/_operations.py +++ b/packages/typespec-python/test/unbranded/generated/payload-json-merge-patch/payload/jsonmergepatch/aio/_operations/_operations.py @@ -15,24 +15,26 @@ map_error, ) from corehttp.rest import AsyncHttpResponse, HttpRequest +from corehttp.runtime import AsyncPipelineClient from corehttp.runtime.pipeline import PipelineResponse from corehttp.utils import case_insensitive_dict from ... import models as _models -from ..._model_base import SdkJSONEncoder, _deserialize from ..._operations._operations import ( build_json_merge_patch_create_resource_request, build_json_merge_patch_update_optional_resource_request, build_json_merge_patch_update_resource_request, ) -from .._vendor import JsonMergePatchClientMixinABC +from ..._utils.model_base import SdkJSONEncoder, _deserialize +from ..._utils.utils import ClientMixinABC +from .._configuration import JsonMergePatchClientConfiguration JSON = MutableMapping[str, Any] T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, AsyncHttpResponse], T, Dict[str, Any]], Any]] -class JsonMergePatchClientOperationsMixin(JsonMergePatchClientMixinABC): +class JsonMergePatchClientOperationsMixin(ClientMixinABC[AsyncPipelineClient, JsonMergePatchClientConfiguration]): @overload async def create_resource( diff --git a/packages/typespec-python/test/unbranded/generated/payload-json-merge-patch/payload/jsonmergepatch/aio/_vendor.py b/packages/typespec-python/test/unbranded/generated/payload-json-merge-patch/payload/jsonmergepatch/aio/_vendor.py deleted file mode 100644 index 8326da40b0d..00000000000 --- a/packages/typespec-python/test/unbranded/generated/payload-json-merge-patch/payload/jsonmergepatch/aio/_vendor.py +++ /dev/null @@ -1,18 +0,0 @@ -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import JsonMergePatchClientConfiguration - -if TYPE_CHECKING: - from corehttp.runtime import AsyncPipelineClient - - from .._serialization import Deserializer, Serializer - - -class JsonMergePatchClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "AsyncPipelineClient" - _config: JsonMergePatchClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/unbranded/generated/payload-json-merge-patch/payload/jsonmergepatch/models/_models.py b/packages/typespec-python/test/unbranded/generated/payload-json-merge-patch/payload/jsonmergepatch/models/_models.py index 9877ae766a1..c46db84c35a 100644 --- a/packages/typespec-python/test/unbranded/generated/payload-json-merge-patch/payload/jsonmergepatch/models/_models.py +++ b/packages/typespec-python/test/unbranded/generated/payload-json-merge-patch/payload/jsonmergepatch/models/_models.py @@ -3,14 +3,13 @@ from typing import Any, Dict, List, Mapping, Optional, TYPE_CHECKING, overload -from .. import _model_base -from .._model_base import rest_field +from .._utils.model_base import Model as _Model, rest_field if TYPE_CHECKING: from .. import models as _models -class InnerModel(_model_base.Model): +class InnerModel(_Model): """It is the model used by Resource model. :ivar name: @@ -41,7 +40,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class Resource(_model_base.Model): +class Resource(_Model): """Details about a resource. :ivar name: Required. @@ -105,7 +104,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class ResourcePatch(_model_base.Model): +class ResourcePatch(_Model): """Details about a resource for patch operation. :ivar description: diff --git a/packages/typespec-python/test/unbranded/generated/payload-media-type/payload/mediatype/_client.py b/packages/typespec-python/test/unbranded/generated/payload-media-type/payload/mediatype/_client.py index 963c7047908..90dadced1c4 100644 --- a/packages/typespec-python/test/unbranded/generated/payload-media-type/payload/mediatype/_client.py +++ b/packages/typespec-python/test/unbranded/generated/payload-media-type/payload/mediatype/_client.py @@ -8,7 +8,7 @@ from corehttp.runtime import PipelineClient, policies from ._configuration import MediaTypeClientConfiguration -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer from .stringbody.operations import StringBodyOperations diff --git a/packages/typespec-python/test/unbranded/generated/payload-media-type/payload/mediatype/_utils/__init__.py b/packages/typespec-python/test/unbranded/generated/payload-media-type/payload/mediatype/_utils/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/packages/typespec-python/test/unbranded/generated/payload-media-type/payload/mediatype/_model_base.py b/packages/typespec-python/test/unbranded/generated/payload-media-type/payload/mediatype/_utils/model_base.py similarity index 100% rename from packages/typespec-python/test/unbranded/generated/payload-media-type/payload/mediatype/_model_base.py rename to packages/typespec-python/test/unbranded/generated/payload-media-type/payload/mediatype/_utils/model_base.py diff --git a/packages/typespec-python/test/unbranded/generated/payload-media-type/payload/mediatype/_serialization.py b/packages/typespec-python/test/unbranded/generated/payload-media-type/payload/mediatype/_utils/serialization.py similarity index 100% rename from packages/typespec-python/test/unbranded/generated/payload-media-type/payload/mediatype/_serialization.py rename to packages/typespec-python/test/unbranded/generated/payload-media-type/payload/mediatype/_utils/serialization.py diff --git a/packages/typespec-python/test/unbranded/generated/payload-media-type/payload/mediatype/aio/_client.py b/packages/typespec-python/test/unbranded/generated/payload-media-type/payload/mediatype/aio/_client.py index fe2e7558049..f35d7df40b0 100644 --- a/packages/typespec-python/test/unbranded/generated/payload-media-type/payload/mediatype/aio/_client.py +++ b/packages/typespec-python/test/unbranded/generated/payload-media-type/payload/mediatype/aio/_client.py @@ -7,7 +7,7 @@ from corehttp.rest import AsyncHttpResponse, HttpRequest from corehttp.runtime import AsyncPipelineClient, policies -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ..stringbody.aio.operations import StringBodyOperations from ._configuration import MediaTypeClientConfiguration diff --git a/packages/typespec-python/test/unbranded/generated/payload-media-type/payload/mediatype/stringbody/aio/operations/_operations.py b/packages/typespec-python/test/unbranded/generated/payload-media-type/payload/mediatype/stringbody/aio/operations/_operations.py index bd41ae60b29..dfc1510c9b4 100644 --- a/packages/typespec-python/test/unbranded/generated/payload-media-type/payload/mediatype/stringbody/aio/operations/_operations.py +++ b/packages/typespec-python/test/unbranded/generated/payload-media-type/payload/mediatype/stringbody/aio/operations/_operations.py @@ -18,8 +18,8 @@ from corehttp.runtime.pipeline import PipelineResponse from corehttp.utils import case_insensitive_dict -from ...._model_base import SdkJSONEncoder, _deserialize -from ...._serialization import Deserializer, Serializer +from ...._utils.model_base import SdkJSONEncoder, _deserialize +from ...._utils.serialization import Deserializer, Serializer from ....aio._configuration import MediaTypeClientConfiguration from ...operations._operations import ( build_string_body_get_as_json_request, diff --git a/packages/typespec-python/test/unbranded/generated/payload-media-type/payload/mediatype/stringbody/operations/_operations.py b/packages/typespec-python/test/unbranded/generated/payload-media-type/payload/mediatype/stringbody/operations/_operations.py index 3998b6dce05..f73dee6348b 100644 --- a/packages/typespec-python/test/unbranded/generated/payload-media-type/payload/mediatype/stringbody/operations/_operations.py +++ b/packages/typespec-python/test/unbranded/generated/payload-media-type/payload/mediatype/stringbody/operations/_operations.py @@ -19,8 +19,8 @@ from corehttp.utils import case_insensitive_dict from ..._configuration import MediaTypeClientConfiguration -from ..._model_base import SdkJSONEncoder, _deserialize -from ..._serialization import Deserializer, Serializer +from ..._utils.model_base import SdkJSONEncoder, _deserialize +from ..._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/typespec-python/test/unbranded/generated/payload-multipart/payload/multipart/_client.py b/packages/typespec-python/test/unbranded/generated/payload-multipart/payload/multipart/_client.py index 575448c6ef4..6ea2b329dbc 100644 --- a/packages/typespec-python/test/unbranded/generated/payload-multipart/payload/multipart/_client.py +++ b/packages/typespec-python/test/unbranded/generated/payload-multipart/payload/multipart/_client.py @@ -8,7 +8,7 @@ from corehttp.runtime import PipelineClient, policies from ._configuration import MultiPartClientConfiguration -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer from .formdata.operations import FormDataOperations diff --git a/packages/typespec-python/test/unbranded/generated/payload-multipart/payload/multipart/_utils/__init__.py b/packages/typespec-python/test/unbranded/generated/payload-multipart/payload/multipart/_utils/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/packages/typespec-python/test/unbranded/generated/payload-multipart/payload/multipart/_model_base.py b/packages/typespec-python/test/unbranded/generated/payload-multipart/payload/multipart/_utils/model_base.py similarity index 100% rename from packages/typespec-python/test/unbranded/generated/payload-multipart/payload/multipart/_model_base.py rename to packages/typespec-python/test/unbranded/generated/payload-multipart/payload/multipart/_utils/model_base.py diff --git a/packages/typespec-python/test/unbranded/generated/payload-multipart/payload/multipart/_serialization.py b/packages/typespec-python/test/unbranded/generated/payload-multipart/payload/multipart/_utils/serialization.py similarity index 100% rename from packages/typespec-python/test/unbranded/generated/payload-multipart/payload/multipart/_serialization.py rename to packages/typespec-python/test/unbranded/generated/payload-multipart/payload/multipart/_utils/serialization.py diff --git a/packages/typespec-python/test/unbranded/generated/payload-multipart/payload/multipart/_utils/utils.py b/packages/typespec-python/test/unbranded/generated/payload-multipart/payload/multipart/_utils/utils.py new file mode 100644 index 00000000000..f73524c7be8 --- /dev/null +++ b/packages/typespec-python/test/unbranded/generated/payload-multipart/payload/multipart/_utils/utils.py @@ -0,0 +1,43 @@ +import json +from typing import Any, Dict, IO, List, Mapping, Optional, Tuple, Union + +from .._utils.model_base import Model, SdkJSONEncoder + + +# file-like tuple could be `(filename, IO (or bytes))` or `(filename, IO (or bytes), content_type)` +FileContent = Union[str, bytes, IO[str], IO[bytes]] + +FileType = Union[ + # file (or bytes) + FileContent, + # (filename, file (or bytes)) + Tuple[Optional[str], FileContent], + # (filename, file (or bytes), content_type) + Tuple[Optional[str], FileContent, Optional[str]], +] + + +def serialize_multipart_data_entry(data_entry: Any) -> Any: + if isinstance(data_entry, (list, tuple, dict, Model)): + return json.dumps(data_entry, cls=SdkJSONEncoder, exclude_readonly=True) + return data_entry + + +def prepare_multipart_form_data( + body: Mapping[str, Any], multipart_fields: List[str], data_fields: List[str] +) -> Tuple[List[FileType], Dict[str, Any]]: + files: List[FileType] = [] + data: Dict[str, Any] = {} + for multipart_field in multipart_fields: + multipart_entry = body.get(multipart_field) + if isinstance(multipart_entry, list): + files.extend([(multipart_field, e) for e in multipart_entry]) + elif multipart_entry: + files.append((multipart_field, multipart_entry)) + + for data_field in data_fields: + data_entry = body.get(data_field) + if data_entry: + data[data_field] = serialize_multipart_data_entry(data_entry) + + return files, data diff --git a/packages/typespec-python/test/unbranded/generated/payload-multipart/payload/multipart/_vendor.py b/packages/typespec-python/test/unbranded/generated/payload-multipart/payload/multipart/_vendor.py deleted file mode 100644 index 2c8542749d8..00000000000 --- a/packages/typespec-python/test/unbranded/generated/payload-multipart/payload/multipart/_vendor.py +++ /dev/null @@ -1,43 +0,0 @@ -import json -from typing import Any, Dict, IO, List, Mapping, Optional, Tuple, Union - -from ._model_base import Model, SdkJSONEncoder - - -# file-like tuple could be `(filename, IO (or bytes))` or `(filename, IO (or bytes), content_type)` -FileContent = Union[str, bytes, IO[str], IO[bytes]] - -FileType = Union[ - # file (or bytes) - FileContent, - # (filename, file (or bytes)) - Tuple[Optional[str], FileContent], - # (filename, file (or bytes), content_type) - Tuple[Optional[str], FileContent, Optional[str]], -] - - -def serialize_multipart_data_entry(data_entry: Any) -> Any: - if isinstance(data_entry, (list, tuple, dict, Model)): - return json.dumps(data_entry, cls=SdkJSONEncoder, exclude_readonly=True) - return data_entry - - -def prepare_multipart_form_data( - body: Mapping[str, Any], multipart_fields: List[str], data_fields: List[str] -) -> Tuple[List[FileType], Dict[str, Any]]: - files: List[FileType] = [] - data: Dict[str, Any] = {} - for multipart_field in multipart_fields: - multipart_entry = body.get(multipart_field) - if isinstance(multipart_entry, list): - files.extend([(multipart_field, e) for e in multipart_entry]) - elif multipart_entry: - files.append((multipart_field, multipart_entry)) - - for data_field in data_fields: - data_entry = body.get(data_field) - if data_entry: - data[data_field] = serialize_multipart_data_entry(data_entry) - - return files, data diff --git a/packages/typespec-python/test/unbranded/generated/payload-multipart/payload/multipart/aio/_client.py b/packages/typespec-python/test/unbranded/generated/payload-multipart/payload/multipart/aio/_client.py index e5e0ba6b4b8..cfc5b1fe28b 100644 --- a/packages/typespec-python/test/unbranded/generated/payload-multipart/payload/multipart/aio/_client.py +++ b/packages/typespec-python/test/unbranded/generated/payload-multipart/payload/multipart/aio/_client.py @@ -7,7 +7,7 @@ from corehttp.rest import AsyncHttpResponse, HttpRequest from corehttp.runtime import AsyncPipelineClient, policies -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ..formdata.aio.operations import FormDataOperations from ._configuration import MultiPartClientConfiguration diff --git a/packages/typespec-python/test/unbranded/generated/payload-multipart/payload/multipart/formdata/aio/operations/_operations.py b/packages/typespec-python/test/unbranded/generated/payload-multipart/payload/multipart/formdata/aio/operations/_operations.py index 61167db768d..85460f2968e 100644 --- a/packages/typespec-python/test/unbranded/generated/payload-multipart/payload/multipart/formdata/aio/operations/_operations.py +++ b/packages/typespec-python/test/unbranded/generated/payload-multipart/payload/multipart/formdata/aio/operations/_operations.py @@ -15,9 +15,10 @@ from corehttp.runtime.pipeline import PipelineResponse from ... import models as _models2 -from .... import _model_base, models as _models3 -from ...._serialization import Deserializer, Serializer -from ...._vendor import prepare_multipart_form_data +from .... import models as _models3 +from ...._utils.model_base import Model as _Model +from ...._utils.serialization import Deserializer, Serializer +from ...._utils.utils import prepare_multipart_form_data from ....aio._configuration import MultiPartClientConfiguration from ...httpparts.aio.operations._operations import FormDataHttpPartsOperations from ...operations._operations import ( @@ -98,7 +99,7 @@ async def basic(self, body: Union[_models3.MultiPartRequest, JSON], **kwargs: An cls: ClsType[None] = kwargs.pop("cls", None) - _body = body.as_dict() if isinstance(body, _model_base.Model) else body + _body = body.as_dict() if isinstance(body, _Model) else body _file_fields: List[str] = ["profileImage"] _data_fields: List[str] = ["id"] _files, _data = prepare_multipart_form_data(_body, _file_fields, _data_fields) @@ -170,7 +171,7 @@ async def file_array_and_basic(self, body: Union[_models3.ComplexPartsRequest, J cls: ClsType[None] = kwargs.pop("cls", None) - _body = body.as_dict() if isinstance(body, _model_base.Model) else body + _body = body.as_dict() if isinstance(body, _Model) else body _file_fields: List[str] = ["profileImage", "pictures"] _data_fields: List[str] = ["id", "address"] _files, _data = prepare_multipart_form_data(_body, _file_fields, _data_fields) @@ -242,7 +243,7 @@ async def json_part(self, body: Union[_models3.JsonPartRequest, JSON], **kwargs: cls: ClsType[None] = kwargs.pop("cls", None) - _body = body.as_dict() if isinstance(body, _model_base.Model) else body + _body = body.as_dict() if isinstance(body, _Model) else body _file_fields: List[str] = ["profileImage"] _data_fields: List[str] = ["address"] _files, _data = prepare_multipart_form_data(_body, _file_fields, _data_fields) @@ -314,7 +315,7 @@ async def binary_array_parts(self, body: Union[_models3.BinaryArrayPartsRequest, cls: ClsType[None] = kwargs.pop("cls", None) - _body = body.as_dict() if isinstance(body, _model_base.Model) else body + _body = body.as_dict() if isinstance(body, _Model) else body _file_fields: List[str] = ["pictures"] _data_fields: List[str] = ["id"] _files, _data = prepare_multipart_form_data(_body, _file_fields, _data_fields) @@ -386,7 +387,7 @@ async def multi_binary_parts(self, body: Union[_models3.MultiBinaryPartsRequest, cls: ClsType[None] = kwargs.pop("cls", None) - _body = body.as_dict() if isinstance(body, _model_base.Model) else body + _body = body.as_dict() if isinstance(body, _Model) else body _file_fields: List[str] = ["profileImage", "picture"] _data_fields: List[str] = [] _files, _data = prepare_multipart_form_data(_body, _file_fields, _data_fields) @@ -460,7 +461,7 @@ async def check_file_name_and_content_type( cls: ClsType[None] = kwargs.pop("cls", None) - _body = body.as_dict() if isinstance(body, _model_base.Model) else body + _body = body.as_dict() if isinstance(body, _Model) else body _file_fields: List[str] = ["profileImage"] _data_fields: List[str] = ["id"] _files, _data = prepare_multipart_form_data(_body, _file_fields, _data_fields) @@ -532,7 +533,7 @@ async def anonymous_model(self, body: Union[_models2.AnonymousModelRequest, JSON cls: ClsType[None] = kwargs.pop("cls", None) - _body = body.as_dict() if isinstance(body, _model_base.Model) else body + _body = body.as_dict() if isinstance(body, _Model) else body _file_fields: List[str] = ["profileImage"] _data_fields: List[str] = [] _files, _data = prepare_multipart_form_data(_body, _file_fields, _data_fields) diff --git a/packages/typespec-python/test/unbranded/generated/payload-multipart/payload/multipart/formdata/httpparts/aio/operations/_operations.py b/packages/typespec-python/test/unbranded/generated/payload-multipart/payload/multipart/formdata/httpparts/aio/operations/_operations.py index 919a074e3e2..10b36a31c00 100644 --- a/packages/typespec-python/test/unbranded/generated/payload-multipart/payload/multipart/formdata/httpparts/aio/operations/_operations.py +++ b/packages/typespec-python/test/unbranded/generated/payload-multipart/payload/multipart/formdata/httpparts/aio/operations/_operations.py @@ -14,9 +14,10 @@ from corehttp.runtime import AsyncPipelineClient from corehttp.runtime.pipeline import PipelineResponse -from ..... import _model_base, models as _models4 -from ....._serialization import Deserializer, Serializer -from ....._vendor import prepare_multipart_form_data +from ..... import models as _models4 +from ....._utils.model_base import Model as _Model +from ....._utils.serialization import Deserializer, Serializer +from ....._utils.utils import prepare_multipart_form_data from .....aio._configuration import MultiPartClientConfiguration from ...contenttype.aio.operations._operations import FormDataHttpPartsContentTypeOperations from ...nonstring.aio.operations._operations import FormDataHttpPartsNonStringOperations @@ -97,7 +98,7 @@ async def json_array_and_file_array( cls: ClsType[None] = kwargs.pop("cls", None) - _body = body.as_dict() if isinstance(body, _model_base.Model) else body + _body = body.as_dict() if isinstance(body, _Model) else body _file_fields: List[str] = ["profileImage", "pictures"] _data_fields: List[str] = ["id", "address", "previousAddresses"] _files, _data = prepare_multipart_form_data(_body, _file_fields, _data_fields) diff --git a/packages/typespec-python/test/unbranded/generated/payload-multipart/payload/multipart/formdata/httpparts/contenttype/aio/operations/_operations.py b/packages/typespec-python/test/unbranded/generated/payload-multipart/payload/multipart/formdata/httpparts/contenttype/aio/operations/_operations.py index b511654cfb3..f2ee8273951 100644 --- a/packages/typespec-python/test/unbranded/generated/payload-multipart/payload/multipart/formdata/httpparts/contenttype/aio/operations/_operations.py +++ b/packages/typespec-python/test/unbranded/generated/payload-multipart/payload/multipart/formdata/httpparts/contenttype/aio/operations/_operations.py @@ -14,9 +14,10 @@ from corehttp.runtime import AsyncPipelineClient from corehttp.runtime.pipeline import PipelineResponse -from ...... import _model_base, models as _models5 -from ......_serialization import Deserializer, Serializer -from ......_vendor import prepare_multipart_form_data +from ...... import models as _models5 +from ......_utils.model_base import Model as _Model +from ......_utils.serialization import Deserializer, Serializer +from ......_utils.utils import prepare_multipart_form_data from ......aio._configuration import MultiPartClientConfiguration from ...operations._operations import ( build_form_data_http_parts_content_type_image_jpeg_content_type_request, @@ -95,7 +96,7 @@ async def image_jpeg_content_type( cls: ClsType[None] = kwargs.pop("cls", None) - _body = body.as_dict() if isinstance(body, _model_base.Model) else body + _body = body.as_dict() if isinstance(body, _Model) else body _file_fields: List[str] = ["profileImage"] _data_fields: List[str] = [] _files, _data = prepare_multipart_form_data(_body, _file_fields, _data_fields) @@ -172,7 +173,7 @@ async def required_content_type( cls: ClsType[None] = kwargs.pop("cls", None) - _body = body.as_dict() if isinstance(body, _model_base.Model) else body + _body = body.as_dict() if isinstance(body, _Model) else body _file_fields: List[str] = ["profileImage"] _data_fields: List[str] = [] _files, _data = prepare_multipart_form_data(_body, _file_fields, _data_fields) @@ -249,7 +250,7 @@ async def optional_content_type( cls: ClsType[None] = kwargs.pop("cls", None) - _body = body.as_dict() if isinstance(body, _model_base.Model) else body + _body = body.as_dict() if isinstance(body, _Model) else body _file_fields: List[str] = ["profileImage"] _data_fields: List[str] = [] _files, _data = prepare_multipart_form_data(_body, _file_fields, _data_fields) diff --git a/packages/typespec-python/test/unbranded/generated/payload-multipart/payload/multipart/formdata/httpparts/contenttype/operations/_operations.py b/packages/typespec-python/test/unbranded/generated/payload-multipart/payload/multipart/formdata/httpparts/contenttype/operations/_operations.py index a9fd7978592..216efe77b10 100644 --- a/packages/typespec-python/test/unbranded/generated/payload-multipart/payload/multipart/formdata/httpparts/contenttype/operations/_operations.py +++ b/packages/typespec-python/test/unbranded/generated/payload-multipart/payload/multipart/formdata/httpparts/contenttype/operations/_operations.py @@ -15,10 +15,11 @@ from corehttp.runtime.pipeline import PipelineResponse from corehttp.utils import case_insensitive_dict -from ..... import _model_base, models as _models4 +from ..... import models as _models4 from ....._configuration import MultiPartClientConfiguration -from ....._serialization import Deserializer, Serializer -from ....._vendor import prepare_multipart_form_data +from ....._utils.model_base import Model as _Model +from ....._utils.serialization import Deserializer, Serializer +from ....._utils.utils import prepare_multipart_form_data JSON = MutableMapping[str, Any] T = TypeVar("T") @@ -125,7 +126,7 @@ def image_jpeg_content_type( # pylint: disable=inconsistent-return-statements cls: ClsType[None] = kwargs.pop("cls", None) - _body = body.as_dict() if isinstance(body, _model_base.Model) else body + _body = body.as_dict() if isinstance(body, _Model) else body _file_fields: List[str] = ["profileImage"] _data_fields: List[str] = [] _files, _data = prepare_multipart_form_data(_body, _file_fields, _data_fields) @@ -200,7 +201,7 @@ def required_content_type( # pylint: disable=inconsistent-return-statements cls: ClsType[None] = kwargs.pop("cls", None) - _body = body.as_dict() if isinstance(body, _model_base.Model) else body + _body = body.as_dict() if isinstance(body, _Model) else body _file_fields: List[str] = ["profileImage"] _data_fields: List[str] = [] _files, _data = prepare_multipart_form_data(_body, _file_fields, _data_fields) @@ -275,7 +276,7 @@ def optional_content_type( # pylint: disable=inconsistent-return-statements cls: ClsType[None] = kwargs.pop("cls", None) - _body = body.as_dict() if isinstance(body, _model_base.Model) else body + _body = body.as_dict() if isinstance(body, _Model) else body _file_fields: List[str] = ["profileImage"] _data_fields: List[str] = [] _files, _data = prepare_multipart_form_data(_body, _file_fields, _data_fields) diff --git a/packages/typespec-python/test/unbranded/generated/payload-multipart/payload/multipart/formdata/httpparts/nonstring/aio/operations/_operations.py b/packages/typespec-python/test/unbranded/generated/payload-multipart/payload/multipart/formdata/httpparts/nonstring/aio/operations/_operations.py index b474c418ec5..c70ded80eba 100644 --- a/packages/typespec-python/test/unbranded/generated/payload-multipart/payload/multipart/formdata/httpparts/nonstring/aio/operations/_operations.py +++ b/packages/typespec-python/test/unbranded/generated/payload-multipart/payload/multipart/formdata/httpparts/nonstring/aio/operations/_operations.py @@ -15,9 +15,9 @@ from corehttp.runtime.pipeline import PipelineResponse from ... import models as _models2 -from ...... import _model_base -from ......_serialization import Deserializer, Serializer -from ......_vendor import prepare_multipart_form_data +from ......_utils.model_base import Model as _Model +from ......_utils.serialization import Deserializer, Serializer +from ......_utils.utils import prepare_multipart_form_data from ......aio._configuration import MultiPartClientConfiguration from ...operations._operations import build_form_data_http_parts_non_string_float_request @@ -87,7 +87,7 @@ async def float(self, body: Union[_models2.FloatRequest, JSON], **kwargs: Any) - cls: ClsType[None] = kwargs.pop("cls", None) - _body = body.as_dict() if isinstance(body, _model_base.Model) else body + _body = body.as_dict() if isinstance(body, _Model) else body _file_fields: List[str] = [] _data_fields: List[str] = ["temperature"] _files, _data = prepare_multipart_form_data(_body, _file_fields, _data_fields) diff --git a/packages/typespec-python/test/unbranded/generated/payload-multipart/payload/multipart/formdata/httpparts/nonstring/models/_models.py b/packages/typespec-python/test/unbranded/generated/payload-multipart/payload/multipart/formdata/httpparts/nonstring/models/_models.py index 9fb8f35a0cc..710fc8be59e 100644 --- a/packages/typespec-python/test/unbranded/generated/payload-multipart/payload/multipart/formdata/httpparts/nonstring/models/_models.py +++ b/packages/typespec-python/test/unbranded/generated/payload-multipart/payload/multipart/formdata/httpparts/nonstring/models/_models.py @@ -3,11 +3,10 @@ from typing import Any, Mapping, overload -from ..... import _model_base -from ....._model_base import rest_field +from ....._utils.model_base import Model as _Model, rest_field -class FloatRequest(_model_base.Model): +class FloatRequest(_Model): """FloatRequest. :ivar temperature: Required. diff --git a/packages/typespec-python/test/unbranded/generated/payload-multipart/payload/multipart/formdata/httpparts/nonstring/operations/_operations.py b/packages/typespec-python/test/unbranded/generated/payload-multipart/payload/multipart/formdata/httpparts/nonstring/operations/_operations.py index 4a48a0265ac..bfbbe6a0679 100644 --- a/packages/typespec-python/test/unbranded/generated/payload-multipart/payload/multipart/formdata/httpparts/nonstring/operations/_operations.py +++ b/packages/typespec-python/test/unbranded/generated/payload-multipart/payload/multipart/formdata/httpparts/nonstring/operations/_operations.py @@ -16,10 +16,10 @@ from corehttp.utils import case_insensitive_dict from .. import models as _models1 -from ..... import _model_base from ....._configuration import MultiPartClientConfiguration -from ....._serialization import Deserializer, Serializer -from ....._vendor import prepare_multipart_form_data +from ....._utils.model_base import Model as _Model +from ....._utils.serialization import Deserializer, Serializer +from ....._utils.utils import prepare_multipart_form_data JSON = MutableMapping[str, Any] T = TypeVar("T") @@ -101,7 +101,7 @@ def float( # pylint: disable=inconsistent-return-statements cls: ClsType[None] = kwargs.pop("cls", None) - _body = body.as_dict() if isinstance(body, _model_base.Model) else body + _body = body.as_dict() if isinstance(body, _Model) else body _file_fields: List[str] = [] _data_fields: List[str] = ["temperature"] _files, _data = prepare_multipart_form_data(_body, _file_fields, _data_fields) diff --git a/packages/typespec-python/test/unbranded/generated/payload-multipart/payload/multipart/formdata/httpparts/operations/_operations.py b/packages/typespec-python/test/unbranded/generated/payload-multipart/payload/multipart/formdata/httpparts/operations/_operations.py index ec14a24f08e..755e0a489c5 100644 --- a/packages/typespec-python/test/unbranded/generated/payload-multipart/payload/multipart/formdata/httpparts/operations/_operations.py +++ b/packages/typespec-python/test/unbranded/generated/payload-multipart/payload/multipart/formdata/httpparts/operations/_operations.py @@ -15,10 +15,11 @@ from corehttp.runtime.pipeline import PipelineResponse from corehttp.utils import case_insensitive_dict -from .... import _model_base, models as _models3 +from .... import models as _models3 from ...._configuration import MultiPartClientConfiguration -from ...._serialization import Deserializer, Serializer -from ...._vendor import prepare_multipart_form_data +from ...._utils.model_base import Model as _Model +from ...._utils.serialization import Deserializer, Serializer +from ...._utils.utils import prepare_multipart_form_data from ..contenttype.operations._operations import FormDataHttpPartsContentTypeOperations from ..nonstring.operations._operations import FormDataHttpPartsNonStringOperations @@ -111,7 +112,7 @@ def json_array_and_file_array( # pylint: disable=inconsistent-return-statements cls: ClsType[None] = kwargs.pop("cls", None) - _body = body.as_dict() if isinstance(body, _model_base.Model) else body + _body = body.as_dict() if isinstance(body, _Model) else body _file_fields: List[str] = ["profileImage", "pictures"] _data_fields: List[str] = ["id", "address", "previousAddresses"] _files, _data = prepare_multipart_form_data(_body, _file_fields, _data_fields) diff --git a/packages/typespec-python/test/unbranded/generated/payload-multipart/payload/multipart/formdata/models/_models.py b/packages/typespec-python/test/unbranded/generated/payload-multipart/payload/multipart/formdata/models/_models.py index 216cf5fe7e0..a0f568bf501 100644 --- a/packages/typespec-python/test/unbranded/generated/payload-multipart/payload/multipart/formdata/models/_models.py +++ b/packages/typespec-python/test/unbranded/generated/payload-multipart/payload/multipart/formdata/models/_models.py @@ -3,16 +3,15 @@ from typing import Any, Mapping, overload -from ... import _model_base -from ..._model_base import rest_field -from ..._vendor import FileType +from ..._utils.model_base import Model as _Model, rest_field +from ..._utils.utils import FileType -class AnonymousModelRequest(_model_base.Model): +class AnonymousModelRequest(_Model): """AnonymousModelRequest. :ivar profile_image: Required. - :vartype profile_image: ~payload.multipart._vendor.FileType + :vartype profile_image: ~payload.multipart._utils.utils.FileType """ profile_image: FileType = rest_field( diff --git a/packages/typespec-python/test/unbranded/generated/payload-multipart/payload/multipart/formdata/operations/_operations.py b/packages/typespec-python/test/unbranded/generated/payload-multipart/payload/multipart/formdata/operations/_operations.py index f0b39cccdc9..047e497def5 100644 --- a/packages/typespec-python/test/unbranded/generated/payload-multipart/payload/multipart/formdata/operations/_operations.py +++ b/packages/typespec-python/test/unbranded/generated/payload-multipart/payload/multipart/formdata/operations/_operations.py @@ -16,10 +16,11 @@ from corehttp.utils import case_insensitive_dict from .. import models as _models1 -from ... import _model_base, models as _models2 +from ... import models as _models2 from ..._configuration import MultiPartClientConfiguration -from ..._serialization import Deserializer, Serializer -from ..._vendor import prepare_multipart_form_data +from ..._utils.model_base import Model as _Model +from ..._utils.serialization import Deserializer, Serializer +from ..._utils.utils import prepare_multipart_form_data from ..httpparts.operations._operations import FormDataHttpPartsOperations JSON = MutableMapping[str, Any] @@ -160,7 +161,7 @@ def basic( # pylint: disable=inconsistent-return-statements cls: ClsType[None] = kwargs.pop("cls", None) - _body = body.as_dict() if isinstance(body, _model_base.Model) else body + _body = body.as_dict() if isinstance(body, _Model) else body _file_fields: List[str] = ["profileImage"] _data_fields: List[str] = ["id"] _files, _data = prepare_multipart_form_data(_body, _file_fields, _data_fields) @@ -234,7 +235,7 @@ def file_array_and_basic( # pylint: disable=inconsistent-return-statements cls: ClsType[None] = kwargs.pop("cls", None) - _body = body.as_dict() if isinstance(body, _model_base.Model) else body + _body = body.as_dict() if isinstance(body, _Model) else body _file_fields: List[str] = ["profileImage", "pictures"] _data_fields: List[str] = ["id", "address"] _files, _data = prepare_multipart_form_data(_body, _file_fields, _data_fields) @@ -308,7 +309,7 @@ def json_part( # pylint: disable=inconsistent-return-statements cls: ClsType[None] = kwargs.pop("cls", None) - _body = body.as_dict() if isinstance(body, _model_base.Model) else body + _body = body.as_dict() if isinstance(body, _Model) else body _file_fields: List[str] = ["profileImage"] _data_fields: List[str] = ["address"] _files, _data = prepare_multipart_form_data(_body, _file_fields, _data_fields) @@ -382,7 +383,7 @@ def binary_array_parts( # pylint: disable=inconsistent-return-statements cls: ClsType[None] = kwargs.pop("cls", None) - _body = body.as_dict() if isinstance(body, _model_base.Model) else body + _body = body.as_dict() if isinstance(body, _Model) else body _file_fields: List[str] = ["pictures"] _data_fields: List[str] = ["id"] _files, _data = prepare_multipart_form_data(_body, _file_fields, _data_fields) @@ -456,7 +457,7 @@ def multi_binary_parts( # pylint: disable=inconsistent-return-statements cls: ClsType[None] = kwargs.pop("cls", None) - _body = body.as_dict() if isinstance(body, _model_base.Model) else body + _body = body.as_dict() if isinstance(body, _Model) else body _file_fields: List[str] = ["profileImage", "picture"] _data_fields: List[str] = [] _files, _data = prepare_multipart_form_data(_body, _file_fields, _data_fields) @@ -530,7 +531,7 @@ def check_file_name_and_content_type( # pylint: disable=inconsistent-return-sta cls: ClsType[None] = kwargs.pop("cls", None) - _body = body.as_dict() if isinstance(body, _model_base.Model) else body + _body = body.as_dict() if isinstance(body, _Model) else body _file_fields: List[str] = ["profileImage"] _data_fields: List[str] = ["id"] _files, _data = prepare_multipart_form_data(_body, _file_fields, _data_fields) @@ -604,7 +605,7 @@ def anonymous_model( # pylint: disable=inconsistent-return-statements cls: ClsType[None] = kwargs.pop("cls", None) - _body = body.as_dict() if isinstance(body, _model_base.Model) else body + _body = body.as_dict() if isinstance(body, _Model) else body _file_fields: List[str] = ["profileImage"] _data_fields: List[str] = [] _files, _data = prepare_multipart_form_data(_body, _file_fields, _data_fields) diff --git a/packages/typespec-python/test/unbranded/generated/payload-multipart/payload/multipart/models/_models.py b/packages/typespec-python/test/unbranded/generated/payload-multipart/payload/multipart/models/_models.py index 60e52deeb41..5dd6b0e8200 100644 --- a/packages/typespec-python/test/unbranded/generated/payload-multipart/payload/multipart/models/_models.py +++ b/packages/typespec-python/test/unbranded/generated/payload-multipart/payload/multipart/models/_models.py @@ -3,15 +3,14 @@ from typing import Any, List, Mapping, Optional, TYPE_CHECKING, overload -from .. import _model_base -from .._model_base import rest_field -from .._vendor import FileType +from .._utils.model_base import Model as _Model, rest_field +from .._utils.utils import FileType if TYPE_CHECKING: from .. import models as _models -class Address(_model_base.Model): +class Address(_Model): """Address. :ivar city: Required. @@ -39,13 +38,13 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class BinaryArrayPartsRequest(_model_base.Model): +class BinaryArrayPartsRequest(_Model): """BinaryArrayPartsRequest. :ivar id: Required. :vartype id: str :ivar pictures: Required. - :vartype pictures: list[~payload.multipart._vendor.FileType] + :vartype pictures: list[~payload.multipart._utils.utils.FileType] """ id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) @@ -74,7 +73,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class ComplexHttpPartsModelRequest(_model_base.Model): +class ComplexHttpPartsModelRequest(_Model): """ComplexHttpPartsModelRequest. :ivar id: Required. @@ -82,11 +81,11 @@ class ComplexHttpPartsModelRequest(_model_base.Model): :ivar address: Required. :vartype address: ~payload.multipart.models.Address :ivar profile_image: Required. - :vartype profile_image: ~payload.multipart._vendor.FileType + :vartype profile_image: ~payload.multipart._utils.utils.FileType :ivar previous_addresses: Required. :vartype previous_addresses: list[~payload.multipart.models.Address] :ivar pictures: Required. - :vartype pictures: list[~payload.multipart._vendor.FileType] + :vartype pictures: list[~payload.multipart._utils.utils.FileType] """ id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) @@ -128,7 +127,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class ComplexPartsRequest(_model_base.Model): +class ComplexPartsRequest(_Model): """ComplexPartsRequest. :ivar id: Required. @@ -136,9 +135,9 @@ class ComplexPartsRequest(_model_base.Model): :ivar address: Required. :vartype address: ~payload.multipart.models.Address :ivar profile_image: Required. - :vartype profile_image: ~payload.multipart._vendor.FileType + :vartype profile_image: ~payload.multipart._utils.utils.FileType :ivar pictures: Required. - :vartype pictures: list[~payload.multipart._vendor.FileType] + :vartype pictures: list[~payload.multipart._utils.utils.FileType] """ id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) @@ -175,11 +174,11 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class FileWithHttpPartOptionalContentTypeRequest(_model_base.Model): # pylint: disable=name-too-long +class FileWithHttpPartOptionalContentTypeRequest(_Model): # pylint: disable=name-too-long """FileWithHttpPartOptionalContentTypeRequest. :ivar profile_image: Required. - :vartype profile_image: ~payload.multipart._vendor.FileType + :vartype profile_image: ~payload.multipart._utils.utils.FileType """ profile_image: FileType = rest_field( @@ -205,11 +204,11 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class FileWithHttpPartRequiredContentTypeRequest(_model_base.Model): # pylint: disable=name-too-long +class FileWithHttpPartRequiredContentTypeRequest(_Model): # pylint: disable=name-too-long """FileWithHttpPartRequiredContentTypeRequest. :ivar profile_image: Required. - :vartype profile_image: ~payload.multipart._vendor.FileType + :vartype profile_image: ~payload.multipart._utils.utils.FileType """ profile_image: FileType = rest_field( @@ -235,11 +234,11 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class FileWithHttpPartSpecificContentTypeRequest(_model_base.Model): # pylint: disable=name-too-long +class FileWithHttpPartSpecificContentTypeRequest(_Model): # pylint: disable=name-too-long """FileWithHttpPartSpecificContentTypeRequest. :ivar profile_image: Required. - :vartype profile_image: ~payload.multipart._vendor.FileType + :vartype profile_image: ~payload.multipart._utils.utils.FileType """ profile_image: FileType = rest_field( @@ -265,13 +264,13 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class JsonPartRequest(_model_base.Model): +class JsonPartRequest(_Model): """JsonPartRequest. :ivar address: Required. :vartype address: ~payload.multipart.models.Address :ivar profile_image: Required. - :vartype profile_image: ~payload.multipart._vendor.FileType + :vartype profile_image: ~payload.multipart._utils.utils.FileType """ address: "_models.Address" = rest_field(visibility=["read", "create", "update", "delete", "query"]) @@ -300,13 +299,13 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class MultiBinaryPartsRequest(_model_base.Model): +class MultiBinaryPartsRequest(_Model): """MultiBinaryPartsRequest. :ivar profile_image: Required. - :vartype profile_image: ~payload.multipart._vendor.FileType + :vartype profile_image: ~payload.multipart._utils.utils.FileType :ivar picture: - :vartype picture: ~payload.multipart._vendor.FileType + :vartype picture: ~payload.multipart._utils.utils.FileType """ profile_image: FileType = rest_field( @@ -336,13 +335,13 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class MultiPartRequest(_model_base.Model): +class MultiPartRequest(_Model): """MultiPartRequest. :ivar id: Required. :vartype id: str :ivar profile_image: Required. - :vartype profile_image: ~payload.multipart._vendor.FileType + :vartype profile_image: ~payload.multipart._utils.utils.FileType """ id: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) diff --git a/packages/typespec-python/test/unbranded/generated/payload-pageable/payload/pageable/_client.py b/packages/typespec-python/test/unbranded/generated/payload-pageable/payload/pageable/_client.py index 5ad1338afb1..79fe60413d3 100644 --- a/packages/typespec-python/test/unbranded/generated/payload-pageable/payload/pageable/_client.py +++ b/packages/typespec-python/test/unbranded/generated/payload-pageable/payload/pageable/_client.py @@ -8,7 +8,7 @@ from corehttp.runtime import PipelineClient, policies from ._configuration import PageableClientConfiguration -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer from .serverdrivenpagination.operations import ServerDrivenPaginationOperations diff --git a/packages/typespec-python/test/unbranded/generated/payload-pageable/payload/pageable/_utils/__init__.py b/packages/typespec-python/test/unbranded/generated/payload-pageable/payload/pageable/_utils/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/packages/typespec-python/test/unbranded/generated/payload-pageable/payload/pageable/_model_base.py b/packages/typespec-python/test/unbranded/generated/payload-pageable/payload/pageable/_utils/model_base.py similarity index 100% rename from packages/typespec-python/test/unbranded/generated/payload-pageable/payload/pageable/_model_base.py rename to packages/typespec-python/test/unbranded/generated/payload-pageable/payload/pageable/_utils/model_base.py diff --git a/packages/typespec-python/test/unbranded/generated/payload-pageable/payload/pageable/_serialization.py b/packages/typespec-python/test/unbranded/generated/payload-pageable/payload/pageable/_utils/serialization.py similarity index 100% rename from packages/typespec-python/test/unbranded/generated/payload-pageable/payload/pageable/_serialization.py rename to packages/typespec-python/test/unbranded/generated/payload-pageable/payload/pageable/_utils/serialization.py diff --git a/packages/typespec-python/test/unbranded/generated/payload-pageable/payload/pageable/aio/_client.py b/packages/typespec-python/test/unbranded/generated/payload-pageable/payload/pageable/aio/_client.py index 6cbb3e2435f..a8952a68163 100644 --- a/packages/typespec-python/test/unbranded/generated/payload-pageable/payload/pageable/aio/_client.py +++ b/packages/typespec-python/test/unbranded/generated/payload-pageable/payload/pageable/aio/_client.py @@ -7,7 +7,7 @@ from corehttp.rest import AsyncHttpResponse, HttpRequest from corehttp.runtime import AsyncPipelineClient, policies -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ..serverdrivenpagination.aio.operations import ServerDrivenPaginationOperations from ._configuration import PageableClientConfiguration diff --git a/packages/typespec-python/test/unbranded/generated/payload-pageable/payload/pageable/models/_models.py b/packages/typespec-python/test/unbranded/generated/payload-pageable/payload/pageable/models/_models.py index 502af952936..b2b0cc11f1e 100644 --- a/packages/typespec-python/test/unbranded/generated/payload-pageable/payload/pageable/models/_models.py +++ b/packages/typespec-python/test/unbranded/generated/payload-pageable/payload/pageable/models/_models.py @@ -3,11 +3,10 @@ from typing import Any, Mapping, overload -from .. import _model_base -from .._model_base import rest_field +from .._utils.model_base import Model as _Model, rest_field -class Pet(_model_base.Model): +class Pet(_Model): """Pet. :ivar id: Required. diff --git a/packages/typespec-python/test/unbranded/generated/payload-pageable/payload/pageable/serverdrivenpagination/aio/operations/_operations.py b/packages/typespec-python/test/unbranded/generated/payload-pageable/payload/pageable/serverdrivenpagination/aio/operations/_operations.py index b101ea513f2..08eea3b1b13 100644 --- a/packages/typespec-python/test/unbranded/generated/payload-pageable/payload/pageable/serverdrivenpagination/aio/operations/_operations.py +++ b/packages/typespec-python/test/unbranded/generated/payload-pageable/payload/pageable/serverdrivenpagination/aio/operations/_operations.py @@ -16,8 +16,8 @@ from corehttp.runtime.pipeline import PipelineResponse from .... import models as _models3 -from ...._model_base import _deserialize -from ...._serialization import Deserializer, Serializer +from ...._utils.model_base import _deserialize +from ...._utils.serialization import Deserializer, Serializer from ....aio._configuration import PageableClientConfiguration from ...continuationtoken.aio.operations._operations import ServerDrivenPaginationContinuationTokenOperations from ...operations._operations import build_server_driven_pagination_link_request diff --git a/packages/typespec-python/test/unbranded/generated/payload-pageable/payload/pageable/serverdrivenpagination/continuationtoken/aio/operations/_operations.py b/packages/typespec-python/test/unbranded/generated/payload-pageable/payload/pageable/serverdrivenpagination/continuationtoken/aio/operations/_operations.py index a627773296e..05722decc1c 100644 --- a/packages/typespec-python/test/unbranded/generated/payload-pageable/payload/pageable/serverdrivenpagination/continuationtoken/aio/operations/_operations.py +++ b/packages/typespec-python/test/unbranded/generated/payload-pageable/payload/pageable/serverdrivenpagination/continuationtoken/aio/operations/_operations.py @@ -16,8 +16,8 @@ from corehttp.runtime.pipeline import PipelineResponse from ..... import models as _models4 -from ....._model_base import _deserialize -from ....._serialization import Deserializer, Serializer +from ....._utils.model_base import _deserialize +from ....._utils.serialization import Deserializer, Serializer from .....aio._configuration import PageableClientConfiguration from ...operations._operations import ( build_server_driven_pagination_continuation_token_request_header_response_body_request, diff --git a/packages/typespec-python/test/unbranded/generated/payload-pageable/payload/pageable/serverdrivenpagination/continuationtoken/operations/_operations.py b/packages/typespec-python/test/unbranded/generated/payload-pageable/payload/pageable/serverdrivenpagination/continuationtoken/operations/_operations.py index b4be7df1920..f2d68ebdcef 100644 --- a/packages/typespec-python/test/unbranded/generated/payload-pageable/payload/pageable/serverdrivenpagination/continuationtoken/operations/_operations.py +++ b/packages/typespec-python/test/unbranded/generated/payload-pageable/payload/pageable/serverdrivenpagination/continuationtoken/operations/_operations.py @@ -19,8 +19,8 @@ from .... import models as _models3 from ...._configuration import PageableClientConfiguration -from ...._model_base import _deserialize -from ...._serialization import Deserializer, Serializer +from ...._utils.model_base import _deserialize +from ...._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/typespec-python/test/unbranded/generated/payload-pageable/payload/pageable/serverdrivenpagination/operations/_operations.py b/packages/typespec-python/test/unbranded/generated/payload-pageable/payload/pageable/serverdrivenpagination/operations/_operations.py index 437ec8005d7..258f4d54786 100644 --- a/packages/typespec-python/test/unbranded/generated/payload-pageable/payload/pageable/serverdrivenpagination/operations/_operations.py +++ b/packages/typespec-python/test/unbranded/generated/payload-pageable/payload/pageable/serverdrivenpagination/operations/_operations.py @@ -18,8 +18,8 @@ from ... import models as _models2 from ..._configuration import PageableClientConfiguration -from ..._model_base import _deserialize -from ..._serialization import Deserializer, Serializer +from ..._utils.model_base import _deserialize +from ..._utils.serialization import Deserializer, Serializer from ..continuationtoken.operations._operations import ServerDrivenPaginationContinuationTokenOperations T = TypeVar("T") diff --git a/packages/typespec-python/test/unbranded/generated/payload-xml/payload/xml/_client.py b/packages/typespec-python/test/unbranded/generated/payload-xml/payload/xml/_client.py index 673595708f0..dad2e5c4554 100644 --- a/packages/typespec-python/test/unbranded/generated/payload-xml/payload/xml/_client.py +++ b/packages/typespec-python/test/unbranded/generated/payload-xml/payload/xml/_client.py @@ -8,7 +8,7 @@ from corehttp.runtime import PipelineClient, policies from ._configuration import XmlClientConfiguration -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer from .operations import ( ModelWithArrayOfModelValueOperations, ModelWithAttributesValueOperations, diff --git a/packages/typespec-python/test/unbranded/generated/payload-xml/payload/xml/_utils/__init__.py b/packages/typespec-python/test/unbranded/generated/payload-xml/payload/xml/_utils/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/packages/typespec-python/test/unbranded/generated/payload-xml/payload/xml/_model_base.py b/packages/typespec-python/test/unbranded/generated/payload-xml/payload/xml/_utils/model_base.py similarity index 100% rename from packages/typespec-python/test/unbranded/generated/payload-xml/payload/xml/_model_base.py rename to packages/typespec-python/test/unbranded/generated/payload-xml/payload/xml/_utils/model_base.py diff --git a/packages/typespec-python/test/unbranded/generated/payload-xml/payload/xml/_serialization.py b/packages/typespec-python/test/unbranded/generated/payload-xml/payload/xml/_utils/serialization.py similarity index 100% rename from packages/typespec-python/test/unbranded/generated/payload-xml/payload/xml/_serialization.py rename to packages/typespec-python/test/unbranded/generated/payload-xml/payload/xml/_utils/serialization.py diff --git a/packages/typespec-python/test/unbranded/generated/payload-xml/payload/xml/aio/_client.py b/packages/typespec-python/test/unbranded/generated/payload-xml/payload/xml/aio/_client.py index 0fcb294265e..f0707b94024 100644 --- a/packages/typespec-python/test/unbranded/generated/payload-xml/payload/xml/aio/_client.py +++ b/packages/typespec-python/test/unbranded/generated/payload-xml/payload/xml/aio/_client.py @@ -7,7 +7,7 @@ from corehttp.rest import AsyncHttpResponse, HttpRequest from corehttp.runtime import AsyncPipelineClient, policies -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import XmlClientConfiguration from .operations import ( ModelWithArrayOfModelValueOperations, diff --git a/packages/typespec-python/test/unbranded/generated/payload-xml/payload/xml/aio/operations/_operations.py b/packages/typespec-python/test/unbranded/generated/payload-xml/payload/xml/aio/operations/_operations.py index 52fc1afcff1..996f86349e2 100644 --- a/packages/typespec-python/test/unbranded/generated/payload-xml/payload/xml/aio/operations/_operations.py +++ b/packages/typespec-python/test/unbranded/generated/payload-xml/payload/xml/aio/operations/_operations.py @@ -19,8 +19,8 @@ from corehttp.utils import case_insensitive_dict from ... import models as _models -from ..._model_base import _deserialize_xml, _get_element -from ..._serialization import Deserializer, Serializer +from ..._utils.model_base import _deserialize_xml, _get_element +from ..._utils.serialization import Deserializer, Serializer from ...operations._operations import ( build_model_with_array_of_model_value_get_request, build_model_with_array_of_model_value_put_request, diff --git a/packages/typespec-python/test/unbranded/generated/payload-xml/payload/xml/models/_models.py b/packages/typespec-python/test/unbranded/generated/payload-xml/payload/xml/models/_models.py index 5f6aafa22ca..8d2c7f2b8d1 100644 --- a/packages/typespec-python/test/unbranded/generated/payload-xml/payload/xml/models/_models.py +++ b/packages/typespec-python/test/unbranded/generated/payload-xml/payload/xml/models/_models.py @@ -3,14 +3,13 @@ from typing import Any, Dict, List, Mapping, Optional, TYPE_CHECKING, overload -from .. import _model_base -from .._model_base import rest_field +from .._utils.model_base import Model as _Model, rest_field if TYPE_CHECKING: from .. import models as _models -class ModelWithArrayOfModel(_model_base.Model): +class ModelWithArrayOfModel(_Model): """Contains an array of models. :ivar items_property: Required. @@ -44,7 +43,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class ModelWithAttributes(_model_base.Model): +class ModelWithAttributes(_Model): """Contains fields that are XML attributes. :ivar id1: Required. @@ -93,7 +92,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class ModelWithDictionary(_model_base.Model): +class ModelWithDictionary(_Model): """Contains a dictionary of key value pairs. :ivar metadata: Required. @@ -126,7 +125,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class ModelWithEmptyArray(_model_base.Model): +class ModelWithEmptyArray(_Model): """Contains an array of models that's supposed to be sent/received as an empty XML element. :ivar items_property: Required. @@ -160,7 +159,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class ModelWithEncodedNames(_model_base.Model): +class ModelWithEncodedNames(_Model): """Uses encodedName instead of Xml.Name which is functionally equivalent. :ivar model_data: Required. @@ -202,7 +201,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class ModelWithOptionalField(_model_base.Model): +class ModelWithOptionalField(_Model): """Contains an optional field. :ivar item: Required. @@ -242,7 +241,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class ModelWithRenamedArrays(_model_base.Model): +class ModelWithRenamedArrays(_Model): """Contains fields of wrapped and unwrapped arrays of primitive types that have different XML representations. @@ -284,7 +283,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class ModelWithRenamedFields(_model_base.Model): +class ModelWithRenamedFields(_Model): """Contains fields of the same type that have different XML representation. :ivar input_data: Required. @@ -327,7 +326,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class ModelWithSimpleArrays(_model_base.Model): +class ModelWithSimpleArrays(_Model): """Contains fields of arrays of primitive types. :ivar colors: Required. @@ -368,7 +367,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class ModelWithText(_model_base.Model): +class ModelWithText(_Model): """Contains an attribute and text. :ivar language: Required. @@ -409,7 +408,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class ModelWithUnwrappedArray(_model_base.Model): +class ModelWithUnwrappedArray(_Model): """Contains fields of wrapped and unwrapped arrays of primitive types. :ivar colors: Required. @@ -450,7 +449,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class SimpleModel(_model_base.Model): +class SimpleModel(_Model): """Contains fields of primitive types. :ivar name: Required. diff --git a/packages/typespec-python/test/unbranded/generated/payload-xml/payload/xml/operations/_operations.py b/packages/typespec-python/test/unbranded/generated/payload-xml/payload/xml/operations/_operations.py index a6de9be85b8..7f1ae9df784 100644 --- a/packages/typespec-python/test/unbranded/generated/payload-xml/payload/xml/operations/_operations.py +++ b/packages/typespec-python/test/unbranded/generated/payload-xml/payload/xml/operations/_operations.py @@ -20,8 +20,8 @@ from .. import models as _models from .._configuration import XmlClientConfiguration -from .._model_base import _deserialize_xml, _get_element -from .._serialization import Deserializer, Serializer +from .._utils.model_base import _deserialize_xml, _get_element +from .._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/typespec-python/test/unbranded/generated/response-status-code-range/response/statuscoderange/_client.py b/packages/typespec-python/test/unbranded/generated/response-status-code-range/response/statuscoderange/_client.py index 9ba09b28af4..8b84c8452de 100644 --- a/packages/typespec-python/test/unbranded/generated/response-status-code-range/response/statuscoderange/_client.py +++ b/packages/typespec-python/test/unbranded/generated/response-status-code-range/response/statuscoderange/_client.py @@ -9,7 +9,7 @@ from ._configuration import StatusCodeRangeClientConfiguration from ._operations import StatusCodeRangeClientOperationsMixin -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer class StatusCodeRangeClient(StatusCodeRangeClientOperationsMixin): # pylint: disable=client-accepts-api-version-keyword diff --git a/packages/typespec-python/test/unbranded/generated/response-status-code-range/response/statuscoderange/_operations/_operations.py b/packages/typespec-python/test/unbranded/generated/response-status-code-range/response/statuscoderange/_operations/_operations.py index c51d67ec98c..8c8a419eb98 100644 --- a/packages/typespec-python/test/unbranded/generated/response-status-code-range/response/statuscoderange/_operations/_operations.py +++ b/packages/typespec-python/test/unbranded/generated/response-status-code-range/response/statuscoderange/_operations/_operations.py @@ -11,13 +11,15 @@ map_error, ) from corehttp.rest import HttpRequest, HttpResponse +from corehttp.runtime import PipelineClient from corehttp.runtime.pipeline import PipelineResponse from corehttp.utils import case_insensitive_dict from .. import models as _models -from .._model_base import _failsafe_deserialize -from .._serialization import Serializer -from .._vendor import StatusCodeRangeClientMixinABC +from .._configuration import StatusCodeRangeClientConfiguration +from .._utils.model_base import _failsafe_deserialize +from .._utils.serialization import Serializer +from .._utils.utils import ClientMixinABC T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] @@ -58,7 +60,7 @@ def build_status_code_range_error_response_status_code404_request( # pylint: di return HttpRequest(method="GET", url=_url, headers=_headers, **kwargs) -class StatusCodeRangeClientOperationsMixin(StatusCodeRangeClientMixinABC): +class StatusCodeRangeClientOperationsMixin(ClientMixinABC[PipelineClient, StatusCodeRangeClientConfiguration]): def error_response_status_code_in_range( # pylint: disable=inconsistent-return-statements self, **kwargs: Any diff --git a/packages/typespec-python/test/unbranded/generated/response-status-code-range/response/statuscoderange/_utils/__init__.py b/packages/typespec-python/test/unbranded/generated/response-status-code-range/response/statuscoderange/_utils/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/packages/typespec-python/test/unbranded/generated/response-status-code-range/response/statuscoderange/_model_base.py b/packages/typespec-python/test/unbranded/generated/response-status-code-range/response/statuscoderange/_utils/model_base.py similarity index 100% rename from packages/typespec-python/test/unbranded/generated/response-status-code-range/response/statuscoderange/_model_base.py rename to packages/typespec-python/test/unbranded/generated/response-status-code-range/response/statuscoderange/_utils/model_base.py diff --git a/packages/typespec-python/test/unbranded/generated/response-status-code-range/response/statuscoderange/_serialization.py b/packages/typespec-python/test/unbranded/generated/response-status-code-range/response/statuscoderange/_utils/serialization.py similarity index 100% rename from packages/typespec-python/test/unbranded/generated/response-status-code-range/response/statuscoderange/_serialization.py rename to packages/typespec-python/test/unbranded/generated/response-status-code-range/response/statuscoderange/_utils/serialization.py diff --git a/packages/typespec-python/test/unbranded/generated/response-status-code-range/response/statuscoderange/_utils/utils.py b/packages/typespec-python/test/unbranded/generated/response-status-code-range/response/statuscoderange/_utils/utils.py new file mode 100644 index 00000000000..02aa2f816ea --- /dev/null +++ b/packages/typespec-python/test/unbranded/generated/response-status-code-range/response/statuscoderange/_utils/utils.py @@ -0,0 +1,18 @@ +from abc import ABC +from typing import Generic, TYPE_CHECKING, TypeVar + +if TYPE_CHECKING: + from .serialization import Deserializer, Serializer + + +TClient = TypeVar("TClient") +TConfig = TypeVar("TConfig") + + +class ClientMixinABC(ABC, Generic[TClient, TConfig]): + """DO NOT use this class. It is for internal typing use only.""" + + _client: TClient + _config: TConfig + _serialize: "Serializer" + _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/unbranded/generated/response-status-code-range/response/statuscoderange/_vendor.py b/packages/typespec-python/test/unbranded/generated/response-status-code-range/response/statuscoderange/_vendor.py deleted file mode 100644 index 04ccdc10bc2..00000000000 --- a/packages/typespec-python/test/unbranded/generated/response-status-code-range/response/statuscoderange/_vendor.py +++ /dev/null @@ -1,18 +0,0 @@ -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import StatusCodeRangeClientConfiguration - -if TYPE_CHECKING: - from corehttp.runtime import PipelineClient - - from ._serialization import Deserializer, Serializer - - -class StatusCodeRangeClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "PipelineClient" - _config: StatusCodeRangeClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/unbranded/generated/response-status-code-range/response/statuscoderange/aio/_client.py b/packages/typespec-python/test/unbranded/generated/response-status-code-range/response/statuscoderange/aio/_client.py index 86fcfb0f96a..ad112d8d2d0 100644 --- a/packages/typespec-python/test/unbranded/generated/response-status-code-range/response/statuscoderange/aio/_client.py +++ b/packages/typespec-python/test/unbranded/generated/response-status-code-range/response/statuscoderange/aio/_client.py @@ -7,7 +7,7 @@ from corehttp.rest import AsyncHttpResponse, HttpRequest from corehttp.runtime import AsyncPipelineClient, policies -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import StatusCodeRangeClientConfiguration from ._operations import StatusCodeRangeClientOperationsMixin diff --git a/packages/typespec-python/test/unbranded/generated/response-status-code-range/response/statuscoderange/aio/_operations/_operations.py b/packages/typespec-python/test/unbranded/generated/response-status-code-range/response/statuscoderange/aio/_operations/_operations.py index 5e54c034b68..c5793da953b 100644 --- a/packages/typespec-python/test/unbranded/generated/response-status-code-range/response/statuscoderange/aio/_operations/_operations.py +++ b/packages/typespec-python/test/unbranded/generated/response-status-code-range/response/statuscoderange/aio/_operations/_operations.py @@ -11,21 +11,23 @@ map_error, ) from corehttp.rest import AsyncHttpResponse, HttpRequest +from corehttp.runtime import AsyncPipelineClient from corehttp.runtime.pipeline import PipelineResponse from ... import models as _models -from ..._model_base import _failsafe_deserialize from ..._operations._operations import ( build_status_code_range_error_response_status_code404_request, build_status_code_range_error_response_status_code_in_range_request, ) -from .._vendor import StatusCodeRangeClientMixinABC +from ..._utils.model_base import _failsafe_deserialize +from ..._utils.utils import ClientMixinABC +from .._configuration import StatusCodeRangeClientConfiguration T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, AsyncHttpResponse], T, Dict[str, Any]], Any]] -class StatusCodeRangeClientOperationsMixin(StatusCodeRangeClientMixinABC): +class StatusCodeRangeClientOperationsMixin(ClientMixinABC[AsyncPipelineClient, StatusCodeRangeClientConfiguration]): async def error_response_status_code_in_range(self, **kwargs: Any) -> None: """error_response_status_code_in_range. diff --git a/packages/typespec-python/test/unbranded/generated/response-status-code-range/response/statuscoderange/aio/_vendor.py b/packages/typespec-python/test/unbranded/generated/response-status-code-range/response/statuscoderange/aio/_vendor.py deleted file mode 100644 index d0983dbfdf9..00000000000 --- a/packages/typespec-python/test/unbranded/generated/response-status-code-range/response/statuscoderange/aio/_vendor.py +++ /dev/null @@ -1,18 +0,0 @@ -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import StatusCodeRangeClientConfiguration - -if TYPE_CHECKING: - from corehttp.runtime import AsyncPipelineClient - - from .._serialization import Deserializer, Serializer - - -class StatusCodeRangeClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "AsyncPipelineClient" - _config: StatusCodeRangeClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/unbranded/generated/response-status-code-range/response/statuscoderange/models/_models.py b/packages/typespec-python/test/unbranded/generated/response-status-code-range/response/statuscoderange/models/_models.py index d171f4985e7..a22cd5571b8 100644 --- a/packages/typespec-python/test/unbranded/generated/response-status-code-range/response/statuscoderange/models/_models.py +++ b/packages/typespec-python/test/unbranded/generated/response-status-code-range/response/statuscoderange/models/_models.py @@ -3,11 +3,10 @@ from typing import Any, Mapping, overload -from .. import _model_base -from .._model_base import rest_field +from .._utils.model_base import Model as _Model, rest_field -class DefaultError(_model_base.Model): +class DefaultError(_Model): """DefaultError. :ivar code: Required. @@ -35,7 +34,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class ErrorInRange(_model_base.Model): +class ErrorInRange(_Model): """ErrorInRange. :ivar code: Required. @@ -68,7 +67,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class NotFoundError(_model_base.Model): +class NotFoundError(_Model): """NotFoundError. :ivar code: Required. @@ -101,7 +100,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class Standard4XXError(_model_base.Model): +class Standard4XXError(_Model): """Standard4XXError. :ivar code: Required. diff --git a/packages/typespec-python/test/unbranded/generated/routes/routes/_client.py b/packages/typespec-python/test/unbranded/generated/routes/routes/_client.py index 44922b79c43..9fe0c699af3 100644 --- a/packages/typespec-python/test/unbranded/generated/routes/routes/_client.py +++ b/packages/typespec-python/test/unbranded/generated/routes/routes/_client.py @@ -8,7 +8,7 @@ from corehttp.runtime import PipelineClient, policies from ._configuration import RoutesClientConfiguration -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer from .operations import InInterfaceOperations, RoutesClientOperationsMixin from .pathparameters.operations import PathParametersOperations from .queryparameters.operations import QueryParametersOperations diff --git a/packages/typespec-python/test/unbranded/generated/routes/routes/_utils/__init__.py b/packages/typespec-python/test/unbranded/generated/routes/routes/_utils/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/packages/typespec-python/test/unbranded/generated/routes/routes/_model_base.py b/packages/typespec-python/test/unbranded/generated/routes/routes/_utils/model_base.py similarity index 100% rename from packages/typespec-python/test/unbranded/generated/routes/routes/_model_base.py rename to packages/typespec-python/test/unbranded/generated/routes/routes/_utils/model_base.py diff --git a/packages/typespec-python/test/unbranded/generated/routes/routes/_serialization.py b/packages/typespec-python/test/unbranded/generated/routes/routes/_utils/serialization.py similarity index 100% rename from packages/typespec-python/test/unbranded/generated/routes/routes/_serialization.py rename to packages/typespec-python/test/unbranded/generated/routes/routes/_utils/serialization.py diff --git a/packages/typespec-python/test/unbranded/generated/routes/routes/_utils/utils.py b/packages/typespec-python/test/unbranded/generated/routes/routes/_utils/utils.py new file mode 100644 index 00000000000..02aa2f816ea --- /dev/null +++ b/packages/typespec-python/test/unbranded/generated/routes/routes/_utils/utils.py @@ -0,0 +1,18 @@ +from abc import ABC +from typing import Generic, TYPE_CHECKING, TypeVar + +if TYPE_CHECKING: + from .serialization import Deserializer, Serializer + + +TClient = TypeVar("TClient") +TConfig = TypeVar("TConfig") + + +class ClientMixinABC(ABC, Generic[TClient, TConfig]): + """DO NOT use this class. It is for internal typing use only.""" + + _client: TClient + _config: TConfig + _serialize: "Serializer" + _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/unbranded/generated/routes/routes/_vendor.py b/packages/typespec-python/test/unbranded/generated/routes/routes/_vendor.py deleted file mode 100644 index 3001699e274..00000000000 --- a/packages/typespec-python/test/unbranded/generated/routes/routes/_vendor.py +++ /dev/null @@ -1,18 +0,0 @@ -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import RoutesClientConfiguration - -if TYPE_CHECKING: - from corehttp.runtime import PipelineClient - - from ._serialization import Deserializer, Serializer - - -class RoutesClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "PipelineClient" - _config: RoutesClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/unbranded/generated/routes/routes/aio/_client.py b/packages/typespec-python/test/unbranded/generated/routes/routes/aio/_client.py index 0c52e581147..a78bf81fd0a 100644 --- a/packages/typespec-python/test/unbranded/generated/routes/routes/aio/_client.py +++ b/packages/typespec-python/test/unbranded/generated/routes/routes/aio/_client.py @@ -7,7 +7,7 @@ from corehttp.rest import AsyncHttpResponse, HttpRequest from corehttp.runtime import AsyncPipelineClient, policies -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ..pathparameters.aio.operations import PathParametersOperations from ..queryparameters.aio.operations import QueryParametersOperations from ._configuration import RoutesClientConfiguration diff --git a/packages/typespec-python/test/unbranded/generated/routes/routes/aio/_vendor.py b/packages/typespec-python/test/unbranded/generated/routes/routes/aio/_vendor.py deleted file mode 100644 index 5dedc4164e6..00000000000 --- a/packages/typespec-python/test/unbranded/generated/routes/routes/aio/_vendor.py +++ /dev/null @@ -1,18 +0,0 @@ -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import RoutesClientConfiguration - -if TYPE_CHECKING: - from corehttp.runtime import AsyncPipelineClient - - from .._serialization import Deserializer, Serializer - - -class RoutesClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "AsyncPipelineClient" - _config: RoutesClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/unbranded/generated/routes/routes/aio/operations/_operations.py b/packages/typespec-python/test/unbranded/generated/routes/routes/aio/operations/_operations.py index 3fc334f5e4d..c57cfd706f0 100644 --- a/packages/typespec-python/test/unbranded/generated/routes/routes/aio/operations/_operations.py +++ b/packages/typespec-python/test/unbranded/generated/routes/routes/aio/operations/_operations.py @@ -14,10 +14,10 @@ from corehttp.runtime import AsyncPipelineClient from corehttp.runtime.pipeline import PipelineResponse -from ..._serialization import Deserializer, Serializer +from ..._utils.serialization import Deserializer, Serializer +from ..._utils.utils import ClientMixinABC from ...operations._operations import build_in_interface_fixed_request, build_routes_fixed_request from .._configuration import RoutesClientConfiguration -from .._vendor import RoutesClientMixinABC T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, AsyncHttpResponse], T, Dict[str, Any]], Any]] @@ -82,7 +82,7 @@ async def fixed(self, **kwargs: Any) -> None: return cls(pipeline_response, None, {}) # type: ignore -class RoutesClientOperationsMixin(RoutesClientMixinABC): +class RoutesClientOperationsMixin(ClientMixinABC[AsyncPipelineClient, RoutesClientConfiguration]): async def fixed(self, **kwargs: Any) -> None: """fixed. diff --git a/packages/typespec-python/test/unbranded/generated/routes/routes/operations/_operations.py b/packages/typespec-python/test/unbranded/generated/routes/routes/operations/_operations.py index 6c354d0003f..ab164941121 100644 --- a/packages/typespec-python/test/unbranded/generated/routes/routes/operations/_operations.py +++ b/packages/typespec-python/test/unbranded/generated/routes/routes/operations/_operations.py @@ -15,8 +15,8 @@ from corehttp.runtime.pipeline import PipelineResponse from .._configuration import RoutesClientConfiguration -from .._serialization import Deserializer, Serializer -from .._vendor import RoutesClientMixinABC +from .._utils.serialization import Deserializer, Serializer +from .._utils.utils import ClientMixinABC T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] @@ -98,7 +98,7 @@ def fixed(self, **kwargs: Any) -> None: # pylint: disable=inconsistent-return-s return cls(pipeline_response, None, {}) # type: ignore -class RoutesClientOperationsMixin(RoutesClientMixinABC): +class RoutesClientOperationsMixin(ClientMixinABC[PipelineClient, RoutesClientConfiguration]): def fixed(self, **kwargs: Any) -> None: # pylint: disable=inconsistent-return-statements """fixed. diff --git a/packages/typespec-python/test/unbranded/generated/routes/routes/pathparameters/aio/operations/_operations.py b/packages/typespec-python/test/unbranded/generated/routes/routes/pathparameters/aio/operations/_operations.py index ec22c47af6b..dcb0f611c83 100644 --- a/packages/typespec-python/test/unbranded/generated/routes/routes/pathparameters/aio/operations/_operations.py +++ b/packages/typespec-python/test/unbranded/generated/routes/routes/pathparameters/aio/operations/_operations.py @@ -14,7 +14,7 @@ from corehttp.runtime import AsyncPipelineClient from corehttp.runtime.pipeline import PipelineResponse -from ...._serialization import Deserializer, Serializer +from ...._utils.serialization import Deserializer, Serializer from ....aio._configuration import RoutesClientConfiguration from ...labelexpansion.aio.operations._operations import PathParametersLabelExpansionOperations from ...matrixexpansion.aio.operations._operations import PathParametersMatrixExpansionOperations diff --git a/packages/typespec-python/test/unbranded/generated/routes/routes/pathparameters/labelexpansion/aio/operations/_operations.py b/packages/typespec-python/test/unbranded/generated/routes/routes/pathparameters/labelexpansion/aio/operations/_operations.py index 06bc5d1c3df..41476161278 100644 --- a/packages/typespec-python/test/unbranded/generated/routes/routes/pathparameters/labelexpansion/aio/operations/_operations.py +++ b/packages/typespec-python/test/unbranded/generated/routes/routes/pathparameters/labelexpansion/aio/operations/_operations.py @@ -1,7 +1,7 @@ # coding=utf-8 from corehttp.runtime import AsyncPipelineClient -from ....._serialization import Deserializer, Serializer +from ....._utils.serialization import Deserializer, Serializer from .....aio._configuration import RoutesClientConfiguration from ...explode.aio.operations._operations import PathParametersLabelExpansionExplodeOperations from ...standard.aio.operations._operations import PathParametersLabelExpansionStandardOperations diff --git a/packages/typespec-python/test/unbranded/generated/routes/routes/pathparameters/labelexpansion/explode/aio/operations/_operations.py b/packages/typespec-python/test/unbranded/generated/routes/routes/pathparameters/labelexpansion/explode/aio/operations/_operations.py index dbcf41e6581..07fd19b0a04 100644 --- a/packages/typespec-python/test/unbranded/generated/routes/routes/pathparameters/labelexpansion/explode/aio/operations/_operations.py +++ b/packages/typespec-python/test/unbranded/generated/routes/routes/pathparameters/labelexpansion/explode/aio/operations/_operations.py @@ -14,7 +14,7 @@ from corehttp.runtime import AsyncPipelineClient from corehttp.runtime.pipeline import PipelineResponse -from ......_serialization import Deserializer, Serializer +from ......_utils.serialization import Deserializer, Serializer from ......aio._configuration import RoutesClientConfiguration from ...operations._operations import ( build_path_parameters_label_expansion_explode_array_request, diff --git a/packages/typespec-python/test/unbranded/generated/routes/routes/pathparameters/labelexpansion/explode/operations/_operations.py b/packages/typespec-python/test/unbranded/generated/routes/routes/pathparameters/labelexpansion/explode/operations/_operations.py index 39543ad9282..3d60dcfe12a 100644 --- a/packages/typespec-python/test/unbranded/generated/routes/routes/pathparameters/labelexpansion/explode/operations/_operations.py +++ b/packages/typespec-python/test/unbranded/generated/routes/routes/pathparameters/labelexpansion/explode/operations/_operations.py @@ -15,7 +15,7 @@ from corehttp.runtime.pipeline import PipelineResponse from ....._configuration import RoutesClientConfiguration -from ....._serialization import Deserializer, Serializer +from ....._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/typespec-python/test/unbranded/generated/routes/routes/pathparameters/labelexpansion/operations/_operations.py b/packages/typespec-python/test/unbranded/generated/routes/routes/pathparameters/labelexpansion/operations/_operations.py index 575d7c574d6..eb11f394232 100644 --- a/packages/typespec-python/test/unbranded/generated/routes/routes/pathparameters/labelexpansion/operations/_operations.py +++ b/packages/typespec-python/test/unbranded/generated/routes/routes/pathparameters/labelexpansion/operations/_operations.py @@ -2,7 +2,7 @@ from corehttp.runtime import PipelineClient from ...._configuration import RoutesClientConfiguration -from ...._serialization import Deserializer, Serializer +from ...._utils.serialization import Deserializer, Serializer from ..explode.operations._operations import PathParametersLabelExpansionExplodeOperations from ..standard.operations._operations import PathParametersLabelExpansionStandardOperations diff --git a/packages/typespec-python/test/unbranded/generated/routes/routes/pathparameters/labelexpansion/standard/aio/operations/_operations.py b/packages/typespec-python/test/unbranded/generated/routes/routes/pathparameters/labelexpansion/standard/aio/operations/_operations.py index 1ca439cd3c7..3550967c287 100644 --- a/packages/typespec-python/test/unbranded/generated/routes/routes/pathparameters/labelexpansion/standard/aio/operations/_operations.py +++ b/packages/typespec-python/test/unbranded/generated/routes/routes/pathparameters/labelexpansion/standard/aio/operations/_operations.py @@ -14,7 +14,7 @@ from corehttp.runtime import AsyncPipelineClient from corehttp.runtime.pipeline import PipelineResponse -from ......_serialization import Deserializer, Serializer +from ......_utils.serialization import Deserializer, Serializer from ......aio._configuration import RoutesClientConfiguration from ...operations._operations import ( build_path_parameters_label_expansion_standard_array_request, diff --git a/packages/typespec-python/test/unbranded/generated/routes/routes/pathparameters/labelexpansion/standard/operations/_operations.py b/packages/typespec-python/test/unbranded/generated/routes/routes/pathparameters/labelexpansion/standard/operations/_operations.py index 6e89161d753..0f6e9c3d7b6 100644 --- a/packages/typespec-python/test/unbranded/generated/routes/routes/pathparameters/labelexpansion/standard/operations/_operations.py +++ b/packages/typespec-python/test/unbranded/generated/routes/routes/pathparameters/labelexpansion/standard/operations/_operations.py @@ -15,7 +15,7 @@ from corehttp.runtime.pipeline import PipelineResponse from ....._configuration import RoutesClientConfiguration -from ....._serialization import Deserializer, Serializer +from ....._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/typespec-python/test/unbranded/generated/routes/routes/pathparameters/matrixexpansion/aio/operations/_operations.py b/packages/typespec-python/test/unbranded/generated/routes/routes/pathparameters/matrixexpansion/aio/operations/_operations.py index f53734c0229..0380245802e 100644 --- a/packages/typespec-python/test/unbranded/generated/routes/routes/pathparameters/matrixexpansion/aio/operations/_operations.py +++ b/packages/typespec-python/test/unbranded/generated/routes/routes/pathparameters/matrixexpansion/aio/operations/_operations.py @@ -1,7 +1,7 @@ # coding=utf-8 from corehttp.runtime import AsyncPipelineClient -from ....._serialization import Deserializer, Serializer +from ....._utils.serialization import Deserializer, Serializer from .....aio._configuration import RoutesClientConfiguration from ...explode.aio.operations._operations import PathParametersMatrixExpansionExplodeOperations from ...standard.aio.operations._operations import PathParametersMatrixExpansionStandardOperations diff --git a/packages/typespec-python/test/unbranded/generated/routes/routes/pathparameters/matrixexpansion/explode/aio/operations/_operations.py b/packages/typespec-python/test/unbranded/generated/routes/routes/pathparameters/matrixexpansion/explode/aio/operations/_operations.py index d2cc8110979..4103e5e53dd 100644 --- a/packages/typespec-python/test/unbranded/generated/routes/routes/pathparameters/matrixexpansion/explode/aio/operations/_operations.py +++ b/packages/typespec-python/test/unbranded/generated/routes/routes/pathparameters/matrixexpansion/explode/aio/operations/_operations.py @@ -14,7 +14,7 @@ from corehttp.runtime import AsyncPipelineClient from corehttp.runtime.pipeline import PipelineResponse -from ......_serialization import Deserializer, Serializer +from ......_utils.serialization import Deserializer, Serializer from ......aio._configuration import RoutesClientConfiguration from ...operations._operations import ( build_path_parameters_matrix_expansion_explode_array_request, diff --git a/packages/typespec-python/test/unbranded/generated/routes/routes/pathparameters/matrixexpansion/explode/operations/_operations.py b/packages/typespec-python/test/unbranded/generated/routes/routes/pathparameters/matrixexpansion/explode/operations/_operations.py index 1001ee8eb00..d94c07827b6 100644 --- a/packages/typespec-python/test/unbranded/generated/routes/routes/pathparameters/matrixexpansion/explode/operations/_operations.py +++ b/packages/typespec-python/test/unbranded/generated/routes/routes/pathparameters/matrixexpansion/explode/operations/_operations.py @@ -15,7 +15,7 @@ from corehttp.runtime.pipeline import PipelineResponse from ....._configuration import RoutesClientConfiguration -from ....._serialization import Deserializer, Serializer +from ....._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/typespec-python/test/unbranded/generated/routes/routes/pathparameters/matrixexpansion/operations/_operations.py b/packages/typespec-python/test/unbranded/generated/routes/routes/pathparameters/matrixexpansion/operations/_operations.py index 03b794c2cfd..67148dc3a14 100644 --- a/packages/typespec-python/test/unbranded/generated/routes/routes/pathparameters/matrixexpansion/operations/_operations.py +++ b/packages/typespec-python/test/unbranded/generated/routes/routes/pathparameters/matrixexpansion/operations/_operations.py @@ -2,7 +2,7 @@ from corehttp.runtime import PipelineClient from ...._configuration import RoutesClientConfiguration -from ...._serialization import Deserializer, Serializer +from ...._utils.serialization import Deserializer, Serializer from ..explode.operations._operations import PathParametersMatrixExpansionExplodeOperations from ..standard.operations._operations import PathParametersMatrixExpansionStandardOperations diff --git a/packages/typespec-python/test/unbranded/generated/routes/routes/pathparameters/matrixexpansion/standard/aio/operations/_operations.py b/packages/typespec-python/test/unbranded/generated/routes/routes/pathparameters/matrixexpansion/standard/aio/operations/_operations.py index 9b30d499efc..7cd56e35d6c 100644 --- a/packages/typespec-python/test/unbranded/generated/routes/routes/pathparameters/matrixexpansion/standard/aio/operations/_operations.py +++ b/packages/typespec-python/test/unbranded/generated/routes/routes/pathparameters/matrixexpansion/standard/aio/operations/_operations.py @@ -14,7 +14,7 @@ from corehttp.runtime import AsyncPipelineClient from corehttp.runtime.pipeline import PipelineResponse -from ......_serialization import Deserializer, Serializer +from ......_utils.serialization import Deserializer, Serializer from ......aio._configuration import RoutesClientConfiguration from ...operations._operations import ( build_path_parameters_matrix_expansion_standard_array_request, diff --git a/packages/typespec-python/test/unbranded/generated/routes/routes/pathparameters/matrixexpansion/standard/operations/_operations.py b/packages/typespec-python/test/unbranded/generated/routes/routes/pathparameters/matrixexpansion/standard/operations/_operations.py index e66d94e5d37..affa736a4a6 100644 --- a/packages/typespec-python/test/unbranded/generated/routes/routes/pathparameters/matrixexpansion/standard/operations/_operations.py +++ b/packages/typespec-python/test/unbranded/generated/routes/routes/pathparameters/matrixexpansion/standard/operations/_operations.py @@ -15,7 +15,7 @@ from corehttp.runtime.pipeline import PipelineResponse from ....._configuration import RoutesClientConfiguration -from ....._serialization import Deserializer, Serializer +from ....._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/typespec-python/test/unbranded/generated/routes/routes/pathparameters/operations/_operations.py b/packages/typespec-python/test/unbranded/generated/routes/routes/pathparameters/operations/_operations.py index 9bbe6ea0c25..1150659c719 100644 --- a/packages/typespec-python/test/unbranded/generated/routes/routes/pathparameters/operations/_operations.py +++ b/packages/typespec-python/test/unbranded/generated/routes/routes/pathparameters/operations/_operations.py @@ -15,7 +15,7 @@ from corehttp.runtime.pipeline import PipelineResponse from ..._configuration import RoutesClientConfiguration -from ..._serialization import Deserializer, Serializer +from ..._utils.serialization import Deserializer, Serializer from ..labelexpansion.operations._operations import PathParametersLabelExpansionOperations from ..matrixexpansion.operations._operations import PathParametersMatrixExpansionOperations from ..pathexpansion.operations._operations import PathParametersPathExpansionOperations diff --git a/packages/typespec-python/test/unbranded/generated/routes/routes/pathparameters/pathexpansion/aio/operations/_operations.py b/packages/typespec-python/test/unbranded/generated/routes/routes/pathparameters/pathexpansion/aio/operations/_operations.py index 0e9497c9ad2..7c690d3e428 100644 --- a/packages/typespec-python/test/unbranded/generated/routes/routes/pathparameters/pathexpansion/aio/operations/_operations.py +++ b/packages/typespec-python/test/unbranded/generated/routes/routes/pathparameters/pathexpansion/aio/operations/_operations.py @@ -1,7 +1,7 @@ # coding=utf-8 from corehttp.runtime import AsyncPipelineClient -from ....._serialization import Deserializer, Serializer +from ....._utils.serialization import Deserializer, Serializer from .....aio._configuration import RoutesClientConfiguration from ...explode.aio.operations._operations import PathParametersPathExpansionExplodeOperations from ...standard.aio.operations._operations import PathParametersPathExpansionStandardOperations diff --git a/packages/typespec-python/test/unbranded/generated/routes/routes/pathparameters/pathexpansion/explode/aio/operations/_operations.py b/packages/typespec-python/test/unbranded/generated/routes/routes/pathparameters/pathexpansion/explode/aio/operations/_operations.py index 097e4bfb6e3..fc513e94b38 100644 --- a/packages/typespec-python/test/unbranded/generated/routes/routes/pathparameters/pathexpansion/explode/aio/operations/_operations.py +++ b/packages/typespec-python/test/unbranded/generated/routes/routes/pathparameters/pathexpansion/explode/aio/operations/_operations.py @@ -14,7 +14,7 @@ from corehttp.runtime import AsyncPipelineClient from corehttp.runtime.pipeline import PipelineResponse -from ......_serialization import Deserializer, Serializer +from ......_utils.serialization import Deserializer, Serializer from ......aio._configuration import RoutesClientConfiguration from ...operations._operations import ( build_path_parameters_path_expansion_explode_array_request, diff --git a/packages/typespec-python/test/unbranded/generated/routes/routes/pathparameters/pathexpansion/explode/operations/_operations.py b/packages/typespec-python/test/unbranded/generated/routes/routes/pathparameters/pathexpansion/explode/operations/_operations.py index 937e53482cb..18e2309a2cf 100644 --- a/packages/typespec-python/test/unbranded/generated/routes/routes/pathparameters/pathexpansion/explode/operations/_operations.py +++ b/packages/typespec-python/test/unbranded/generated/routes/routes/pathparameters/pathexpansion/explode/operations/_operations.py @@ -15,7 +15,7 @@ from corehttp.runtime.pipeline import PipelineResponse from ....._configuration import RoutesClientConfiguration -from ....._serialization import Deserializer, Serializer +from ....._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/typespec-python/test/unbranded/generated/routes/routes/pathparameters/pathexpansion/operations/_operations.py b/packages/typespec-python/test/unbranded/generated/routes/routes/pathparameters/pathexpansion/operations/_operations.py index 496b774cf6c..0b0a93e617a 100644 --- a/packages/typespec-python/test/unbranded/generated/routes/routes/pathparameters/pathexpansion/operations/_operations.py +++ b/packages/typespec-python/test/unbranded/generated/routes/routes/pathparameters/pathexpansion/operations/_operations.py @@ -2,7 +2,7 @@ from corehttp.runtime import PipelineClient from ...._configuration import RoutesClientConfiguration -from ...._serialization import Deserializer, Serializer +from ...._utils.serialization import Deserializer, Serializer from ..explode.operations._operations import PathParametersPathExpansionExplodeOperations from ..standard.operations._operations import PathParametersPathExpansionStandardOperations diff --git a/packages/typespec-python/test/unbranded/generated/routes/routes/pathparameters/pathexpansion/standard/aio/operations/_operations.py b/packages/typespec-python/test/unbranded/generated/routes/routes/pathparameters/pathexpansion/standard/aio/operations/_operations.py index 367e9c732d0..842d93590eb 100644 --- a/packages/typespec-python/test/unbranded/generated/routes/routes/pathparameters/pathexpansion/standard/aio/operations/_operations.py +++ b/packages/typespec-python/test/unbranded/generated/routes/routes/pathparameters/pathexpansion/standard/aio/operations/_operations.py @@ -14,7 +14,7 @@ from corehttp.runtime import AsyncPipelineClient from corehttp.runtime.pipeline import PipelineResponse -from ......_serialization import Deserializer, Serializer +from ......_utils.serialization import Deserializer, Serializer from ......aio._configuration import RoutesClientConfiguration from ...operations._operations import ( build_path_parameters_path_expansion_standard_array_request, diff --git a/packages/typespec-python/test/unbranded/generated/routes/routes/pathparameters/pathexpansion/standard/operations/_operations.py b/packages/typespec-python/test/unbranded/generated/routes/routes/pathparameters/pathexpansion/standard/operations/_operations.py index 35898267f40..aa148e7b978 100644 --- a/packages/typespec-python/test/unbranded/generated/routes/routes/pathparameters/pathexpansion/standard/operations/_operations.py +++ b/packages/typespec-python/test/unbranded/generated/routes/routes/pathparameters/pathexpansion/standard/operations/_operations.py @@ -15,7 +15,7 @@ from corehttp.runtime.pipeline import PipelineResponse from ....._configuration import RoutesClientConfiguration -from ....._serialization import Deserializer, Serializer +from ....._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/typespec-python/test/unbranded/generated/routes/routes/pathparameters/reservedexpansion/aio/operations/_operations.py b/packages/typespec-python/test/unbranded/generated/routes/routes/pathparameters/reservedexpansion/aio/operations/_operations.py index 55ee6250e00..f851227d735 100644 --- a/packages/typespec-python/test/unbranded/generated/routes/routes/pathparameters/reservedexpansion/aio/operations/_operations.py +++ b/packages/typespec-python/test/unbranded/generated/routes/routes/pathparameters/reservedexpansion/aio/operations/_operations.py @@ -14,7 +14,7 @@ from corehttp.runtime import AsyncPipelineClient from corehttp.runtime.pipeline import PipelineResponse -from ....._serialization import Deserializer, Serializer +from ....._utils.serialization import Deserializer, Serializer from .....aio._configuration import RoutesClientConfiguration from ...operations._operations import ( build_path_parameters_reserved_expansion_annotation_request, diff --git a/packages/typespec-python/test/unbranded/generated/routes/routes/pathparameters/reservedexpansion/operations/_operations.py b/packages/typespec-python/test/unbranded/generated/routes/routes/pathparameters/reservedexpansion/operations/_operations.py index 6b9e9813a7d..07dbfb0f428 100644 --- a/packages/typespec-python/test/unbranded/generated/routes/routes/pathparameters/reservedexpansion/operations/_operations.py +++ b/packages/typespec-python/test/unbranded/generated/routes/routes/pathparameters/reservedexpansion/operations/_operations.py @@ -15,7 +15,7 @@ from corehttp.runtime.pipeline import PipelineResponse from ...._configuration import RoutesClientConfiguration -from ...._serialization import Deserializer, Serializer +from ...._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/typespec-python/test/unbranded/generated/routes/routes/pathparameters/simpleexpansion/aio/operations/_operations.py b/packages/typespec-python/test/unbranded/generated/routes/routes/pathparameters/simpleexpansion/aio/operations/_operations.py index a14ddae15db..db0a1145ef1 100644 --- a/packages/typespec-python/test/unbranded/generated/routes/routes/pathparameters/simpleexpansion/aio/operations/_operations.py +++ b/packages/typespec-python/test/unbranded/generated/routes/routes/pathparameters/simpleexpansion/aio/operations/_operations.py @@ -1,7 +1,7 @@ # coding=utf-8 from corehttp.runtime import AsyncPipelineClient -from ....._serialization import Deserializer, Serializer +from ....._utils.serialization import Deserializer, Serializer from .....aio._configuration import RoutesClientConfiguration from ...explode.aio.operations._operations import PathParametersSimpleExpansionExplodeOperations from ...standard.aio.operations._operations import PathParametersSimpleExpansionStandardOperations diff --git a/packages/typespec-python/test/unbranded/generated/routes/routes/pathparameters/simpleexpansion/explode/aio/operations/_operations.py b/packages/typespec-python/test/unbranded/generated/routes/routes/pathparameters/simpleexpansion/explode/aio/operations/_operations.py index 281717ae3b3..58ce0e9c1b8 100644 --- a/packages/typespec-python/test/unbranded/generated/routes/routes/pathparameters/simpleexpansion/explode/aio/operations/_operations.py +++ b/packages/typespec-python/test/unbranded/generated/routes/routes/pathparameters/simpleexpansion/explode/aio/operations/_operations.py @@ -14,7 +14,7 @@ from corehttp.runtime import AsyncPipelineClient from corehttp.runtime.pipeline import PipelineResponse -from ......_serialization import Deserializer, Serializer +from ......_utils.serialization import Deserializer, Serializer from ......aio._configuration import RoutesClientConfiguration from ...operations._operations import ( build_path_parameters_simple_expansion_explode_array_request, diff --git a/packages/typespec-python/test/unbranded/generated/routes/routes/pathparameters/simpleexpansion/explode/operations/_operations.py b/packages/typespec-python/test/unbranded/generated/routes/routes/pathparameters/simpleexpansion/explode/operations/_operations.py index 49dbac7802c..ef6b5ba12fc 100644 --- a/packages/typespec-python/test/unbranded/generated/routes/routes/pathparameters/simpleexpansion/explode/operations/_operations.py +++ b/packages/typespec-python/test/unbranded/generated/routes/routes/pathparameters/simpleexpansion/explode/operations/_operations.py @@ -15,7 +15,7 @@ from corehttp.runtime.pipeline import PipelineResponse from ....._configuration import RoutesClientConfiguration -from ....._serialization import Deserializer, Serializer +from ....._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/typespec-python/test/unbranded/generated/routes/routes/pathparameters/simpleexpansion/operations/_operations.py b/packages/typespec-python/test/unbranded/generated/routes/routes/pathparameters/simpleexpansion/operations/_operations.py index 3acf0e0defb..ef98b2f2ec9 100644 --- a/packages/typespec-python/test/unbranded/generated/routes/routes/pathparameters/simpleexpansion/operations/_operations.py +++ b/packages/typespec-python/test/unbranded/generated/routes/routes/pathparameters/simpleexpansion/operations/_operations.py @@ -2,7 +2,7 @@ from corehttp.runtime import PipelineClient from ...._configuration import RoutesClientConfiguration -from ...._serialization import Deserializer, Serializer +from ...._utils.serialization import Deserializer, Serializer from ..explode.operations._operations import PathParametersSimpleExpansionExplodeOperations from ..standard.operations._operations import PathParametersSimpleExpansionStandardOperations diff --git a/packages/typespec-python/test/unbranded/generated/routes/routes/pathparameters/simpleexpansion/standard/aio/operations/_operations.py b/packages/typespec-python/test/unbranded/generated/routes/routes/pathparameters/simpleexpansion/standard/aio/operations/_operations.py index a9770073974..a3078ffed71 100644 --- a/packages/typespec-python/test/unbranded/generated/routes/routes/pathparameters/simpleexpansion/standard/aio/operations/_operations.py +++ b/packages/typespec-python/test/unbranded/generated/routes/routes/pathparameters/simpleexpansion/standard/aio/operations/_operations.py @@ -14,7 +14,7 @@ from corehttp.runtime import AsyncPipelineClient from corehttp.runtime.pipeline import PipelineResponse -from ......_serialization import Deserializer, Serializer +from ......_utils.serialization import Deserializer, Serializer from ......aio._configuration import RoutesClientConfiguration from ...operations._operations import ( build_path_parameters_simple_expansion_standard_array_request, diff --git a/packages/typespec-python/test/unbranded/generated/routes/routes/pathparameters/simpleexpansion/standard/operations/_operations.py b/packages/typespec-python/test/unbranded/generated/routes/routes/pathparameters/simpleexpansion/standard/operations/_operations.py index 745999d2eac..23ef35356eb 100644 --- a/packages/typespec-python/test/unbranded/generated/routes/routes/pathparameters/simpleexpansion/standard/operations/_operations.py +++ b/packages/typespec-python/test/unbranded/generated/routes/routes/pathparameters/simpleexpansion/standard/operations/_operations.py @@ -15,7 +15,7 @@ from corehttp.runtime.pipeline import PipelineResponse from ....._configuration import RoutesClientConfiguration -from ....._serialization import Deserializer, Serializer +from ....._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/typespec-python/test/unbranded/generated/routes/routes/queryparameters/aio/operations/_operations.py b/packages/typespec-python/test/unbranded/generated/routes/routes/queryparameters/aio/operations/_operations.py index 6a823921510..bd67cff97cf 100644 --- a/packages/typespec-python/test/unbranded/generated/routes/routes/queryparameters/aio/operations/_operations.py +++ b/packages/typespec-python/test/unbranded/generated/routes/routes/queryparameters/aio/operations/_operations.py @@ -14,7 +14,7 @@ from corehttp.runtime import AsyncPipelineClient from corehttp.runtime.pipeline import PipelineResponse -from ...._serialization import Deserializer, Serializer +from ...._utils.serialization import Deserializer, Serializer from ....aio._configuration import RoutesClientConfiguration from ...operations._operations import ( build_query_parameters_annotation_only_request, diff --git a/packages/typespec-python/test/unbranded/generated/routes/routes/queryparameters/operations/_operations.py b/packages/typespec-python/test/unbranded/generated/routes/routes/queryparameters/operations/_operations.py index b90e2102663..799c091bfc1 100644 --- a/packages/typespec-python/test/unbranded/generated/routes/routes/queryparameters/operations/_operations.py +++ b/packages/typespec-python/test/unbranded/generated/routes/routes/queryparameters/operations/_operations.py @@ -16,7 +16,7 @@ from corehttp.utils import case_insensitive_dict from ..._configuration import RoutesClientConfiguration -from ..._serialization import Deserializer, Serializer +from ..._utils.serialization import Deserializer, Serializer from ..querycontinuation.operations._operations import QueryParametersQueryContinuationOperations from ..queryexpansion.operations._operations import QueryParametersQueryExpansionOperations diff --git a/packages/typespec-python/test/unbranded/generated/routes/routes/queryparameters/querycontinuation/aio/operations/_operations.py b/packages/typespec-python/test/unbranded/generated/routes/routes/queryparameters/querycontinuation/aio/operations/_operations.py index 0e49410ae39..8340e017a49 100644 --- a/packages/typespec-python/test/unbranded/generated/routes/routes/queryparameters/querycontinuation/aio/operations/_operations.py +++ b/packages/typespec-python/test/unbranded/generated/routes/routes/queryparameters/querycontinuation/aio/operations/_operations.py @@ -1,7 +1,7 @@ # coding=utf-8 from corehttp.runtime import AsyncPipelineClient -from ....._serialization import Deserializer, Serializer +from ....._utils.serialization import Deserializer, Serializer from .....aio._configuration import RoutesClientConfiguration from ...explode.aio.operations._operations import QueryParametersQueryContinuationExplodeOperations from ...standard.aio.operations._operations import QueryParametersQueryContinuationStandardOperations diff --git a/packages/typespec-python/test/unbranded/generated/routes/routes/queryparameters/querycontinuation/explode/aio/operations/_operations.py b/packages/typespec-python/test/unbranded/generated/routes/routes/queryparameters/querycontinuation/explode/aio/operations/_operations.py index 5126b654423..b9db7f053b0 100644 --- a/packages/typespec-python/test/unbranded/generated/routes/routes/queryparameters/querycontinuation/explode/aio/operations/_operations.py +++ b/packages/typespec-python/test/unbranded/generated/routes/routes/queryparameters/querycontinuation/explode/aio/operations/_operations.py @@ -14,7 +14,7 @@ from corehttp.runtime import AsyncPipelineClient from corehttp.runtime.pipeline import PipelineResponse -from ......_serialization import Deserializer, Serializer +from ......_utils.serialization import Deserializer, Serializer from ......aio._configuration import RoutesClientConfiguration from ...operations._operations import ( build_query_parameters_query_continuation_explode_array_request, diff --git a/packages/typespec-python/test/unbranded/generated/routes/routes/queryparameters/querycontinuation/explode/operations/_operations.py b/packages/typespec-python/test/unbranded/generated/routes/routes/queryparameters/querycontinuation/explode/operations/_operations.py index e104bd93dd6..95f8d0dbbe0 100644 --- a/packages/typespec-python/test/unbranded/generated/routes/routes/queryparameters/querycontinuation/explode/operations/_operations.py +++ b/packages/typespec-python/test/unbranded/generated/routes/routes/queryparameters/querycontinuation/explode/operations/_operations.py @@ -16,7 +16,7 @@ from corehttp.utils import case_insensitive_dict from ....._configuration import RoutesClientConfiguration -from ....._serialization import Deserializer, Serializer +from ....._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/typespec-python/test/unbranded/generated/routes/routes/queryparameters/querycontinuation/operations/_operations.py b/packages/typespec-python/test/unbranded/generated/routes/routes/queryparameters/querycontinuation/operations/_operations.py index 537bf47eae1..a88228ca603 100644 --- a/packages/typespec-python/test/unbranded/generated/routes/routes/queryparameters/querycontinuation/operations/_operations.py +++ b/packages/typespec-python/test/unbranded/generated/routes/routes/queryparameters/querycontinuation/operations/_operations.py @@ -2,7 +2,7 @@ from corehttp.runtime import PipelineClient from ...._configuration import RoutesClientConfiguration -from ...._serialization import Deserializer, Serializer +from ...._utils.serialization import Deserializer, Serializer from ..explode.operations._operations import QueryParametersQueryContinuationExplodeOperations from ..standard.operations._operations import QueryParametersQueryContinuationStandardOperations diff --git a/packages/typespec-python/test/unbranded/generated/routes/routes/queryparameters/querycontinuation/standard/aio/operations/_operations.py b/packages/typespec-python/test/unbranded/generated/routes/routes/queryparameters/querycontinuation/standard/aio/operations/_operations.py index d20314ffe69..d351f85574a 100644 --- a/packages/typespec-python/test/unbranded/generated/routes/routes/queryparameters/querycontinuation/standard/aio/operations/_operations.py +++ b/packages/typespec-python/test/unbranded/generated/routes/routes/queryparameters/querycontinuation/standard/aio/operations/_operations.py @@ -14,7 +14,7 @@ from corehttp.runtime import AsyncPipelineClient from corehttp.runtime.pipeline import PipelineResponse -from ......_serialization import Deserializer, Serializer +from ......_utils.serialization import Deserializer, Serializer from ......aio._configuration import RoutesClientConfiguration from ...operations._operations import ( build_query_parameters_query_continuation_standard_array_request, diff --git a/packages/typespec-python/test/unbranded/generated/routes/routes/queryparameters/querycontinuation/standard/operations/_operations.py b/packages/typespec-python/test/unbranded/generated/routes/routes/queryparameters/querycontinuation/standard/operations/_operations.py index 5cbe0197dbf..6cfb0bed311 100644 --- a/packages/typespec-python/test/unbranded/generated/routes/routes/queryparameters/querycontinuation/standard/operations/_operations.py +++ b/packages/typespec-python/test/unbranded/generated/routes/routes/queryparameters/querycontinuation/standard/operations/_operations.py @@ -16,7 +16,7 @@ from corehttp.utils import case_insensitive_dict from ....._configuration import RoutesClientConfiguration -from ....._serialization import Deserializer, Serializer +from ....._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/typespec-python/test/unbranded/generated/routes/routes/queryparameters/queryexpansion/aio/operations/_operations.py b/packages/typespec-python/test/unbranded/generated/routes/routes/queryparameters/queryexpansion/aio/operations/_operations.py index 730b90a0bd8..9bad903379f 100644 --- a/packages/typespec-python/test/unbranded/generated/routes/routes/queryparameters/queryexpansion/aio/operations/_operations.py +++ b/packages/typespec-python/test/unbranded/generated/routes/routes/queryparameters/queryexpansion/aio/operations/_operations.py @@ -1,7 +1,7 @@ # coding=utf-8 from corehttp.runtime import AsyncPipelineClient -from ....._serialization import Deserializer, Serializer +from ....._utils.serialization import Deserializer, Serializer from .....aio._configuration import RoutesClientConfiguration from ...explode.aio.operations._operations import QueryParametersQueryExpansionExplodeOperations from ...standard.aio.operations._operations import QueryParametersQueryExpansionStandardOperations diff --git a/packages/typespec-python/test/unbranded/generated/routes/routes/queryparameters/queryexpansion/explode/aio/operations/_operations.py b/packages/typespec-python/test/unbranded/generated/routes/routes/queryparameters/queryexpansion/explode/aio/operations/_operations.py index 9cfa0e4af24..ad86f962014 100644 --- a/packages/typespec-python/test/unbranded/generated/routes/routes/queryparameters/queryexpansion/explode/aio/operations/_operations.py +++ b/packages/typespec-python/test/unbranded/generated/routes/routes/queryparameters/queryexpansion/explode/aio/operations/_operations.py @@ -14,7 +14,7 @@ from corehttp.runtime import AsyncPipelineClient from corehttp.runtime.pipeline import PipelineResponse -from ......_serialization import Deserializer, Serializer +from ......_utils.serialization import Deserializer, Serializer from ......aio._configuration import RoutesClientConfiguration from ...operations._operations import ( build_query_parameters_query_expansion_explode_array_request, diff --git a/packages/typespec-python/test/unbranded/generated/routes/routes/queryparameters/queryexpansion/explode/operations/_operations.py b/packages/typespec-python/test/unbranded/generated/routes/routes/queryparameters/queryexpansion/explode/operations/_operations.py index 931a85a6520..2ae8cf2e46f 100644 --- a/packages/typespec-python/test/unbranded/generated/routes/routes/queryparameters/queryexpansion/explode/operations/_operations.py +++ b/packages/typespec-python/test/unbranded/generated/routes/routes/queryparameters/queryexpansion/explode/operations/_operations.py @@ -16,7 +16,7 @@ from corehttp.utils import case_insensitive_dict from ....._configuration import RoutesClientConfiguration -from ....._serialization import Deserializer, Serializer +from ....._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/typespec-python/test/unbranded/generated/routes/routes/queryparameters/queryexpansion/operations/_operations.py b/packages/typespec-python/test/unbranded/generated/routes/routes/queryparameters/queryexpansion/operations/_operations.py index 0438873b620..7e061fe6d2f 100644 --- a/packages/typespec-python/test/unbranded/generated/routes/routes/queryparameters/queryexpansion/operations/_operations.py +++ b/packages/typespec-python/test/unbranded/generated/routes/routes/queryparameters/queryexpansion/operations/_operations.py @@ -2,7 +2,7 @@ from corehttp.runtime import PipelineClient from ...._configuration import RoutesClientConfiguration -from ...._serialization import Deserializer, Serializer +from ...._utils.serialization import Deserializer, Serializer from ..explode.operations._operations import QueryParametersQueryExpansionExplodeOperations from ..standard.operations._operations import QueryParametersQueryExpansionStandardOperations diff --git a/packages/typespec-python/test/unbranded/generated/routes/routes/queryparameters/queryexpansion/standard/aio/operations/_operations.py b/packages/typespec-python/test/unbranded/generated/routes/routes/queryparameters/queryexpansion/standard/aio/operations/_operations.py index 65fea19cd7e..6a851eeb699 100644 --- a/packages/typespec-python/test/unbranded/generated/routes/routes/queryparameters/queryexpansion/standard/aio/operations/_operations.py +++ b/packages/typespec-python/test/unbranded/generated/routes/routes/queryparameters/queryexpansion/standard/aio/operations/_operations.py @@ -14,7 +14,7 @@ from corehttp.runtime import AsyncPipelineClient from corehttp.runtime.pipeline import PipelineResponse -from ......_serialization import Deserializer, Serializer +from ......_utils.serialization import Deserializer, Serializer from ......aio._configuration import RoutesClientConfiguration from ...operations._operations import ( build_query_parameters_query_expansion_standard_array_request, diff --git a/packages/typespec-python/test/unbranded/generated/routes/routes/queryparameters/queryexpansion/standard/operations/_operations.py b/packages/typespec-python/test/unbranded/generated/routes/routes/queryparameters/queryexpansion/standard/operations/_operations.py index 5e379222421..7a61d54c731 100644 --- a/packages/typespec-python/test/unbranded/generated/routes/routes/queryparameters/queryexpansion/standard/operations/_operations.py +++ b/packages/typespec-python/test/unbranded/generated/routes/routes/queryparameters/queryexpansion/standard/operations/_operations.py @@ -16,7 +16,7 @@ from corehttp.utils import case_insensitive_dict from ....._configuration import RoutesClientConfiguration -from ....._serialization import Deserializer, Serializer +from ....._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/typespec-python/test/unbranded/generated/serialization-encoded-name-json/serialization/encodedname/json/_client.py b/packages/typespec-python/test/unbranded/generated/serialization-encoded-name-json/serialization/encodedname/json/_client.py index 6ac7e6fd8bf..4aff34de051 100644 --- a/packages/typespec-python/test/unbranded/generated/serialization-encoded-name-json/serialization/encodedname/json/_client.py +++ b/packages/typespec-python/test/unbranded/generated/serialization-encoded-name-json/serialization/encodedname/json/_client.py @@ -8,7 +8,7 @@ from corehttp.runtime import PipelineClient, policies from ._configuration import JsonClientConfiguration -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer from .property.operations import PropertyOperations diff --git a/packages/typespec-python/test/unbranded/generated/serialization-encoded-name-json/serialization/encodedname/json/_utils/__init__.py b/packages/typespec-python/test/unbranded/generated/serialization-encoded-name-json/serialization/encodedname/json/_utils/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/packages/typespec-python/test/unbranded/generated/serialization-encoded-name-json/serialization/encodedname/json/_model_base.py b/packages/typespec-python/test/unbranded/generated/serialization-encoded-name-json/serialization/encodedname/json/_utils/model_base.py similarity index 100% rename from packages/typespec-python/test/unbranded/generated/serialization-encoded-name-json/serialization/encodedname/json/_model_base.py rename to packages/typespec-python/test/unbranded/generated/serialization-encoded-name-json/serialization/encodedname/json/_utils/model_base.py diff --git a/packages/typespec-python/test/unbranded/generated/serialization-encoded-name-json/serialization/encodedname/json/_serialization.py b/packages/typespec-python/test/unbranded/generated/serialization-encoded-name-json/serialization/encodedname/json/_utils/serialization.py similarity index 100% rename from packages/typespec-python/test/unbranded/generated/serialization-encoded-name-json/serialization/encodedname/json/_serialization.py rename to packages/typespec-python/test/unbranded/generated/serialization-encoded-name-json/serialization/encodedname/json/_utils/serialization.py diff --git a/packages/typespec-python/test/unbranded/generated/serialization-encoded-name-json/serialization/encodedname/json/aio/_client.py b/packages/typespec-python/test/unbranded/generated/serialization-encoded-name-json/serialization/encodedname/json/aio/_client.py index 4ef24bac981..3c73b23acbb 100644 --- a/packages/typespec-python/test/unbranded/generated/serialization-encoded-name-json/serialization/encodedname/json/aio/_client.py +++ b/packages/typespec-python/test/unbranded/generated/serialization-encoded-name-json/serialization/encodedname/json/aio/_client.py @@ -7,7 +7,7 @@ from corehttp.rest import AsyncHttpResponse, HttpRequest from corehttp.runtime import AsyncPipelineClient, policies -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ..property.aio.operations import PropertyOperations from ._configuration import JsonClientConfiguration diff --git a/packages/typespec-python/test/unbranded/generated/serialization-encoded-name-json/serialization/encodedname/json/property/aio/operations/_operations.py b/packages/typespec-python/test/unbranded/generated/serialization-encoded-name-json/serialization/encodedname/json/property/aio/operations/_operations.py index 35647059ae6..d5530127621 100644 --- a/packages/typespec-python/test/unbranded/generated/serialization-encoded-name-json/serialization/encodedname/json/property/aio/operations/_operations.py +++ b/packages/typespec-python/test/unbranded/generated/serialization-encoded-name-json/serialization/encodedname/json/property/aio/operations/_operations.py @@ -20,8 +20,8 @@ from corehttp.utils import case_insensitive_dict from ... import models as _models2 -from ...._model_base import SdkJSONEncoder, _deserialize -from ...._serialization import Deserializer, Serializer +from ...._utils.model_base import SdkJSONEncoder, _deserialize +from ...._utils.serialization import Deserializer, Serializer from ....aio._configuration import JsonClientConfiguration from ...operations._operations import build_property_get_request, build_property_send_request diff --git a/packages/typespec-python/test/unbranded/generated/serialization-encoded-name-json/serialization/encodedname/json/property/models/_models.py b/packages/typespec-python/test/unbranded/generated/serialization-encoded-name-json/serialization/encodedname/json/property/models/_models.py index a4629ef6d44..cf340fcb490 100644 --- a/packages/typespec-python/test/unbranded/generated/serialization-encoded-name-json/serialization/encodedname/json/property/models/_models.py +++ b/packages/typespec-python/test/unbranded/generated/serialization-encoded-name-json/serialization/encodedname/json/property/models/_models.py @@ -3,11 +3,10 @@ from typing import Any, Mapping, overload -from ... import _model_base -from ..._model_base import rest_field +from ..._utils.model_base import Model as _Model, rest_field -class JsonEncodedNameModel(_model_base.Model): +class JsonEncodedNameModel(_Model): """JsonEncodedNameModel. :ivar default_name: Pass in true. Required. diff --git a/packages/typespec-python/test/unbranded/generated/serialization-encoded-name-json/serialization/encodedname/json/property/operations/_operations.py b/packages/typespec-python/test/unbranded/generated/serialization-encoded-name-json/serialization/encodedname/json/property/operations/_operations.py index 268dc95afc8..2ebc96c1374 100644 --- a/packages/typespec-python/test/unbranded/generated/serialization-encoded-name-json/serialization/encodedname/json/property/operations/_operations.py +++ b/packages/typespec-python/test/unbranded/generated/serialization-encoded-name-json/serialization/encodedname/json/property/operations/_operations.py @@ -21,8 +21,8 @@ from .. import models as _models1 from ..._configuration import JsonClientConfiguration -from ..._model_base import SdkJSONEncoder, _deserialize -from ..._serialization import Deserializer, Serializer +from ..._utils.model_base import SdkJSONEncoder, _deserialize +from ..._utils.serialization import Deserializer, Serializer JSON = MutableMapping[str, Any] T = TypeVar("T") diff --git a/packages/typespec-python/test/unbranded/generated/server-endpoint-not-defined/server/endpoint/notdefined/_client.py b/packages/typespec-python/test/unbranded/generated/server-endpoint-not-defined/server/endpoint/notdefined/_client.py index 83088747cba..96913e9501c 100644 --- a/packages/typespec-python/test/unbranded/generated/server-endpoint-not-defined/server/endpoint/notdefined/_client.py +++ b/packages/typespec-python/test/unbranded/generated/server-endpoint-not-defined/server/endpoint/notdefined/_client.py @@ -9,7 +9,7 @@ from ._configuration import NotDefinedClientConfiguration from ._operations import NotDefinedClientOperationsMixin -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer class NotDefinedClient(NotDefinedClientOperationsMixin): # pylint: disable=client-accepts-api-version-keyword diff --git a/packages/typespec-python/test/unbranded/generated/server-endpoint-not-defined/server/endpoint/notdefined/_operations/_operations.py b/packages/typespec-python/test/unbranded/generated/server-endpoint-not-defined/server/endpoint/notdefined/_operations/_operations.py index dcbcd58181d..8589d598252 100644 --- a/packages/typespec-python/test/unbranded/generated/server-endpoint-not-defined/server/endpoint/notdefined/_operations/_operations.py +++ b/packages/typespec-python/test/unbranded/generated/server-endpoint-not-defined/server/endpoint/notdefined/_operations/_operations.py @@ -11,10 +11,12 @@ map_error, ) from corehttp.rest import HttpRequest, HttpResponse +from corehttp.runtime import PipelineClient from corehttp.runtime.pipeline import PipelineResponse -from .._serialization import Serializer -from .._vendor import NotDefinedClientMixinABC +from .._configuration import NotDefinedClientConfiguration +from .._utils.serialization import Serializer +from .._utils.utils import ClientMixinABC T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] @@ -30,7 +32,7 @@ def build_not_defined_valid_request(**kwargs: Any) -> HttpRequest: return HttpRequest(method="HEAD", url=_url, **kwargs) -class NotDefinedClientOperationsMixin(NotDefinedClientMixinABC): +class NotDefinedClientOperationsMixin(ClientMixinABC[PipelineClient, NotDefinedClientConfiguration]): def valid(self, **kwargs: Any) -> bool: """valid. diff --git a/packages/typespec-python/test/unbranded/generated/server-endpoint-not-defined/server/endpoint/notdefined/_utils/__init__.py b/packages/typespec-python/test/unbranded/generated/server-endpoint-not-defined/server/endpoint/notdefined/_utils/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/packages/typespec-python/test/unbranded/generated/server-endpoint-not-defined/server/endpoint/notdefined/_model_base.py b/packages/typespec-python/test/unbranded/generated/server-endpoint-not-defined/server/endpoint/notdefined/_utils/model_base.py similarity index 100% rename from packages/typespec-python/test/unbranded/generated/server-endpoint-not-defined/server/endpoint/notdefined/_model_base.py rename to packages/typespec-python/test/unbranded/generated/server-endpoint-not-defined/server/endpoint/notdefined/_utils/model_base.py diff --git a/packages/typespec-python/test/unbranded/generated/server-endpoint-not-defined/server/endpoint/notdefined/_serialization.py b/packages/typespec-python/test/unbranded/generated/server-endpoint-not-defined/server/endpoint/notdefined/_utils/serialization.py similarity index 100% rename from packages/typespec-python/test/unbranded/generated/server-endpoint-not-defined/server/endpoint/notdefined/_serialization.py rename to packages/typespec-python/test/unbranded/generated/server-endpoint-not-defined/server/endpoint/notdefined/_utils/serialization.py diff --git a/packages/typespec-python/test/unbranded/generated/server-endpoint-not-defined/server/endpoint/notdefined/_utils/utils.py b/packages/typespec-python/test/unbranded/generated/server-endpoint-not-defined/server/endpoint/notdefined/_utils/utils.py new file mode 100644 index 00000000000..02aa2f816ea --- /dev/null +++ b/packages/typespec-python/test/unbranded/generated/server-endpoint-not-defined/server/endpoint/notdefined/_utils/utils.py @@ -0,0 +1,18 @@ +from abc import ABC +from typing import Generic, TYPE_CHECKING, TypeVar + +if TYPE_CHECKING: + from .serialization import Deserializer, Serializer + + +TClient = TypeVar("TClient") +TConfig = TypeVar("TConfig") + + +class ClientMixinABC(ABC, Generic[TClient, TConfig]): + """DO NOT use this class. It is for internal typing use only.""" + + _client: TClient + _config: TConfig + _serialize: "Serializer" + _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/unbranded/generated/server-endpoint-not-defined/server/endpoint/notdefined/_vendor.py b/packages/typespec-python/test/unbranded/generated/server-endpoint-not-defined/server/endpoint/notdefined/_vendor.py deleted file mode 100644 index b070c5dfe7b..00000000000 --- a/packages/typespec-python/test/unbranded/generated/server-endpoint-not-defined/server/endpoint/notdefined/_vendor.py +++ /dev/null @@ -1,18 +0,0 @@ -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import NotDefinedClientConfiguration - -if TYPE_CHECKING: - from corehttp.runtime import PipelineClient - - from ._serialization import Deserializer, Serializer - - -class NotDefinedClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "PipelineClient" - _config: NotDefinedClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/unbranded/generated/server-endpoint-not-defined/server/endpoint/notdefined/aio/_client.py b/packages/typespec-python/test/unbranded/generated/server-endpoint-not-defined/server/endpoint/notdefined/aio/_client.py index 556b7686be2..5f0ae452419 100644 --- a/packages/typespec-python/test/unbranded/generated/server-endpoint-not-defined/server/endpoint/notdefined/aio/_client.py +++ b/packages/typespec-python/test/unbranded/generated/server-endpoint-not-defined/server/endpoint/notdefined/aio/_client.py @@ -7,7 +7,7 @@ from corehttp.rest import AsyncHttpResponse, HttpRequest from corehttp.runtime import AsyncPipelineClient, policies -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import NotDefinedClientConfiguration from ._operations import NotDefinedClientOperationsMixin diff --git a/packages/typespec-python/test/unbranded/generated/server-endpoint-not-defined/server/endpoint/notdefined/aio/_operations/_operations.py b/packages/typespec-python/test/unbranded/generated/server-endpoint-not-defined/server/endpoint/notdefined/aio/_operations/_operations.py index c9b6e432a47..f1a782c6ca8 100644 --- a/packages/typespec-python/test/unbranded/generated/server-endpoint-not-defined/server/endpoint/notdefined/aio/_operations/_operations.py +++ b/packages/typespec-python/test/unbranded/generated/server-endpoint-not-defined/server/endpoint/notdefined/aio/_operations/_operations.py @@ -11,16 +11,18 @@ map_error, ) from corehttp.rest import AsyncHttpResponse, HttpRequest +from corehttp.runtime import AsyncPipelineClient from corehttp.runtime.pipeline import PipelineResponse from ..._operations._operations import build_not_defined_valid_request -from .._vendor import NotDefinedClientMixinABC +from ..._utils.utils import ClientMixinABC +from .._configuration import NotDefinedClientConfiguration T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, AsyncHttpResponse], T, Dict[str, Any]], Any]] -class NotDefinedClientOperationsMixin(NotDefinedClientMixinABC): +class NotDefinedClientOperationsMixin(ClientMixinABC[AsyncPipelineClient, NotDefinedClientConfiguration]): async def valid(self, **kwargs: Any) -> bool: """valid. diff --git a/packages/typespec-python/test/unbranded/generated/server-endpoint-not-defined/server/endpoint/notdefined/aio/_vendor.py b/packages/typespec-python/test/unbranded/generated/server-endpoint-not-defined/server/endpoint/notdefined/aio/_vendor.py deleted file mode 100644 index d2907d639eb..00000000000 --- a/packages/typespec-python/test/unbranded/generated/server-endpoint-not-defined/server/endpoint/notdefined/aio/_vendor.py +++ /dev/null @@ -1,18 +0,0 @@ -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import NotDefinedClientConfiguration - -if TYPE_CHECKING: - from corehttp.runtime import AsyncPipelineClient - - from .._serialization import Deserializer, Serializer - - -class NotDefinedClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "AsyncPipelineClient" - _config: NotDefinedClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/unbranded/generated/server-path-multiple/server/path/multiple/_client.py b/packages/typespec-python/test/unbranded/generated/server-path-multiple/server/path/multiple/_client.py index d2cda168b2e..5f38d002037 100644 --- a/packages/typespec-python/test/unbranded/generated/server-path-multiple/server/path/multiple/_client.py +++ b/packages/typespec-python/test/unbranded/generated/server-path-multiple/server/path/multiple/_client.py @@ -9,7 +9,7 @@ from ._configuration import MultipleClientConfiguration from ._operations import MultipleClientOperationsMixin -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer class MultipleClient(MultipleClientOperationsMixin): diff --git a/packages/typespec-python/test/unbranded/generated/server-path-multiple/server/path/multiple/_operations/_operations.py b/packages/typespec-python/test/unbranded/generated/server-path-multiple/server/path/multiple/_operations/_operations.py index a0a32729228..b650215ff33 100644 --- a/packages/typespec-python/test/unbranded/generated/server-path-multiple/server/path/multiple/_operations/_operations.py +++ b/packages/typespec-python/test/unbranded/generated/server-path-multiple/server/path/multiple/_operations/_operations.py @@ -11,10 +11,12 @@ map_error, ) from corehttp.rest import HttpRequest, HttpResponse +from corehttp.runtime import PipelineClient from corehttp.runtime.pipeline import PipelineResponse -from .._serialization import Serializer -from .._vendor import MultipleClientMixinABC +from .._configuration import MultipleClientConfiguration +from .._utils.serialization import Serializer +from .._utils.utils import ClientMixinABC T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] @@ -44,7 +46,7 @@ def build_multiple_with_operation_path_param_request( # pylint: disable=name-to return HttpRequest(method="GET", url=_url, **kwargs) -class MultipleClientOperationsMixin(MultipleClientMixinABC): +class MultipleClientOperationsMixin(ClientMixinABC[PipelineClient, MultipleClientConfiguration]): def no_operation_params(self, **kwargs: Any) -> None: # pylint: disable=inconsistent-return-statements """no_operation_params. diff --git a/packages/typespec-python/test/unbranded/generated/server-path-multiple/server/path/multiple/_utils/__init__.py b/packages/typespec-python/test/unbranded/generated/server-path-multiple/server/path/multiple/_utils/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/packages/typespec-python/test/unbranded/generated/server-path-multiple/server/path/multiple/_model_base.py b/packages/typespec-python/test/unbranded/generated/server-path-multiple/server/path/multiple/_utils/model_base.py similarity index 100% rename from packages/typespec-python/test/unbranded/generated/server-path-multiple/server/path/multiple/_model_base.py rename to packages/typespec-python/test/unbranded/generated/server-path-multiple/server/path/multiple/_utils/model_base.py diff --git a/packages/typespec-python/test/unbranded/generated/server-path-multiple/server/path/multiple/_serialization.py b/packages/typespec-python/test/unbranded/generated/server-path-multiple/server/path/multiple/_utils/serialization.py similarity index 100% rename from packages/typespec-python/test/unbranded/generated/server-path-multiple/server/path/multiple/_serialization.py rename to packages/typespec-python/test/unbranded/generated/server-path-multiple/server/path/multiple/_utils/serialization.py diff --git a/packages/typespec-python/test/unbranded/generated/server-path-multiple/server/path/multiple/_utils/utils.py b/packages/typespec-python/test/unbranded/generated/server-path-multiple/server/path/multiple/_utils/utils.py new file mode 100644 index 00000000000..02aa2f816ea --- /dev/null +++ b/packages/typespec-python/test/unbranded/generated/server-path-multiple/server/path/multiple/_utils/utils.py @@ -0,0 +1,18 @@ +from abc import ABC +from typing import Generic, TYPE_CHECKING, TypeVar + +if TYPE_CHECKING: + from .serialization import Deserializer, Serializer + + +TClient = TypeVar("TClient") +TConfig = TypeVar("TConfig") + + +class ClientMixinABC(ABC, Generic[TClient, TConfig]): + """DO NOT use this class. It is for internal typing use only.""" + + _client: TClient + _config: TConfig + _serialize: "Serializer" + _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/unbranded/generated/server-path-multiple/server/path/multiple/_vendor.py b/packages/typespec-python/test/unbranded/generated/server-path-multiple/server/path/multiple/_vendor.py deleted file mode 100644 index 56ca034e497..00000000000 --- a/packages/typespec-python/test/unbranded/generated/server-path-multiple/server/path/multiple/_vendor.py +++ /dev/null @@ -1,18 +0,0 @@ -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import MultipleClientConfiguration - -if TYPE_CHECKING: - from corehttp.runtime import PipelineClient - - from ._serialization import Deserializer, Serializer - - -class MultipleClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "PipelineClient" - _config: MultipleClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/unbranded/generated/server-path-multiple/server/path/multiple/aio/_client.py b/packages/typespec-python/test/unbranded/generated/server-path-multiple/server/path/multiple/aio/_client.py index 6fe20d4ba6e..8f798274a0b 100644 --- a/packages/typespec-python/test/unbranded/generated/server-path-multiple/server/path/multiple/aio/_client.py +++ b/packages/typespec-python/test/unbranded/generated/server-path-multiple/server/path/multiple/aio/_client.py @@ -7,7 +7,7 @@ from corehttp.rest import AsyncHttpResponse, HttpRequest from corehttp.runtime import AsyncPipelineClient, policies -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import MultipleClientConfiguration from ._operations import MultipleClientOperationsMixin diff --git a/packages/typespec-python/test/unbranded/generated/server-path-multiple/server/path/multiple/aio/_operations/_operations.py b/packages/typespec-python/test/unbranded/generated/server-path-multiple/server/path/multiple/aio/_operations/_operations.py index 532446e4f32..5e1eba550e5 100644 --- a/packages/typespec-python/test/unbranded/generated/server-path-multiple/server/path/multiple/aio/_operations/_operations.py +++ b/packages/typespec-python/test/unbranded/generated/server-path-multiple/server/path/multiple/aio/_operations/_operations.py @@ -11,19 +11,21 @@ map_error, ) from corehttp.rest import AsyncHttpResponse, HttpRequest +from corehttp.runtime import AsyncPipelineClient from corehttp.runtime.pipeline import PipelineResponse from ..._operations._operations import ( build_multiple_no_operation_params_request, build_multiple_with_operation_path_param_request, ) -from .._vendor import MultipleClientMixinABC +from ..._utils.utils import ClientMixinABC +from .._configuration import MultipleClientConfiguration T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, AsyncHttpResponse], T, Dict[str, Any]], Any]] -class MultipleClientOperationsMixin(MultipleClientMixinABC): +class MultipleClientOperationsMixin(ClientMixinABC[AsyncPipelineClient, MultipleClientConfiguration]): async def no_operation_params(self, **kwargs: Any) -> None: """no_operation_params. diff --git a/packages/typespec-python/test/unbranded/generated/server-path-multiple/server/path/multiple/aio/_vendor.py b/packages/typespec-python/test/unbranded/generated/server-path-multiple/server/path/multiple/aio/_vendor.py deleted file mode 100644 index 2142fb11fb3..00000000000 --- a/packages/typespec-python/test/unbranded/generated/server-path-multiple/server/path/multiple/aio/_vendor.py +++ /dev/null @@ -1,18 +0,0 @@ -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import MultipleClientConfiguration - -if TYPE_CHECKING: - from corehttp.runtime import AsyncPipelineClient - - from .._serialization import Deserializer, Serializer - - -class MultipleClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "AsyncPipelineClient" - _config: MultipleClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/unbranded/generated/server-path-single/server/path/single/_client.py b/packages/typespec-python/test/unbranded/generated/server-path-single/server/path/single/_client.py index ff90a25d7e9..ebbf861b448 100644 --- a/packages/typespec-python/test/unbranded/generated/server-path-single/server/path/single/_client.py +++ b/packages/typespec-python/test/unbranded/generated/server-path-single/server/path/single/_client.py @@ -9,7 +9,7 @@ from ._configuration import SingleClientConfiguration from ._operations import SingleClientOperationsMixin -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer class SingleClient(SingleClientOperationsMixin): # pylint: disable=client-accepts-api-version-keyword diff --git a/packages/typespec-python/test/unbranded/generated/server-path-single/server/path/single/_operations/_operations.py b/packages/typespec-python/test/unbranded/generated/server-path-single/server/path/single/_operations/_operations.py index 5319488e757..a464fe0bd72 100644 --- a/packages/typespec-python/test/unbranded/generated/server-path-single/server/path/single/_operations/_operations.py +++ b/packages/typespec-python/test/unbranded/generated/server-path-single/server/path/single/_operations/_operations.py @@ -11,10 +11,12 @@ map_error, ) from corehttp.rest import HttpRequest, HttpResponse +from corehttp.runtime import PipelineClient from corehttp.runtime.pipeline import PipelineResponse -from .._serialization import Serializer -from .._vendor import SingleClientMixinABC +from .._configuration import SingleClientConfiguration +from .._utils.serialization import Serializer +from .._utils.utils import ClientMixinABC T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] @@ -30,7 +32,7 @@ def build_single_my_op_request(**kwargs: Any) -> HttpRequest: return HttpRequest(method="HEAD", url=_url, **kwargs) -class SingleClientOperationsMixin(SingleClientMixinABC): +class SingleClientOperationsMixin(ClientMixinABC[PipelineClient, SingleClientConfiguration]): def my_op(self, **kwargs: Any) -> bool: """my_op. diff --git a/packages/typespec-python/test/unbranded/generated/server-path-single/server/path/single/_utils/__init__.py b/packages/typespec-python/test/unbranded/generated/server-path-single/server/path/single/_utils/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/packages/typespec-python/test/unbranded/generated/server-path-single/server/path/single/_model_base.py b/packages/typespec-python/test/unbranded/generated/server-path-single/server/path/single/_utils/model_base.py similarity index 100% rename from packages/typespec-python/test/unbranded/generated/server-path-single/server/path/single/_model_base.py rename to packages/typespec-python/test/unbranded/generated/server-path-single/server/path/single/_utils/model_base.py diff --git a/packages/typespec-python/test/unbranded/generated/server-path-single/server/path/single/_serialization.py b/packages/typespec-python/test/unbranded/generated/server-path-single/server/path/single/_utils/serialization.py similarity index 100% rename from packages/typespec-python/test/unbranded/generated/server-path-single/server/path/single/_serialization.py rename to packages/typespec-python/test/unbranded/generated/server-path-single/server/path/single/_utils/serialization.py diff --git a/packages/typespec-python/test/unbranded/generated/server-path-single/server/path/single/_utils/utils.py b/packages/typespec-python/test/unbranded/generated/server-path-single/server/path/single/_utils/utils.py new file mode 100644 index 00000000000..02aa2f816ea --- /dev/null +++ b/packages/typespec-python/test/unbranded/generated/server-path-single/server/path/single/_utils/utils.py @@ -0,0 +1,18 @@ +from abc import ABC +from typing import Generic, TYPE_CHECKING, TypeVar + +if TYPE_CHECKING: + from .serialization import Deserializer, Serializer + + +TClient = TypeVar("TClient") +TConfig = TypeVar("TConfig") + + +class ClientMixinABC(ABC, Generic[TClient, TConfig]): + """DO NOT use this class. It is for internal typing use only.""" + + _client: TClient + _config: TConfig + _serialize: "Serializer" + _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/unbranded/generated/server-path-single/server/path/single/_vendor.py b/packages/typespec-python/test/unbranded/generated/server-path-single/server/path/single/_vendor.py deleted file mode 100644 index 58a1d53f3f9..00000000000 --- a/packages/typespec-python/test/unbranded/generated/server-path-single/server/path/single/_vendor.py +++ /dev/null @@ -1,18 +0,0 @@ -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import SingleClientConfiguration - -if TYPE_CHECKING: - from corehttp.runtime import PipelineClient - - from ._serialization import Deserializer, Serializer - - -class SingleClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "PipelineClient" - _config: SingleClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/unbranded/generated/server-path-single/server/path/single/aio/_client.py b/packages/typespec-python/test/unbranded/generated/server-path-single/server/path/single/aio/_client.py index e71f9e92eca..fcb85d526c8 100644 --- a/packages/typespec-python/test/unbranded/generated/server-path-single/server/path/single/aio/_client.py +++ b/packages/typespec-python/test/unbranded/generated/server-path-single/server/path/single/aio/_client.py @@ -7,7 +7,7 @@ from corehttp.rest import AsyncHttpResponse, HttpRequest from corehttp.runtime import AsyncPipelineClient, policies -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import SingleClientConfiguration from ._operations import SingleClientOperationsMixin diff --git a/packages/typespec-python/test/unbranded/generated/server-path-single/server/path/single/aio/_operations/_operations.py b/packages/typespec-python/test/unbranded/generated/server-path-single/server/path/single/aio/_operations/_operations.py index 75e43329203..f6b8add81bf 100644 --- a/packages/typespec-python/test/unbranded/generated/server-path-single/server/path/single/aio/_operations/_operations.py +++ b/packages/typespec-python/test/unbranded/generated/server-path-single/server/path/single/aio/_operations/_operations.py @@ -11,16 +11,18 @@ map_error, ) from corehttp.rest import AsyncHttpResponse, HttpRequest +from corehttp.runtime import AsyncPipelineClient from corehttp.runtime.pipeline import PipelineResponse from ..._operations._operations import build_single_my_op_request -from .._vendor import SingleClientMixinABC +from ..._utils.utils import ClientMixinABC +from .._configuration import SingleClientConfiguration T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, AsyncHttpResponse], T, Dict[str, Any]], Any]] -class SingleClientOperationsMixin(SingleClientMixinABC): +class SingleClientOperationsMixin(ClientMixinABC[AsyncPipelineClient, SingleClientConfiguration]): async def my_op(self, **kwargs: Any) -> bool: """my_op. diff --git a/packages/typespec-python/test/unbranded/generated/server-path-single/server/path/single/aio/_vendor.py b/packages/typespec-python/test/unbranded/generated/server-path-single/server/path/single/aio/_vendor.py deleted file mode 100644 index 6d8d191898c..00000000000 --- a/packages/typespec-python/test/unbranded/generated/server-path-single/server/path/single/aio/_vendor.py +++ /dev/null @@ -1,18 +0,0 @@ -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import SingleClientConfiguration - -if TYPE_CHECKING: - from corehttp.runtime import AsyncPipelineClient - - from .._serialization import Deserializer, Serializer - - -class SingleClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "AsyncPipelineClient" - _config: SingleClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/unbranded/generated/server-versions-not-versioned/server/versions/notversioned/_client.py b/packages/typespec-python/test/unbranded/generated/server-versions-not-versioned/server/versions/notversioned/_client.py index c111680086f..70adb872b5b 100644 --- a/packages/typespec-python/test/unbranded/generated/server-versions-not-versioned/server/versions/notversioned/_client.py +++ b/packages/typespec-python/test/unbranded/generated/server-versions-not-versioned/server/versions/notversioned/_client.py @@ -9,7 +9,7 @@ from ._configuration import NotVersionedClientConfiguration from ._operations import NotVersionedClientOperationsMixin -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer class NotVersionedClient(NotVersionedClientOperationsMixin): # pylint: disable=client-accepts-api-version-keyword diff --git a/packages/typespec-python/test/unbranded/generated/server-versions-not-versioned/server/versions/notversioned/_operations/_operations.py b/packages/typespec-python/test/unbranded/generated/server-versions-not-versioned/server/versions/notversioned/_operations/_operations.py index 35c2cbaabac..8a2dd9d488f 100644 --- a/packages/typespec-python/test/unbranded/generated/server-versions-not-versioned/server/versions/notversioned/_operations/_operations.py +++ b/packages/typespec-python/test/unbranded/generated/server-versions-not-versioned/server/versions/notversioned/_operations/_operations.py @@ -11,11 +11,13 @@ map_error, ) from corehttp.rest import HttpRequest, HttpResponse +from corehttp.runtime import PipelineClient from corehttp.runtime.pipeline import PipelineResponse from corehttp.utils import case_insensitive_dict -from .._serialization import Serializer -from .._vendor import NotVersionedClientMixinABC +from .._configuration import NotVersionedClientConfiguration +from .._utils.serialization import Serializer +from .._utils.utils import ClientMixinABC T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] @@ -59,7 +61,7 @@ def build_not_versioned_with_path_api_version_request( # pylint: disable=name-t return HttpRequest(method="HEAD", url=_url, **kwargs) -class NotVersionedClientOperationsMixin(NotVersionedClientMixinABC): +class NotVersionedClientOperationsMixin(ClientMixinABC[PipelineClient, NotVersionedClientConfiguration]): def without_api_version(self, **kwargs: Any) -> bool: """without_api_version. diff --git a/packages/typespec-python/test/unbranded/generated/server-versions-not-versioned/server/versions/notversioned/_utils/__init__.py b/packages/typespec-python/test/unbranded/generated/server-versions-not-versioned/server/versions/notversioned/_utils/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/packages/typespec-python/test/unbranded/generated/server-versions-not-versioned/server/versions/notversioned/_model_base.py b/packages/typespec-python/test/unbranded/generated/server-versions-not-versioned/server/versions/notversioned/_utils/model_base.py similarity index 100% rename from packages/typespec-python/test/unbranded/generated/server-versions-not-versioned/server/versions/notversioned/_model_base.py rename to packages/typespec-python/test/unbranded/generated/server-versions-not-versioned/server/versions/notversioned/_utils/model_base.py diff --git a/packages/typespec-python/test/unbranded/generated/server-versions-not-versioned/server/versions/notversioned/_serialization.py b/packages/typespec-python/test/unbranded/generated/server-versions-not-versioned/server/versions/notversioned/_utils/serialization.py similarity index 100% rename from packages/typespec-python/test/unbranded/generated/server-versions-not-versioned/server/versions/notversioned/_serialization.py rename to packages/typespec-python/test/unbranded/generated/server-versions-not-versioned/server/versions/notversioned/_utils/serialization.py diff --git a/packages/typespec-python/test/unbranded/generated/server-versions-not-versioned/server/versions/notversioned/_utils/utils.py b/packages/typespec-python/test/unbranded/generated/server-versions-not-versioned/server/versions/notversioned/_utils/utils.py new file mode 100644 index 00000000000..02aa2f816ea --- /dev/null +++ b/packages/typespec-python/test/unbranded/generated/server-versions-not-versioned/server/versions/notversioned/_utils/utils.py @@ -0,0 +1,18 @@ +from abc import ABC +from typing import Generic, TYPE_CHECKING, TypeVar + +if TYPE_CHECKING: + from .serialization import Deserializer, Serializer + + +TClient = TypeVar("TClient") +TConfig = TypeVar("TConfig") + + +class ClientMixinABC(ABC, Generic[TClient, TConfig]): + """DO NOT use this class. It is for internal typing use only.""" + + _client: TClient + _config: TConfig + _serialize: "Serializer" + _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/unbranded/generated/server-versions-not-versioned/server/versions/notversioned/_vendor.py b/packages/typespec-python/test/unbranded/generated/server-versions-not-versioned/server/versions/notversioned/_vendor.py deleted file mode 100644 index d68d1ff790c..00000000000 --- a/packages/typespec-python/test/unbranded/generated/server-versions-not-versioned/server/versions/notversioned/_vendor.py +++ /dev/null @@ -1,18 +0,0 @@ -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import NotVersionedClientConfiguration - -if TYPE_CHECKING: - from corehttp.runtime import PipelineClient - - from ._serialization import Deserializer, Serializer - - -class NotVersionedClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "PipelineClient" - _config: NotVersionedClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/unbranded/generated/server-versions-not-versioned/server/versions/notversioned/aio/_client.py b/packages/typespec-python/test/unbranded/generated/server-versions-not-versioned/server/versions/notversioned/aio/_client.py index 1a0c4956327..9ad89bb4c52 100644 --- a/packages/typespec-python/test/unbranded/generated/server-versions-not-versioned/server/versions/notversioned/aio/_client.py +++ b/packages/typespec-python/test/unbranded/generated/server-versions-not-versioned/server/versions/notversioned/aio/_client.py @@ -7,7 +7,7 @@ from corehttp.rest import AsyncHttpResponse, HttpRequest from corehttp.runtime import AsyncPipelineClient, policies -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import NotVersionedClientConfiguration from ._operations import NotVersionedClientOperationsMixin diff --git a/packages/typespec-python/test/unbranded/generated/server-versions-not-versioned/server/versions/notversioned/aio/_operations/_operations.py b/packages/typespec-python/test/unbranded/generated/server-versions-not-versioned/server/versions/notversioned/aio/_operations/_operations.py index 5456524f007..44c1b026afa 100644 --- a/packages/typespec-python/test/unbranded/generated/server-versions-not-versioned/server/versions/notversioned/aio/_operations/_operations.py +++ b/packages/typespec-python/test/unbranded/generated/server-versions-not-versioned/server/versions/notversioned/aio/_operations/_operations.py @@ -11,6 +11,7 @@ map_error, ) from corehttp.rest import AsyncHttpResponse, HttpRequest +from corehttp.runtime import AsyncPipelineClient from corehttp.runtime.pipeline import PipelineResponse from ..._operations._operations import ( @@ -18,13 +19,14 @@ build_not_versioned_with_query_api_version_request, build_not_versioned_without_api_version_request, ) -from .._vendor import NotVersionedClientMixinABC +from ..._utils.utils import ClientMixinABC +from .._configuration import NotVersionedClientConfiguration T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, AsyncHttpResponse], T, Dict[str, Any]], Any]] -class NotVersionedClientOperationsMixin(NotVersionedClientMixinABC): +class NotVersionedClientOperationsMixin(ClientMixinABC[AsyncPipelineClient, NotVersionedClientConfiguration]): async def without_api_version(self, **kwargs: Any) -> bool: """without_api_version. diff --git a/packages/typespec-python/test/unbranded/generated/server-versions-not-versioned/server/versions/notversioned/aio/_vendor.py b/packages/typespec-python/test/unbranded/generated/server-versions-not-versioned/server/versions/notversioned/aio/_vendor.py deleted file mode 100644 index d884e12af13..00000000000 --- a/packages/typespec-python/test/unbranded/generated/server-versions-not-versioned/server/versions/notversioned/aio/_vendor.py +++ /dev/null @@ -1,18 +0,0 @@ -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import NotVersionedClientConfiguration - -if TYPE_CHECKING: - from corehttp.runtime import AsyncPipelineClient - - from .._serialization import Deserializer, Serializer - - -class NotVersionedClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "AsyncPipelineClient" - _config: NotVersionedClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/unbranded/generated/server-versions-versioned/server/versions/versioned/_client.py b/packages/typespec-python/test/unbranded/generated/server-versions-versioned/server/versions/versioned/_client.py index dbcfc40b63e..bab9e4459df 100644 --- a/packages/typespec-python/test/unbranded/generated/server-versions-versioned/server/versions/versioned/_client.py +++ b/packages/typespec-python/test/unbranded/generated/server-versions-versioned/server/versions/versioned/_client.py @@ -9,7 +9,7 @@ from ._configuration import VersionedClientConfiguration from ._operations import VersionedClientOperationsMixin -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer class VersionedClient(VersionedClientOperationsMixin): diff --git a/packages/typespec-python/test/unbranded/generated/server-versions-versioned/server/versions/versioned/_operations/_operations.py b/packages/typespec-python/test/unbranded/generated/server-versions-versioned/server/versions/versioned/_operations/_operations.py index 379539fe031..bfee5bed03a 100644 --- a/packages/typespec-python/test/unbranded/generated/server-versions-versioned/server/versions/versioned/_operations/_operations.py +++ b/packages/typespec-python/test/unbranded/generated/server-versions-versioned/server/versions/versioned/_operations/_operations.py @@ -11,11 +11,13 @@ map_error, ) from corehttp.rest import HttpRequest, HttpResponse +from corehttp.runtime import PipelineClient from corehttp.runtime.pipeline import PipelineResponse from corehttp.utils import case_insensitive_dict -from .._serialization import Serializer -from .._vendor import VersionedClientMixinABC +from .._configuration import VersionedClientConfiguration +from .._utils.serialization import Serializer +from .._utils.utils import ClientMixinABC T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] @@ -70,7 +72,7 @@ def build_versioned_with_query_old_api_version_request(**kwargs: Any) -> HttpReq return HttpRequest(method="HEAD", url=_url, params=_params, **kwargs) -class VersionedClientOperationsMixin(VersionedClientMixinABC): +class VersionedClientOperationsMixin(ClientMixinABC[PipelineClient, VersionedClientConfiguration]): def without_api_version(self, **kwargs: Any) -> bool: """without_api_version. diff --git a/packages/typespec-python/test/unbranded/generated/server-versions-versioned/server/versions/versioned/_utils/__init__.py b/packages/typespec-python/test/unbranded/generated/server-versions-versioned/server/versions/versioned/_utils/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/packages/typespec-python/test/unbranded/generated/server-versions-versioned/server/versions/versioned/_model_base.py b/packages/typespec-python/test/unbranded/generated/server-versions-versioned/server/versions/versioned/_utils/model_base.py similarity index 100% rename from packages/typespec-python/test/unbranded/generated/server-versions-versioned/server/versions/versioned/_model_base.py rename to packages/typespec-python/test/unbranded/generated/server-versions-versioned/server/versions/versioned/_utils/model_base.py diff --git a/packages/typespec-python/test/unbranded/generated/server-versions-versioned/server/versions/versioned/_serialization.py b/packages/typespec-python/test/unbranded/generated/server-versions-versioned/server/versions/versioned/_utils/serialization.py similarity index 100% rename from packages/typespec-python/test/unbranded/generated/server-versions-versioned/server/versions/versioned/_serialization.py rename to packages/typespec-python/test/unbranded/generated/server-versions-versioned/server/versions/versioned/_utils/serialization.py diff --git a/packages/typespec-python/test/unbranded/generated/server-versions-versioned/server/versions/versioned/_utils/utils.py b/packages/typespec-python/test/unbranded/generated/server-versions-versioned/server/versions/versioned/_utils/utils.py new file mode 100644 index 00000000000..02aa2f816ea --- /dev/null +++ b/packages/typespec-python/test/unbranded/generated/server-versions-versioned/server/versions/versioned/_utils/utils.py @@ -0,0 +1,18 @@ +from abc import ABC +from typing import Generic, TYPE_CHECKING, TypeVar + +if TYPE_CHECKING: + from .serialization import Deserializer, Serializer + + +TClient = TypeVar("TClient") +TConfig = TypeVar("TConfig") + + +class ClientMixinABC(ABC, Generic[TClient, TConfig]): + """DO NOT use this class. It is for internal typing use only.""" + + _client: TClient + _config: TConfig + _serialize: "Serializer" + _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/unbranded/generated/server-versions-versioned/server/versions/versioned/_vendor.py b/packages/typespec-python/test/unbranded/generated/server-versions-versioned/server/versions/versioned/_vendor.py deleted file mode 100644 index 4d339d5580b..00000000000 --- a/packages/typespec-python/test/unbranded/generated/server-versions-versioned/server/versions/versioned/_vendor.py +++ /dev/null @@ -1,18 +0,0 @@ -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import VersionedClientConfiguration - -if TYPE_CHECKING: - from corehttp.runtime import PipelineClient - - from ._serialization import Deserializer, Serializer - - -class VersionedClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "PipelineClient" - _config: VersionedClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/unbranded/generated/server-versions-versioned/server/versions/versioned/aio/_client.py b/packages/typespec-python/test/unbranded/generated/server-versions-versioned/server/versions/versioned/aio/_client.py index 8c96ec9fc06..313afe379df 100644 --- a/packages/typespec-python/test/unbranded/generated/server-versions-versioned/server/versions/versioned/aio/_client.py +++ b/packages/typespec-python/test/unbranded/generated/server-versions-versioned/server/versions/versioned/aio/_client.py @@ -7,7 +7,7 @@ from corehttp.rest import AsyncHttpResponse, HttpRequest from corehttp.runtime import AsyncPipelineClient, policies -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import VersionedClientConfiguration from ._operations import VersionedClientOperationsMixin diff --git a/packages/typespec-python/test/unbranded/generated/server-versions-versioned/server/versions/versioned/aio/_operations/_operations.py b/packages/typespec-python/test/unbranded/generated/server-versions-versioned/server/versions/versioned/aio/_operations/_operations.py index d466516a102..0dd7aad29f5 100644 --- a/packages/typespec-python/test/unbranded/generated/server-versions-versioned/server/versions/versioned/aio/_operations/_operations.py +++ b/packages/typespec-python/test/unbranded/generated/server-versions-versioned/server/versions/versioned/aio/_operations/_operations.py @@ -11,6 +11,7 @@ map_error, ) from corehttp.rest import AsyncHttpResponse, HttpRequest +from corehttp.runtime import AsyncPipelineClient from corehttp.runtime.pipeline import PipelineResponse from ..._operations._operations import ( @@ -19,13 +20,14 @@ build_versioned_with_query_old_api_version_request, build_versioned_without_api_version_request, ) -from .._vendor import VersionedClientMixinABC +from ..._utils.utils import ClientMixinABC +from .._configuration import VersionedClientConfiguration T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, AsyncHttpResponse], T, Dict[str, Any]], Any]] -class VersionedClientOperationsMixin(VersionedClientMixinABC): +class VersionedClientOperationsMixin(ClientMixinABC[AsyncPipelineClient, VersionedClientConfiguration]): async def without_api_version(self, **kwargs: Any) -> bool: """without_api_version. diff --git a/packages/typespec-python/test/unbranded/generated/server-versions-versioned/server/versions/versioned/aio/_vendor.py b/packages/typespec-python/test/unbranded/generated/server-versions-versioned/server/versions/versioned/aio/_vendor.py deleted file mode 100644 index ca534da6cbf..00000000000 --- a/packages/typespec-python/test/unbranded/generated/server-versions-versioned/server/versions/versioned/aio/_vendor.py +++ /dev/null @@ -1,18 +0,0 @@ -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import VersionedClientConfiguration - -if TYPE_CHECKING: - from corehttp.runtime import AsyncPipelineClient - - from .._serialization import Deserializer, Serializer - - -class VersionedClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "AsyncPipelineClient" - _config: VersionedClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/unbranded/generated/special-headers-conditional-request/specialheaders/conditionalrequest/_client.py b/packages/typespec-python/test/unbranded/generated/special-headers-conditional-request/specialheaders/conditionalrequest/_client.py index 4119077cd2f..212a11bd11d 100644 --- a/packages/typespec-python/test/unbranded/generated/special-headers-conditional-request/specialheaders/conditionalrequest/_client.py +++ b/packages/typespec-python/test/unbranded/generated/special-headers-conditional-request/specialheaders/conditionalrequest/_client.py @@ -9,7 +9,7 @@ from ._configuration import ConditionalRequestClientConfiguration from ._operations import ConditionalRequestClientOperationsMixin -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer class ConditionalRequestClient( diff --git a/packages/typespec-python/test/unbranded/generated/special-headers-conditional-request/specialheaders/conditionalrequest/_operations/_operations.py b/packages/typespec-python/test/unbranded/generated/special-headers-conditional-request/specialheaders/conditionalrequest/_operations/_operations.py index ad6fe4245e1..134c9f6cdd9 100644 --- a/packages/typespec-python/test/unbranded/generated/special-headers-conditional-request/specialheaders/conditionalrequest/_operations/_operations.py +++ b/packages/typespec-python/test/unbranded/generated/special-headers-conditional-request/specialheaders/conditionalrequest/_operations/_operations.py @@ -14,11 +14,13 @@ map_error, ) from corehttp.rest import HttpRequest, HttpResponse +from corehttp.runtime import PipelineClient from corehttp.runtime.pipeline import PipelineResponse from corehttp.utils import case_insensitive_dict -from .._serialization import Serializer -from .._vendor import ConditionalRequestClientMixinABC, prep_if_match, prep_if_none_match +from .._configuration import ConditionalRequestClientConfiguration +from .._utils.serialization import Serializer +from .._utils.utils import ClientMixinABC, prep_if_match, prep_if_none_match T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] @@ -95,7 +97,7 @@ def build_conditional_request_post_if_unmodified_since_request( # pylint: disab return HttpRequest(method="POST", url=_url, headers=_headers, **kwargs) -class ConditionalRequestClientOperationsMixin(ConditionalRequestClientMixinABC): +class ConditionalRequestClientOperationsMixin(ClientMixinABC[PipelineClient, ConditionalRequestClientConfiguration]): def post_if_match( # pylint: disable=inconsistent-return-statements self, *, etag: Optional[str] = None, match_condition: Optional[MatchConditions] = None, **kwargs: Any diff --git a/packages/typespec-python/test/unbranded/generated/special-headers-conditional-request/specialheaders/conditionalrequest/_utils/__init__.py b/packages/typespec-python/test/unbranded/generated/special-headers-conditional-request/specialheaders/conditionalrequest/_utils/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/packages/typespec-python/test/unbranded/generated/special-headers-conditional-request/specialheaders/conditionalrequest/_model_base.py b/packages/typespec-python/test/unbranded/generated/special-headers-conditional-request/specialheaders/conditionalrequest/_utils/model_base.py similarity index 100% rename from packages/typespec-python/test/unbranded/generated/special-headers-conditional-request/specialheaders/conditionalrequest/_model_base.py rename to packages/typespec-python/test/unbranded/generated/special-headers-conditional-request/specialheaders/conditionalrequest/_utils/model_base.py diff --git a/packages/typespec-python/test/unbranded/generated/special-headers-conditional-request/specialheaders/conditionalrequest/_serialization.py b/packages/typespec-python/test/unbranded/generated/special-headers-conditional-request/specialheaders/conditionalrequest/_utils/serialization.py similarity index 100% rename from packages/typespec-python/test/unbranded/generated/special-headers-conditional-request/specialheaders/conditionalrequest/_serialization.py rename to packages/typespec-python/test/unbranded/generated/special-headers-conditional-request/specialheaders/conditionalrequest/_utils/serialization.py diff --git a/packages/typespec-python/test/unbranded/generated/special-headers-conditional-request/specialheaders/conditionalrequest/_utils/utils.py b/packages/typespec-python/test/unbranded/generated/special-headers-conditional-request/specialheaders/conditionalrequest/_utils/utils.py new file mode 100644 index 00000000000..e112131fc7d --- /dev/null +++ b/packages/typespec-python/test/unbranded/generated/special-headers-conditional-request/specialheaders/conditionalrequest/_utils/utils.py @@ -0,0 +1,50 @@ +from abc import ABC +from typing import Generic, Optional, TYPE_CHECKING, TypeVar + +from corehttp import MatchConditions + +if TYPE_CHECKING: + from .serialization import Deserializer, Serializer + + +TClient = TypeVar("TClient") +TConfig = TypeVar("TConfig") + + +class ClientMixinABC(ABC, Generic[TClient, TConfig]): + """DO NOT use this class. It is for internal typing use only.""" + + _client: TClient + _config: TConfig + _serialize: "Serializer" + _deserialize: "Deserializer" + + +def quote_etag(etag: Optional[str]) -> Optional[str]: + if not etag or etag == "*": + return etag + if etag.startswith("W/"): + return etag + if etag.startswith('"') and etag.endswith('"'): + return etag + if etag.startswith("'") and etag.endswith("'"): + return etag + return '"' + etag + '"' + + +def prep_if_match(etag: Optional[str], match_condition: Optional[MatchConditions]) -> Optional[str]: + if match_condition == MatchConditions.IfNotModified: + if_match = quote_etag(etag) if etag else None + return if_match + if match_condition == MatchConditions.IfPresent: + return "*" + return None + + +def prep_if_none_match(etag: Optional[str], match_condition: Optional[MatchConditions]) -> Optional[str]: + if match_condition == MatchConditions.IfModified: + if_none_match = quote_etag(etag) if etag else None + return if_none_match + if match_condition == MatchConditions.IfMissing: + return "*" + return None diff --git a/packages/typespec-python/test/unbranded/generated/special-headers-conditional-request/specialheaders/conditionalrequest/_vendor.py b/packages/typespec-python/test/unbranded/generated/special-headers-conditional-request/specialheaders/conditionalrequest/_vendor.py deleted file mode 100644 index 86a29e9a638..00000000000 --- a/packages/typespec-python/test/unbranded/generated/special-headers-conditional-request/specialheaders/conditionalrequest/_vendor.py +++ /dev/null @@ -1,50 +0,0 @@ -from abc import ABC -from typing import Optional, TYPE_CHECKING - -from corehttp import MatchConditions - -from ._configuration import ConditionalRequestClientConfiguration - -if TYPE_CHECKING: - from corehttp.runtime import PipelineClient - - from ._serialization import Deserializer, Serializer - - -class ConditionalRequestClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "PipelineClient" - _config: ConditionalRequestClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" - - -def quote_etag(etag: Optional[str]) -> Optional[str]: - if not etag or etag == "*": - return etag - if etag.startswith("W/"): - return etag - if etag.startswith('"') and etag.endswith('"'): - return etag - if etag.startswith("'") and etag.endswith("'"): - return etag - return '"' + etag + '"' - - -def prep_if_match(etag: Optional[str], match_condition: Optional[MatchConditions]) -> Optional[str]: - if match_condition == MatchConditions.IfNotModified: - if_match = quote_etag(etag) if etag else None - return if_match - if match_condition == MatchConditions.IfPresent: - return "*" - return None - - -def prep_if_none_match(etag: Optional[str], match_condition: Optional[MatchConditions]) -> Optional[str]: - if match_condition == MatchConditions.IfModified: - if_none_match = quote_etag(etag) if etag else None - return if_none_match - if match_condition == MatchConditions.IfMissing: - return "*" - return None diff --git a/packages/typespec-python/test/unbranded/generated/special-headers-conditional-request/specialheaders/conditionalrequest/aio/_client.py b/packages/typespec-python/test/unbranded/generated/special-headers-conditional-request/specialheaders/conditionalrequest/aio/_client.py index a8add88828c..3811114ee18 100644 --- a/packages/typespec-python/test/unbranded/generated/special-headers-conditional-request/specialheaders/conditionalrequest/aio/_client.py +++ b/packages/typespec-python/test/unbranded/generated/special-headers-conditional-request/specialheaders/conditionalrequest/aio/_client.py @@ -7,7 +7,7 @@ from corehttp.rest import AsyncHttpResponse, HttpRequest from corehttp.runtime import AsyncPipelineClient, policies -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import ConditionalRequestClientConfiguration from ._operations import ConditionalRequestClientOperationsMixin diff --git a/packages/typespec-python/test/unbranded/generated/special-headers-conditional-request/specialheaders/conditionalrequest/aio/_operations/_operations.py b/packages/typespec-python/test/unbranded/generated/special-headers-conditional-request/specialheaders/conditionalrequest/aio/_operations/_operations.py index 4fb5ac1e299..c83466c699e 100644 --- a/packages/typespec-python/test/unbranded/generated/special-headers-conditional-request/specialheaders/conditionalrequest/aio/_operations/_operations.py +++ b/packages/typespec-python/test/unbranded/generated/special-headers-conditional-request/specialheaders/conditionalrequest/aio/_operations/_operations.py @@ -14,6 +14,7 @@ map_error, ) from corehttp.rest import AsyncHttpResponse, HttpRequest +from corehttp.runtime import AsyncPipelineClient from corehttp.runtime.pipeline import PipelineResponse from ..._operations._operations import ( @@ -22,13 +23,16 @@ build_conditional_request_post_if_none_match_request, build_conditional_request_post_if_unmodified_since_request, ) -from .._vendor import ConditionalRequestClientMixinABC +from ..._utils.utils import ClientMixinABC +from .._configuration import ConditionalRequestClientConfiguration T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, AsyncHttpResponse], T, Dict[str, Any]], Any]] -class ConditionalRequestClientOperationsMixin(ConditionalRequestClientMixinABC): +class ConditionalRequestClientOperationsMixin( + ClientMixinABC[AsyncPipelineClient, ConditionalRequestClientConfiguration] +): async def post_if_match( self, *, etag: Optional[str] = None, match_condition: Optional[MatchConditions] = None, **kwargs: Any diff --git a/packages/typespec-python/test/unbranded/generated/special-headers-conditional-request/specialheaders/conditionalrequest/aio/_vendor.py b/packages/typespec-python/test/unbranded/generated/special-headers-conditional-request/specialheaders/conditionalrequest/aio/_vendor.py deleted file mode 100644 index a711185f6ab..00000000000 --- a/packages/typespec-python/test/unbranded/generated/special-headers-conditional-request/specialheaders/conditionalrequest/aio/_vendor.py +++ /dev/null @@ -1,50 +0,0 @@ -from abc import ABC -from typing import Optional, TYPE_CHECKING - -from corehttp import MatchConditions - -from ._configuration import ConditionalRequestClientConfiguration - -if TYPE_CHECKING: - from corehttp.runtime import AsyncPipelineClient - - from .._serialization import Deserializer, Serializer - - -class ConditionalRequestClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "AsyncPipelineClient" - _config: ConditionalRequestClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" - - -def quote_etag(etag: Optional[str]) -> Optional[str]: - if not etag or etag == "*": - return etag - if etag.startswith("W/"): - return etag - if etag.startswith('"') and etag.endswith('"'): - return etag - if etag.startswith("'") and etag.endswith("'"): - return etag - return '"' + etag + '"' - - -def prep_if_match(etag: Optional[str], match_condition: Optional[MatchConditions]) -> Optional[str]: - if match_condition == MatchConditions.IfNotModified: - if_match = quote_etag(etag) if etag else None - return if_match - if match_condition == MatchConditions.IfPresent: - return "*" - return None - - -def prep_if_none_match(etag: Optional[str], match_condition: Optional[MatchConditions]) -> Optional[str]: - if match_condition == MatchConditions.IfModified: - if_none_match = quote_etag(etag) if etag else None - return if_none_match - if match_condition == MatchConditions.IfMissing: - return "*" - return None diff --git a/packages/typespec-python/test/unbranded/generated/special-headers-repeatability/specialheaders/repeatability/_client.py b/packages/typespec-python/test/unbranded/generated/special-headers-repeatability/specialheaders/repeatability/_client.py index d371f824e99..6cf7c076018 100644 --- a/packages/typespec-python/test/unbranded/generated/special-headers-repeatability/specialheaders/repeatability/_client.py +++ b/packages/typespec-python/test/unbranded/generated/special-headers-repeatability/specialheaders/repeatability/_client.py @@ -9,7 +9,7 @@ from ._configuration import RepeatabilityClientConfiguration from ._operations import RepeatabilityClientOperationsMixin -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer class RepeatabilityClient(RepeatabilityClientOperationsMixin): # pylint: disable=client-accepts-api-version-keyword diff --git a/packages/typespec-python/test/unbranded/generated/special-headers-repeatability/specialheaders/repeatability/_operations/_operations.py b/packages/typespec-python/test/unbranded/generated/special-headers-repeatability/specialheaders/repeatability/_operations/_operations.py index 60a08264fc8..7328a90ed87 100644 --- a/packages/typespec-python/test/unbranded/generated/special-headers-repeatability/specialheaders/repeatability/_operations/_operations.py +++ b/packages/typespec-python/test/unbranded/generated/special-headers-repeatability/specialheaders/repeatability/_operations/_operations.py @@ -13,11 +13,13 @@ map_error, ) from corehttp.rest import HttpRequest, HttpResponse +from corehttp.runtime import PipelineClient from corehttp.runtime.pipeline import PipelineResponse from corehttp.utils import case_insensitive_dict -from .._serialization import Serializer -from .._vendor import RepeatabilityClientMixinABC +from .._configuration import RepeatabilityClientConfiguration +from .._utils.serialization import Serializer +from .._utils.utils import ClientMixinABC T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] @@ -43,7 +45,7 @@ def build_repeatability_immediate_success_request(**kwargs: Any) -> HttpRequest: return HttpRequest(method="POST", url=_url, headers=_headers, **kwargs) -class RepeatabilityClientOperationsMixin(RepeatabilityClientMixinABC): +class RepeatabilityClientOperationsMixin(ClientMixinABC[PipelineClient, RepeatabilityClientConfiguration]): def immediate_success(self, **kwargs: Any) -> None: # pylint: disable=inconsistent-return-statements """Check we recognize Repeatability-Request-ID and Repeatability-First-Sent. diff --git a/packages/typespec-python/test/unbranded/generated/special-headers-repeatability/specialheaders/repeatability/_utils/__init__.py b/packages/typespec-python/test/unbranded/generated/special-headers-repeatability/specialheaders/repeatability/_utils/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/packages/typespec-python/test/unbranded/generated/special-headers-repeatability/specialheaders/repeatability/_model_base.py b/packages/typespec-python/test/unbranded/generated/special-headers-repeatability/specialheaders/repeatability/_utils/model_base.py similarity index 100% rename from packages/typespec-python/test/unbranded/generated/special-headers-repeatability/specialheaders/repeatability/_model_base.py rename to packages/typespec-python/test/unbranded/generated/special-headers-repeatability/specialheaders/repeatability/_utils/model_base.py diff --git a/packages/typespec-python/test/unbranded/generated/special-headers-repeatability/specialheaders/repeatability/_serialization.py b/packages/typespec-python/test/unbranded/generated/special-headers-repeatability/specialheaders/repeatability/_utils/serialization.py similarity index 100% rename from packages/typespec-python/test/unbranded/generated/special-headers-repeatability/specialheaders/repeatability/_serialization.py rename to packages/typespec-python/test/unbranded/generated/special-headers-repeatability/specialheaders/repeatability/_utils/serialization.py diff --git a/packages/typespec-python/test/unbranded/generated/special-headers-repeatability/specialheaders/repeatability/_utils/utils.py b/packages/typespec-python/test/unbranded/generated/special-headers-repeatability/specialheaders/repeatability/_utils/utils.py new file mode 100644 index 00000000000..02aa2f816ea --- /dev/null +++ b/packages/typespec-python/test/unbranded/generated/special-headers-repeatability/specialheaders/repeatability/_utils/utils.py @@ -0,0 +1,18 @@ +from abc import ABC +from typing import Generic, TYPE_CHECKING, TypeVar + +if TYPE_CHECKING: + from .serialization import Deserializer, Serializer + + +TClient = TypeVar("TClient") +TConfig = TypeVar("TConfig") + + +class ClientMixinABC(ABC, Generic[TClient, TConfig]): + """DO NOT use this class. It is for internal typing use only.""" + + _client: TClient + _config: TConfig + _serialize: "Serializer" + _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/unbranded/generated/special-headers-repeatability/specialheaders/repeatability/_vendor.py b/packages/typespec-python/test/unbranded/generated/special-headers-repeatability/specialheaders/repeatability/_vendor.py deleted file mode 100644 index 74b5290f1a6..00000000000 --- a/packages/typespec-python/test/unbranded/generated/special-headers-repeatability/specialheaders/repeatability/_vendor.py +++ /dev/null @@ -1,18 +0,0 @@ -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import RepeatabilityClientConfiguration - -if TYPE_CHECKING: - from corehttp.runtime import PipelineClient - - from ._serialization import Deserializer, Serializer - - -class RepeatabilityClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "PipelineClient" - _config: RepeatabilityClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/unbranded/generated/special-headers-repeatability/specialheaders/repeatability/aio/_client.py b/packages/typespec-python/test/unbranded/generated/special-headers-repeatability/specialheaders/repeatability/aio/_client.py index 0897745edd3..abd20e4628e 100644 --- a/packages/typespec-python/test/unbranded/generated/special-headers-repeatability/specialheaders/repeatability/aio/_client.py +++ b/packages/typespec-python/test/unbranded/generated/special-headers-repeatability/specialheaders/repeatability/aio/_client.py @@ -7,7 +7,7 @@ from corehttp.rest import AsyncHttpResponse, HttpRequest from corehttp.runtime import AsyncPipelineClient, policies -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import RepeatabilityClientConfiguration from ._operations import RepeatabilityClientOperationsMixin diff --git a/packages/typespec-python/test/unbranded/generated/special-headers-repeatability/specialheaders/repeatability/aio/_operations/_operations.py b/packages/typespec-python/test/unbranded/generated/special-headers-repeatability/specialheaders/repeatability/aio/_operations/_operations.py index 159b15a7bf0..6620ed9d8b5 100644 --- a/packages/typespec-python/test/unbranded/generated/special-headers-repeatability/specialheaders/repeatability/aio/_operations/_operations.py +++ b/packages/typespec-python/test/unbranded/generated/special-headers-repeatability/specialheaders/repeatability/aio/_operations/_operations.py @@ -11,16 +11,18 @@ map_error, ) from corehttp.rest import AsyncHttpResponse, HttpRequest +from corehttp.runtime import AsyncPipelineClient from corehttp.runtime.pipeline import PipelineResponse from ..._operations._operations import build_repeatability_immediate_success_request -from .._vendor import RepeatabilityClientMixinABC +from ..._utils.utils import ClientMixinABC +from .._configuration import RepeatabilityClientConfiguration T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, AsyncHttpResponse], T, Dict[str, Any]], Any]] -class RepeatabilityClientOperationsMixin(RepeatabilityClientMixinABC): +class RepeatabilityClientOperationsMixin(ClientMixinABC[AsyncPipelineClient, RepeatabilityClientConfiguration]): async def immediate_success(self, **kwargs: Any) -> None: """Check we recognize Repeatability-Request-ID and Repeatability-First-Sent. diff --git a/packages/typespec-python/test/unbranded/generated/special-headers-repeatability/specialheaders/repeatability/aio/_vendor.py b/packages/typespec-python/test/unbranded/generated/special-headers-repeatability/specialheaders/repeatability/aio/_vendor.py deleted file mode 100644 index 719b5bd38e9..00000000000 --- a/packages/typespec-python/test/unbranded/generated/special-headers-repeatability/specialheaders/repeatability/aio/_vendor.py +++ /dev/null @@ -1,18 +0,0 @@ -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import RepeatabilityClientConfiguration - -if TYPE_CHECKING: - from corehttp.runtime import AsyncPipelineClient - - from .._serialization import Deserializer, Serializer - - -class RepeatabilityClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "AsyncPipelineClient" - _config: RepeatabilityClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/unbranded/generated/special-words/specialwords/_client.py b/packages/typespec-python/test/unbranded/generated/special-words/specialwords/_client.py index 24759ef96b6..06ce296e1f1 100644 --- a/packages/typespec-python/test/unbranded/generated/special-words/specialwords/_client.py +++ b/packages/typespec-python/test/unbranded/generated/special-words/specialwords/_client.py @@ -8,7 +8,7 @@ from corehttp.runtime import PipelineClient, policies from ._configuration import SpecialWordsClientConfiguration -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer from .modelproperties.operations import ModelPropertiesOperations from .models.operations import ModelsOperations from .operations import Operations, ParametersOperations diff --git a/packages/typespec-python/test/unbranded/generated/special-words/specialwords/_utils/__init__.py b/packages/typespec-python/test/unbranded/generated/special-words/specialwords/_utils/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/packages/typespec-python/test/unbranded/generated/special-words/specialwords/_model_base.py b/packages/typespec-python/test/unbranded/generated/special-words/specialwords/_utils/model_base.py similarity index 100% rename from packages/typespec-python/test/unbranded/generated/special-words/specialwords/_model_base.py rename to packages/typespec-python/test/unbranded/generated/special-words/specialwords/_utils/model_base.py diff --git a/packages/typespec-python/test/unbranded/generated/special-words/specialwords/_serialization.py b/packages/typespec-python/test/unbranded/generated/special-words/specialwords/_utils/serialization.py similarity index 100% rename from packages/typespec-python/test/unbranded/generated/special-words/specialwords/_serialization.py rename to packages/typespec-python/test/unbranded/generated/special-words/specialwords/_utils/serialization.py diff --git a/packages/typespec-python/test/unbranded/generated/special-words/specialwords/aio/_client.py b/packages/typespec-python/test/unbranded/generated/special-words/specialwords/aio/_client.py index 9fda885262b..3e85666f60b 100644 --- a/packages/typespec-python/test/unbranded/generated/special-words/specialwords/aio/_client.py +++ b/packages/typespec-python/test/unbranded/generated/special-words/specialwords/aio/_client.py @@ -7,7 +7,7 @@ from corehttp.rest import AsyncHttpResponse, HttpRequest from corehttp.runtime import AsyncPipelineClient, policies -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ..modelproperties.aio.operations import ModelPropertiesOperations from ..models.aio.operations import ModelsOperations from ._configuration import SpecialWordsClientConfiguration diff --git a/packages/typespec-python/test/unbranded/generated/special-words/specialwords/aio/operations/_operations.py b/packages/typespec-python/test/unbranded/generated/special-words/specialwords/aio/operations/_operations.py index 9ed13b04285..5ed18ac93c1 100644 --- a/packages/typespec-python/test/unbranded/generated/special-words/specialwords/aio/operations/_operations.py +++ b/packages/typespec-python/test/unbranded/generated/special-words/specialwords/aio/operations/_operations.py @@ -15,7 +15,7 @@ from corehttp.runtime import AsyncPipelineClient from corehttp.runtime.pipeline import PipelineResponse -from ..._serialization import Deserializer, Serializer +from ..._utils.serialization import Deserializer, Serializer from ...operations._operations import ( build_operations_and_method_request, build_operations_as_method_request, diff --git a/packages/typespec-python/test/unbranded/generated/special-words/specialwords/modelproperties/aio/operations/_operations.py b/packages/typespec-python/test/unbranded/generated/special-words/specialwords/modelproperties/aio/operations/_operations.py index f8b60938a1f..0d57a8ecc5d 100644 --- a/packages/typespec-python/test/unbranded/generated/special-words/specialwords/modelproperties/aio/operations/_operations.py +++ b/packages/typespec-python/test/unbranded/generated/special-words/specialwords/modelproperties/aio/operations/_operations.py @@ -18,8 +18,8 @@ from corehttp.utils import case_insensitive_dict from ... import models as _models2 -from ...._model_base import SdkJSONEncoder -from ...._serialization import Deserializer, Serializer +from ...._utils.model_base import SdkJSONEncoder +from ...._utils.serialization import Deserializer, Serializer from ....aio._configuration import SpecialWordsClientConfiguration from ...operations._operations import build_model_properties_same_as_model_request diff --git a/packages/typespec-python/test/unbranded/generated/special-words/specialwords/modelproperties/models/_models.py b/packages/typespec-python/test/unbranded/generated/special-words/specialwords/modelproperties/models/_models.py index c3184464075..7944d92df98 100644 --- a/packages/typespec-python/test/unbranded/generated/special-words/specialwords/modelproperties/models/_models.py +++ b/packages/typespec-python/test/unbranded/generated/special-words/specialwords/modelproperties/models/_models.py @@ -3,11 +3,10 @@ from typing import Any, Mapping, overload -from ... import _model_base -from ..._model_base import rest_field +from ..._utils.model_base import Model as _Model, rest_field -class SameAsModel(_model_base.Model): +class SameAsModel(_Model): """SameAsModel. :ivar same_as_model: Required. diff --git a/packages/typespec-python/test/unbranded/generated/special-words/specialwords/modelproperties/operations/_operations.py b/packages/typespec-python/test/unbranded/generated/special-words/specialwords/modelproperties/operations/_operations.py index 9d2a47b6379..ac06431279a 100644 --- a/packages/typespec-python/test/unbranded/generated/special-words/specialwords/modelproperties/operations/_operations.py +++ b/packages/typespec-python/test/unbranded/generated/special-words/specialwords/modelproperties/operations/_operations.py @@ -19,8 +19,8 @@ from .. import models as _models1 from ..._configuration import SpecialWordsClientConfiguration -from ..._model_base import SdkJSONEncoder -from ..._serialization import Deserializer, Serializer +from ..._utils.model_base import SdkJSONEncoder +from ..._utils.serialization import Deserializer, Serializer JSON = MutableMapping[str, Any] T = TypeVar("T") diff --git a/packages/typespec-python/test/unbranded/generated/special-words/specialwords/models/aio/operations/_operations.py b/packages/typespec-python/test/unbranded/generated/special-words/specialwords/models/aio/operations/_operations.py index 14fa7689de2..7da50b08e27 100644 --- a/packages/typespec-python/test/unbranded/generated/special-words/specialwords/models/aio/operations/_operations.py +++ b/packages/typespec-python/test/unbranded/generated/special-words/specialwords/models/aio/operations/_operations.py @@ -19,8 +19,8 @@ from corehttp.utils import case_insensitive_dict from ... import models as _models2 -from ...._model_base import SdkJSONEncoder -from ...._serialization import Deserializer, Serializer +from ...._utils.model_base import SdkJSONEncoder +from ...._utils.serialization import Deserializer, Serializer from ....aio._configuration import SpecialWordsClientConfiguration from ...operations._operations import ( build_models_with_and_request, diff --git a/packages/typespec-python/test/unbranded/generated/special-words/specialwords/models/models/_models.py b/packages/typespec-python/test/unbranded/generated/special-words/specialwords/models/models/_models.py index c7bbe796a8e..56214349bd4 100644 --- a/packages/typespec-python/test/unbranded/generated/special-words/specialwords/models/models/_models.py +++ b/packages/typespec-python/test/unbranded/generated/special-words/specialwords/models/models/_models.py @@ -3,11 +3,10 @@ from typing import Any, Mapping, overload -from ... import _model_base -from ..._model_base import rest_field +from ..._utils.model_base import Model as _Model, rest_field -class AndModel(_model_base.Model): +class AndModel(_Model): """AndModel. :ivar name: Required. @@ -35,7 +34,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class AsModel(_model_base.Model): +class AsModel(_Model): """AsModel. :ivar name: Required. @@ -63,7 +62,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class AssertModel(_model_base.Model): +class AssertModel(_Model): """AssertModel. :ivar name: Required. @@ -91,7 +90,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class AsyncModel(_model_base.Model): +class AsyncModel(_Model): """AsyncModel. :ivar name: Required. @@ -119,7 +118,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class AwaitModel(_model_base.Model): +class AwaitModel(_Model): """AwaitModel. :ivar name: Required. @@ -147,7 +146,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class BreakModel(_model_base.Model): +class BreakModel(_Model): """BreakModel. :ivar name: Required. @@ -175,7 +174,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class ClassModel(_model_base.Model): +class ClassModel(_Model): """ClassModel. :ivar name: Required. @@ -203,7 +202,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class Constructor(_model_base.Model): +class Constructor(_Model): """Constructor. :ivar name: Required. @@ -231,7 +230,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class ContinueModel(_model_base.Model): +class ContinueModel(_Model): """ContinueModel. :ivar name: Required. @@ -259,7 +258,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class DefModel(_model_base.Model): +class DefModel(_Model): """DefModel. :ivar name: Required. @@ -287,7 +286,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class DelModel(_model_base.Model): +class DelModel(_Model): """DelModel. :ivar name: Required. @@ -315,7 +314,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class ElifModel(_model_base.Model): +class ElifModel(_Model): """ElifModel. :ivar name: Required. @@ -343,7 +342,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class ElseModel(_model_base.Model): +class ElseModel(_Model): """ElseModel. :ivar name: Required. @@ -371,7 +370,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class ExceptModel(_model_base.Model): +class ExceptModel(_Model): """ExceptModel. :ivar name: Required. @@ -399,7 +398,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class ExecModel(_model_base.Model): +class ExecModel(_Model): """ExecModel. :ivar name: Required. @@ -427,7 +426,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class FinallyModel(_model_base.Model): +class FinallyModel(_Model): """FinallyModel. :ivar name: Required. @@ -455,7 +454,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class ForModel(_model_base.Model): +class ForModel(_Model): """ForModel. :ivar name: Required. @@ -483,7 +482,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class FromModel(_model_base.Model): +class FromModel(_Model): """FromModel. :ivar name: Required. @@ -511,7 +510,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class GlobalModel(_model_base.Model): +class GlobalModel(_Model): """GlobalModel. :ivar name: Required. @@ -539,7 +538,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class IfModel(_model_base.Model): +class IfModel(_Model): """IfModel. :ivar name: Required. @@ -567,7 +566,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class ImportModel(_model_base.Model): +class ImportModel(_Model): """ImportModel. :ivar name: Required. @@ -595,7 +594,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class InModel(_model_base.Model): +class InModel(_Model): """InModel. :ivar name: Required. @@ -623,7 +622,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class IsModel(_model_base.Model): +class IsModel(_Model): """IsModel. :ivar name: Required. @@ -651,7 +650,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class LambdaModel(_model_base.Model): +class LambdaModel(_Model): """LambdaModel. :ivar name: Required. @@ -679,7 +678,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class NotModel(_model_base.Model): +class NotModel(_Model): """NotModel. :ivar name: Required. @@ -707,7 +706,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class OrModel(_model_base.Model): +class OrModel(_Model): """OrModel. :ivar name: Required. @@ -735,7 +734,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class PassModel(_model_base.Model): +class PassModel(_Model): """PassModel. :ivar name: Required. @@ -763,7 +762,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class RaiseModel(_model_base.Model): +class RaiseModel(_Model): """RaiseModel. :ivar name: Required. @@ -791,7 +790,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class ReturnModel(_model_base.Model): +class ReturnModel(_Model): """ReturnModel. :ivar name: Required. @@ -819,7 +818,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class TryModel(_model_base.Model): +class TryModel(_Model): """TryModel. :ivar name: Required. @@ -847,7 +846,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class WhileModel(_model_base.Model): +class WhileModel(_Model): """WhileModel. :ivar name: Required. @@ -875,7 +874,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class WithModel(_model_base.Model): +class WithModel(_Model): """WithModel. :ivar name: Required. @@ -903,7 +902,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class YieldModel(_model_base.Model): +class YieldModel(_Model): """YieldModel. :ivar name: Required. diff --git a/packages/typespec-python/test/unbranded/generated/special-words/specialwords/models/operations/_operations.py b/packages/typespec-python/test/unbranded/generated/special-words/specialwords/models/operations/_operations.py index 947f65584fe..26a272820f7 100644 --- a/packages/typespec-python/test/unbranded/generated/special-words/specialwords/models/operations/_operations.py +++ b/packages/typespec-python/test/unbranded/generated/special-words/specialwords/models/operations/_operations.py @@ -20,8 +20,8 @@ from .. import models as _models1 from ..._configuration import SpecialWordsClientConfiguration -from ..._model_base import SdkJSONEncoder -from ..._serialization import Deserializer, Serializer +from ..._utils.model_base import SdkJSONEncoder +from ..._utils.serialization import Deserializer, Serializer JSON = MutableMapping[str, Any] T = TypeVar("T") diff --git a/packages/typespec-python/test/unbranded/generated/special-words/specialwords/operations/_operations.py b/packages/typespec-python/test/unbranded/generated/special-words/specialwords/operations/_operations.py index d3059c875ed..ad0372408d0 100644 --- a/packages/typespec-python/test/unbranded/generated/special-words/specialwords/operations/_operations.py +++ b/packages/typespec-python/test/unbranded/generated/special-words/specialwords/operations/_operations.py @@ -17,7 +17,7 @@ from corehttp.utils import case_insensitive_dict from .._configuration import SpecialWordsClientConfiguration -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/typespec-python/test/unbranded/generated/streaming-jsonl/streaming/jsonl/_client.py b/packages/typespec-python/test/unbranded/generated/streaming-jsonl/streaming/jsonl/_client.py index a50bfbfc3ef..feb3d65ac5b 100644 --- a/packages/typespec-python/test/unbranded/generated/streaming-jsonl/streaming/jsonl/_client.py +++ b/packages/typespec-python/test/unbranded/generated/streaming-jsonl/streaming/jsonl/_client.py @@ -8,7 +8,7 @@ from corehttp.runtime import PipelineClient, policies from ._configuration import JsonlClientConfiguration -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer from .basic.operations import BasicOperations diff --git a/packages/typespec-python/test/unbranded/generated/streaming-jsonl/streaming/jsonl/_utils/__init__.py b/packages/typespec-python/test/unbranded/generated/streaming-jsonl/streaming/jsonl/_utils/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/packages/typespec-python/test/unbranded/generated/streaming-jsonl/streaming/jsonl/_model_base.py b/packages/typespec-python/test/unbranded/generated/streaming-jsonl/streaming/jsonl/_utils/model_base.py similarity index 100% rename from packages/typespec-python/test/unbranded/generated/streaming-jsonl/streaming/jsonl/_model_base.py rename to packages/typespec-python/test/unbranded/generated/streaming-jsonl/streaming/jsonl/_utils/model_base.py diff --git a/packages/typespec-python/test/unbranded/generated/streaming-jsonl/streaming/jsonl/_serialization.py b/packages/typespec-python/test/unbranded/generated/streaming-jsonl/streaming/jsonl/_utils/serialization.py similarity index 100% rename from packages/typespec-python/test/unbranded/generated/streaming-jsonl/streaming/jsonl/_serialization.py rename to packages/typespec-python/test/unbranded/generated/streaming-jsonl/streaming/jsonl/_utils/serialization.py diff --git a/packages/typespec-python/test/unbranded/generated/streaming-jsonl/streaming/jsonl/aio/_client.py b/packages/typespec-python/test/unbranded/generated/streaming-jsonl/streaming/jsonl/aio/_client.py index 2a9fc1a89f6..f0123acbc4f 100644 --- a/packages/typespec-python/test/unbranded/generated/streaming-jsonl/streaming/jsonl/aio/_client.py +++ b/packages/typespec-python/test/unbranded/generated/streaming-jsonl/streaming/jsonl/aio/_client.py @@ -7,7 +7,7 @@ from corehttp.rest import AsyncHttpResponse, HttpRequest from corehttp.runtime import AsyncPipelineClient, policies -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ..basic.aio.operations import BasicOperations from ._configuration import JsonlClientConfiguration diff --git a/packages/typespec-python/test/unbranded/generated/streaming-jsonl/streaming/jsonl/basic/aio/operations/_operations.py b/packages/typespec-python/test/unbranded/generated/streaming-jsonl/streaming/jsonl/basic/aio/operations/_operations.py index 712bc9326cf..ebe72ecdece 100644 --- a/packages/typespec-python/test/unbranded/generated/streaming-jsonl/streaming/jsonl/basic/aio/operations/_operations.py +++ b/packages/typespec-python/test/unbranded/generated/streaming-jsonl/streaming/jsonl/basic/aio/operations/_operations.py @@ -17,7 +17,7 @@ from corehttp.runtime.pipeline import PipelineResponse from corehttp.utils import case_insensitive_dict -from ...._serialization import Deserializer, Serializer +from ...._utils.serialization import Deserializer, Serializer from ....aio._configuration import JsonlClientConfiguration from ...operations._operations import build_basic_receive_request, build_basic_send_request diff --git a/packages/typespec-python/test/unbranded/generated/streaming-jsonl/streaming/jsonl/basic/operations/_operations.py b/packages/typespec-python/test/unbranded/generated/streaming-jsonl/streaming/jsonl/basic/operations/_operations.py index 9513307171d..a3c640ffee0 100644 --- a/packages/typespec-python/test/unbranded/generated/streaming-jsonl/streaming/jsonl/basic/operations/_operations.py +++ b/packages/typespec-python/test/unbranded/generated/streaming-jsonl/streaming/jsonl/basic/operations/_operations.py @@ -18,7 +18,7 @@ from corehttp.utils import case_insensitive_dict from ..._configuration import JsonlClientConfiguration -from ..._serialization import Deserializer, Serializer +from ..._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/typespec-python/test/unbranded/generated/typetest-array/typetest/array/_client.py b/packages/typespec-python/test/unbranded/generated/typetest-array/typetest/array/_client.py index 330e5f439e3..08e71e15c10 100644 --- a/packages/typespec-python/test/unbranded/generated/typetest-array/typetest/array/_client.py +++ b/packages/typespec-python/test/unbranded/generated/typetest-array/typetest/array/_client.py @@ -8,7 +8,7 @@ from corehttp.runtime import PipelineClient, policies from ._configuration import ArrayClientConfiguration -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer from .operations import ( BooleanValueOperations, DatetimeValueOperations, diff --git a/packages/typespec-python/test/unbranded/generated/typetest-array/typetest/array/_utils/__init__.py b/packages/typespec-python/test/unbranded/generated/typetest-array/typetest/array/_utils/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/packages/typespec-python/test/unbranded/generated/typetest-array/typetest/array/_model_base.py b/packages/typespec-python/test/unbranded/generated/typetest-array/typetest/array/_utils/model_base.py similarity index 100% rename from packages/typespec-python/test/unbranded/generated/typetest-array/typetest/array/_model_base.py rename to packages/typespec-python/test/unbranded/generated/typetest-array/typetest/array/_utils/model_base.py diff --git a/packages/typespec-python/test/unbranded/generated/typetest-array/typetest/array/_serialization.py b/packages/typespec-python/test/unbranded/generated/typetest-array/typetest/array/_utils/serialization.py similarity index 100% rename from packages/typespec-python/test/unbranded/generated/typetest-array/typetest/array/_serialization.py rename to packages/typespec-python/test/unbranded/generated/typetest-array/typetest/array/_utils/serialization.py diff --git a/packages/typespec-python/test/unbranded/generated/typetest-array/typetest/array/aio/_client.py b/packages/typespec-python/test/unbranded/generated/typetest-array/typetest/array/aio/_client.py index 1972edaf079..19c24fc6456 100644 --- a/packages/typespec-python/test/unbranded/generated/typetest-array/typetest/array/aio/_client.py +++ b/packages/typespec-python/test/unbranded/generated/typetest-array/typetest/array/aio/_client.py @@ -7,7 +7,7 @@ from corehttp.rest import AsyncHttpResponse, HttpRequest from corehttp.runtime import AsyncPipelineClient, policies -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import ArrayClientConfiguration from .operations import ( BooleanValueOperations, diff --git a/packages/typespec-python/test/unbranded/generated/typetest-array/typetest/array/aio/operations/_operations.py b/packages/typespec-python/test/unbranded/generated/typetest-array/typetest/array/aio/operations/_operations.py index f1716973590..dbea3f13641 100644 --- a/packages/typespec-python/test/unbranded/generated/typetest-array/typetest/array/aio/operations/_operations.py +++ b/packages/typespec-python/test/unbranded/generated/typetest-array/typetest/array/aio/operations/_operations.py @@ -22,8 +22,8 @@ from corehttp.utils import case_insensitive_dict from ... import models as _models -from ..._model_base import SdkJSONEncoder, _deserialize -from ..._serialization import Deserializer, Serializer +from ..._utils.model_base import SdkJSONEncoder, _deserialize +from ..._utils.serialization import Deserializer, Serializer from ...operations._operations import ( build_boolean_value_get_request, build_boolean_value_put_request, diff --git a/packages/typespec-python/test/unbranded/generated/typetest-array/typetest/array/models/_models.py b/packages/typespec-python/test/unbranded/generated/typetest-array/typetest/array/models/_models.py index 995393c84a6..39f2708dd2d 100644 --- a/packages/typespec-python/test/unbranded/generated/typetest-array/typetest/array/models/_models.py +++ b/packages/typespec-python/test/unbranded/generated/typetest-array/typetest/array/models/_models.py @@ -3,14 +3,13 @@ from typing import Any, List, Mapping, Optional, TYPE_CHECKING, overload -from .. import _model_base -from .._model_base import rest_field +from .._utils.model_base import Model as _Model, rest_field if TYPE_CHECKING: from .. import models as _models -class InnerModel(_model_base.Model): +class InnerModel(_Model): """Array inner model. :ivar property: Required string property. Required. diff --git a/packages/typespec-python/test/unbranded/generated/typetest-array/typetest/array/operations/_operations.py b/packages/typespec-python/test/unbranded/generated/typetest-array/typetest/array/operations/_operations.py index 3698d4fa394..d988b4c21a3 100644 --- a/packages/typespec-python/test/unbranded/generated/typetest-array/typetest/array/operations/_operations.py +++ b/packages/typespec-python/test/unbranded/generated/typetest-array/typetest/array/operations/_operations.py @@ -23,8 +23,8 @@ from .. import models as _models from .._configuration import ArrayClientConfiguration -from .._model_base import SdkJSONEncoder, _deserialize -from .._serialization import Deserializer, Serializer +from .._utils.model_base import SdkJSONEncoder, _deserialize +from .._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/typespec-python/test/unbranded/generated/typetest-dictionary/typetest/dictionary/_client.py b/packages/typespec-python/test/unbranded/generated/typetest-dictionary/typetest/dictionary/_client.py index 80ca1d5f13b..5fad49ebd0a 100644 --- a/packages/typespec-python/test/unbranded/generated/typetest-dictionary/typetest/dictionary/_client.py +++ b/packages/typespec-python/test/unbranded/generated/typetest-dictionary/typetest/dictionary/_client.py @@ -8,7 +8,7 @@ from corehttp.runtime import PipelineClient, policies from ._configuration import DictionaryClientConfiguration -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer from .operations import ( BooleanValueOperations, DatetimeValueOperations, diff --git a/packages/typespec-python/test/unbranded/generated/typetest-dictionary/typetest/dictionary/_utils/__init__.py b/packages/typespec-python/test/unbranded/generated/typetest-dictionary/typetest/dictionary/_utils/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/packages/typespec-python/test/unbranded/generated/typetest-dictionary/typetest/dictionary/_model_base.py b/packages/typespec-python/test/unbranded/generated/typetest-dictionary/typetest/dictionary/_utils/model_base.py similarity index 100% rename from packages/typespec-python/test/unbranded/generated/typetest-dictionary/typetest/dictionary/_model_base.py rename to packages/typespec-python/test/unbranded/generated/typetest-dictionary/typetest/dictionary/_utils/model_base.py diff --git a/packages/typespec-python/test/unbranded/generated/typetest-dictionary/typetest/dictionary/_serialization.py b/packages/typespec-python/test/unbranded/generated/typetest-dictionary/typetest/dictionary/_utils/serialization.py similarity index 100% rename from packages/typespec-python/test/unbranded/generated/typetest-dictionary/typetest/dictionary/_serialization.py rename to packages/typespec-python/test/unbranded/generated/typetest-dictionary/typetest/dictionary/_utils/serialization.py diff --git a/packages/typespec-python/test/unbranded/generated/typetest-dictionary/typetest/dictionary/aio/_client.py b/packages/typespec-python/test/unbranded/generated/typetest-dictionary/typetest/dictionary/aio/_client.py index 547d6aaa83f..a01df3d4f6d 100644 --- a/packages/typespec-python/test/unbranded/generated/typetest-dictionary/typetest/dictionary/aio/_client.py +++ b/packages/typespec-python/test/unbranded/generated/typetest-dictionary/typetest/dictionary/aio/_client.py @@ -7,7 +7,7 @@ from corehttp.rest import AsyncHttpResponse, HttpRequest from corehttp.runtime import AsyncPipelineClient, policies -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import DictionaryClientConfiguration from .operations import ( BooleanValueOperations, diff --git a/packages/typespec-python/test/unbranded/generated/typetest-dictionary/typetest/dictionary/aio/operations/_operations.py b/packages/typespec-python/test/unbranded/generated/typetest-dictionary/typetest/dictionary/aio/operations/_operations.py index b1c1f761e5f..e3f52814484 100644 --- a/packages/typespec-python/test/unbranded/generated/typetest-dictionary/typetest/dictionary/aio/operations/_operations.py +++ b/packages/typespec-python/test/unbranded/generated/typetest-dictionary/typetest/dictionary/aio/operations/_operations.py @@ -22,8 +22,8 @@ from corehttp.utils import case_insensitive_dict from ... import models as _models -from ..._model_base import SdkJSONEncoder, _deserialize -from ..._serialization import Deserializer, Serializer +from ..._utils.model_base import SdkJSONEncoder, _deserialize +from ..._utils.serialization import Deserializer, Serializer from ...operations._operations import ( build_boolean_value_get_request, build_boolean_value_put_request, diff --git a/packages/typespec-python/test/unbranded/generated/typetest-dictionary/typetest/dictionary/models/_models.py b/packages/typespec-python/test/unbranded/generated/typetest-dictionary/typetest/dictionary/models/_models.py index b068716a4dd..1cae2246648 100644 --- a/packages/typespec-python/test/unbranded/generated/typetest-dictionary/typetest/dictionary/models/_models.py +++ b/packages/typespec-python/test/unbranded/generated/typetest-dictionary/typetest/dictionary/models/_models.py @@ -3,14 +3,13 @@ from typing import Any, Dict, Mapping, Optional, TYPE_CHECKING, overload -from .. import _model_base -from .._model_base import rest_field +from .._utils.model_base import Model as _Model, rest_field if TYPE_CHECKING: from .. import models as _models -class InnerModel(_model_base.Model): +class InnerModel(_Model): """Dictionary inner model. :ivar property: Required string property. Required. diff --git a/packages/typespec-python/test/unbranded/generated/typetest-dictionary/typetest/dictionary/operations/_operations.py b/packages/typespec-python/test/unbranded/generated/typetest-dictionary/typetest/dictionary/operations/_operations.py index 9e2d9ec14f5..c4347d2dd20 100644 --- a/packages/typespec-python/test/unbranded/generated/typetest-dictionary/typetest/dictionary/operations/_operations.py +++ b/packages/typespec-python/test/unbranded/generated/typetest-dictionary/typetest/dictionary/operations/_operations.py @@ -23,8 +23,8 @@ from .. import models as _models from .._configuration import DictionaryClientConfiguration -from .._model_base import SdkJSONEncoder, _deserialize -from .._serialization import Deserializer, Serializer +from .._utils.model_base import SdkJSONEncoder, _deserialize +from .._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/typespec-python/test/unbranded/generated/typetest-enum-extensible/typetest/enum/extensible/_client.py b/packages/typespec-python/test/unbranded/generated/typetest-enum-extensible/typetest/enum/extensible/_client.py index ff6b75d0752..41ba8593129 100644 --- a/packages/typespec-python/test/unbranded/generated/typetest-enum-extensible/typetest/enum/extensible/_client.py +++ b/packages/typespec-python/test/unbranded/generated/typetest-enum-extensible/typetest/enum/extensible/_client.py @@ -8,7 +8,7 @@ from corehttp.runtime import PipelineClient, policies from ._configuration import ExtensibleClientConfiguration -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer from .operations import StringOperations diff --git a/packages/typespec-python/test/unbranded/generated/typetest-enum-extensible/typetest/enum/extensible/_utils/__init__.py b/packages/typespec-python/test/unbranded/generated/typetest-enum-extensible/typetest/enum/extensible/_utils/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/packages/typespec-python/test/unbranded/generated/typetest-enum-extensible/typetest/enum/extensible/_model_base.py b/packages/typespec-python/test/unbranded/generated/typetest-enum-extensible/typetest/enum/extensible/_utils/model_base.py similarity index 100% rename from packages/typespec-python/test/unbranded/generated/typetest-enum-extensible/typetest/enum/extensible/_model_base.py rename to packages/typespec-python/test/unbranded/generated/typetest-enum-extensible/typetest/enum/extensible/_utils/model_base.py diff --git a/packages/typespec-python/test/unbranded/generated/typetest-enum-extensible/typetest/enum/extensible/_serialization.py b/packages/typespec-python/test/unbranded/generated/typetest-enum-extensible/typetest/enum/extensible/_utils/serialization.py similarity index 100% rename from packages/typespec-python/test/unbranded/generated/typetest-enum-extensible/typetest/enum/extensible/_serialization.py rename to packages/typespec-python/test/unbranded/generated/typetest-enum-extensible/typetest/enum/extensible/_utils/serialization.py diff --git a/packages/typespec-python/test/unbranded/generated/typetest-enum-extensible/typetest/enum/extensible/aio/_client.py b/packages/typespec-python/test/unbranded/generated/typetest-enum-extensible/typetest/enum/extensible/aio/_client.py index 89d3733b354..9fb7f42219d 100644 --- a/packages/typespec-python/test/unbranded/generated/typetest-enum-extensible/typetest/enum/extensible/aio/_client.py +++ b/packages/typespec-python/test/unbranded/generated/typetest-enum-extensible/typetest/enum/extensible/aio/_client.py @@ -7,7 +7,7 @@ from corehttp.rest import AsyncHttpResponse, HttpRequest from corehttp.runtime import AsyncPipelineClient, policies -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import ExtensibleClientConfiguration from .operations import StringOperations diff --git a/packages/typespec-python/test/unbranded/generated/typetest-enum-extensible/typetest/enum/extensible/aio/operations/_operations.py b/packages/typespec-python/test/unbranded/generated/typetest-enum-extensible/typetest/enum/extensible/aio/operations/_operations.py index 20efe5909e5..5ceff58a053 100644 --- a/packages/typespec-python/test/unbranded/generated/typetest-enum-extensible/typetest/enum/extensible/aio/operations/_operations.py +++ b/packages/typespec-python/test/unbranded/generated/typetest-enum-extensible/typetest/enum/extensible/aio/operations/_operations.py @@ -19,8 +19,8 @@ from corehttp.utils import case_insensitive_dict from ... import models as _models -from ..._model_base import SdkJSONEncoder, _deserialize -from ..._serialization import Deserializer, Serializer +from ..._utils.model_base import SdkJSONEncoder, _deserialize +from ..._utils.serialization import Deserializer, Serializer from ...operations._operations import ( build_string_get_known_value_request, build_string_get_unknown_value_request, diff --git a/packages/typespec-python/test/unbranded/generated/typetest-enum-extensible/typetest/enum/extensible/operations/_operations.py b/packages/typespec-python/test/unbranded/generated/typetest-enum-extensible/typetest/enum/extensible/operations/_operations.py index c556b9ee5fc..4335afdb2a1 100644 --- a/packages/typespec-python/test/unbranded/generated/typetest-enum-extensible/typetest/enum/extensible/operations/_operations.py +++ b/packages/typespec-python/test/unbranded/generated/typetest-enum-extensible/typetest/enum/extensible/operations/_operations.py @@ -20,8 +20,8 @@ from .. import models as _models from .._configuration import ExtensibleClientConfiguration -from .._model_base import SdkJSONEncoder, _deserialize -from .._serialization import Deserializer, Serializer +from .._utils.model_base import SdkJSONEncoder, _deserialize +from .._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/typespec-python/test/unbranded/generated/typetest-enum-fixed/typetest/enum/fixed/_client.py b/packages/typespec-python/test/unbranded/generated/typetest-enum-fixed/typetest/enum/fixed/_client.py index af5c6b7e08f..9796efb373e 100644 --- a/packages/typespec-python/test/unbranded/generated/typetest-enum-fixed/typetest/enum/fixed/_client.py +++ b/packages/typespec-python/test/unbranded/generated/typetest-enum-fixed/typetest/enum/fixed/_client.py @@ -8,7 +8,7 @@ from corehttp.runtime import PipelineClient, policies from ._configuration import FixedClientConfiguration -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer from .operations import StringOperations diff --git a/packages/typespec-python/test/unbranded/generated/typetest-enum-fixed/typetest/enum/fixed/_utils/__init__.py b/packages/typespec-python/test/unbranded/generated/typetest-enum-fixed/typetest/enum/fixed/_utils/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/packages/typespec-python/test/unbranded/generated/typetest-enum-fixed/typetest/enum/fixed/_model_base.py b/packages/typespec-python/test/unbranded/generated/typetest-enum-fixed/typetest/enum/fixed/_utils/model_base.py similarity index 100% rename from packages/typespec-python/test/unbranded/generated/typetest-enum-fixed/typetest/enum/fixed/_model_base.py rename to packages/typespec-python/test/unbranded/generated/typetest-enum-fixed/typetest/enum/fixed/_utils/model_base.py diff --git a/packages/typespec-python/test/unbranded/generated/typetest-enum-fixed/typetest/enum/fixed/_serialization.py b/packages/typespec-python/test/unbranded/generated/typetest-enum-fixed/typetest/enum/fixed/_utils/serialization.py similarity index 100% rename from packages/typespec-python/test/unbranded/generated/typetest-enum-fixed/typetest/enum/fixed/_serialization.py rename to packages/typespec-python/test/unbranded/generated/typetest-enum-fixed/typetest/enum/fixed/_utils/serialization.py diff --git a/packages/typespec-python/test/unbranded/generated/typetest-enum-fixed/typetest/enum/fixed/aio/_client.py b/packages/typespec-python/test/unbranded/generated/typetest-enum-fixed/typetest/enum/fixed/aio/_client.py index 336dd86ce2c..b816e9c3124 100644 --- a/packages/typespec-python/test/unbranded/generated/typetest-enum-fixed/typetest/enum/fixed/aio/_client.py +++ b/packages/typespec-python/test/unbranded/generated/typetest-enum-fixed/typetest/enum/fixed/aio/_client.py @@ -7,7 +7,7 @@ from corehttp.rest import AsyncHttpResponse, HttpRequest from corehttp.runtime import AsyncPipelineClient, policies -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import FixedClientConfiguration from .operations import StringOperations diff --git a/packages/typespec-python/test/unbranded/generated/typetest-enum-fixed/typetest/enum/fixed/aio/operations/_operations.py b/packages/typespec-python/test/unbranded/generated/typetest-enum-fixed/typetest/enum/fixed/aio/operations/_operations.py index ad9432aeece..3621e60518d 100644 --- a/packages/typespec-python/test/unbranded/generated/typetest-enum-fixed/typetest/enum/fixed/aio/operations/_operations.py +++ b/packages/typespec-python/test/unbranded/generated/typetest-enum-fixed/typetest/enum/fixed/aio/operations/_operations.py @@ -19,8 +19,8 @@ from corehttp.utils import case_insensitive_dict from ... import models as _models -from ..._model_base import SdkJSONEncoder, _deserialize -from ..._serialization import Deserializer, Serializer +from ..._utils.model_base import SdkJSONEncoder, _deserialize +from ..._utils.serialization import Deserializer, Serializer from ...operations._operations import ( build_string_get_known_value_request, build_string_put_known_value_request, diff --git a/packages/typespec-python/test/unbranded/generated/typetest-enum-fixed/typetest/enum/fixed/operations/_operations.py b/packages/typespec-python/test/unbranded/generated/typetest-enum-fixed/typetest/enum/fixed/operations/_operations.py index 2be603b38e5..8a92ef8dfd4 100644 --- a/packages/typespec-python/test/unbranded/generated/typetest-enum-fixed/typetest/enum/fixed/operations/_operations.py +++ b/packages/typespec-python/test/unbranded/generated/typetest-enum-fixed/typetest/enum/fixed/operations/_operations.py @@ -20,8 +20,8 @@ from .. import models as _models from .._configuration import FixedClientConfiguration -from .._model_base import SdkJSONEncoder, _deserialize -from .._serialization import Deserializer, Serializer +from .._utils.model_base import SdkJSONEncoder, _deserialize +from .._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/typespec-python/test/unbranded/generated/typetest-model-empty/typetest/model/empty/_client.py b/packages/typespec-python/test/unbranded/generated/typetest-model-empty/typetest/model/empty/_client.py index 3dbf0abe3f1..ab62b05bb86 100644 --- a/packages/typespec-python/test/unbranded/generated/typetest-model-empty/typetest/model/empty/_client.py +++ b/packages/typespec-python/test/unbranded/generated/typetest-model-empty/typetest/model/empty/_client.py @@ -9,7 +9,7 @@ from ._configuration import EmptyClientConfiguration from ._operations import EmptyClientOperationsMixin -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer class EmptyClient(EmptyClientOperationsMixin): # pylint: disable=client-accepts-api-version-keyword diff --git a/packages/typespec-python/test/unbranded/generated/typetest-model-empty/typetest/model/empty/_operations/_operations.py b/packages/typespec-python/test/unbranded/generated/typetest-model-empty/typetest/model/empty/_operations/_operations.py index ea34116f630..e14adb34961 100644 --- a/packages/typespec-python/test/unbranded/generated/typetest-model-empty/typetest/model/empty/_operations/_operations.py +++ b/packages/typespec-python/test/unbranded/generated/typetest-model-empty/typetest/model/empty/_operations/_operations.py @@ -15,13 +15,15 @@ map_error, ) from corehttp.rest import HttpRequest, HttpResponse +from corehttp.runtime import PipelineClient from corehttp.runtime.pipeline import PipelineResponse from corehttp.utils import case_insensitive_dict from .. import models as _models -from .._model_base import SdkJSONEncoder, _deserialize -from .._serialization import Serializer -from .._vendor import EmptyClientMixinABC +from .._configuration import EmptyClientConfiguration +from .._utils.model_base import SdkJSONEncoder, _deserialize +from .._utils.serialization import Serializer +from .._utils.utils import ClientMixinABC JSON = MutableMapping[str, Any] T = TypeVar("T") @@ -76,7 +78,7 @@ def build_empty_post_round_trip_empty_request(**kwargs: Any) -> HttpRequest: # return HttpRequest(method="POST", url=_url, headers=_headers, **kwargs) -class EmptyClientOperationsMixin(EmptyClientMixinABC): +class EmptyClientOperationsMixin(ClientMixinABC[PipelineClient, EmptyClientConfiguration]): @overload def put_empty(self, input: _models.EmptyInput, *, content_type: str = "application/json", **kwargs: Any) -> None: diff --git a/packages/typespec-python/test/unbranded/generated/typetest-model-empty/typetest/model/empty/_utils/__init__.py b/packages/typespec-python/test/unbranded/generated/typetest-model-empty/typetest/model/empty/_utils/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/packages/typespec-python/test/unbranded/generated/typetest-model-empty/typetest/model/empty/_model_base.py b/packages/typespec-python/test/unbranded/generated/typetest-model-empty/typetest/model/empty/_utils/model_base.py similarity index 100% rename from packages/typespec-python/test/unbranded/generated/typetest-model-empty/typetest/model/empty/_model_base.py rename to packages/typespec-python/test/unbranded/generated/typetest-model-empty/typetest/model/empty/_utils/model_base.py diff --git a/packages/typespec-python/test/unbranded/generated/typetest-model-empty/typetest/model/empty/_serialization.py b/packages/typespec-python/test/unbranded/generated/typetest-model-empty/typetest/model/empty/_utils/serialization.py similarity index 100% rename from packages/typespec-python/test/unbranded/generated/typetest-model-empty/typetest/model/empty/_serialization.py rename to packages/typespec-python/test/unbranded/generated/typetest-model-empty/typetest/model/empty/_utils/serialization.py diff --git a/packages/typespec-python/test/unbranded/generated/typetest-model-empty/typetest/model/empty/_utils/utils.py b/packages/typespec-python/test/unbranded/generated/typetest-model-empty/typetest/model/empty/_utils/utils.py new file mode 100644 index 00000000000..02aa2f816ea --- /dev/null +++ b/packages/typespec-python/test/unbranded/generated/typetest-model-empty/typetest/model/empty/_utils/utils.py @@ -0,0 +1,18 @@ +from abc import ABC +from typing import Generic, TYPE_CHECKING, TypeVar + +if TYPE_CHECKING: + from .serialization import Deserializer, Serializer + + +TClient = TypeVar("TClient") +TConfig = TypeVar("TConfig") + + +class ClientMixinABC(ABC, Generic[TClient, TConfig]): + """DO NOT use this class. It is for internal typing use only.""" + + _client: TClient + _config: TConfig + _serialize: "Serializer" + _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/unbranded/generated/typetest-model-empty/typetest/model/empty/_vendor.py b/packages/typespec-python/test/unbranded/generated/typetest-model-empty/typetest/model/empty/_vendor.py deleted file mode 100644 index 8e5bf449d13..00000000000 --- a/packages/typespec-python/test/unbranded/generated/typetest-model-empty/typetest/model/empty/_vendor.py +++ /dev/null @@ -1,18 +0,0 @@ -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import EmptyClientConfiguration - -if TYPE_CHECKING: - from corehttp.runtime import PipelineClient - - from ._serialization import Deserializer, Serializer - - -class EmptyClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "PipelineClient" - _config: EmptyClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/unbranded/generated/typetest-model-empty/typetest/model/empty/aio/_client.py b/packages/typespec-python/test/unbranded/generated/typetest-model-empty/typetest/model/empty/aio/_client.py index 82baa939e13..941e84034b1 100644 --- a/packages/typespec-python/test/unbranded/generated/typetest-model-empty/typetest/model/empty/aio/_client.py +++ b/packages/typespec-python/test/unbranded/generated/typetest-model-empty/typetest/model/empty/aio/_client.py @@ -7,7 +7,7 @@ from corehttp.rest import AsyncHttpResponse, HttpRequest from corehttp.runtime import AsyncPipelineClient, policies -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import EmptyClientConfiguration from ._operations import EmptyClientOperationsMixin diff --git a/packages/typespec-python/test/unbranded/generated/typetest-model-empty/typetest/model/empty/aio/_operations/_operations.py b/packages/typespec-python/test/unbranded/generated/typetest-model-empty/typetest/model/empty/aio/_operations/_operations.py index 2cdb711ca5a..2a56b3653b0 100644 --- a/packages/typespec-python/test/unbranded/generated/typetest-model-empty/typetest/model/empty/aio/_operations/_operations.py +++ b/packages/typespec-python/test/unbranded/generated/typetest-model-empty/typetest/model/empty/aio/_operations/_operations.py @@ -15,24 +15,26 @@ map_error, ) from corehttp.rest import AsyncHttpResponse, HttpRequest +from corehttp.runtime import AsyncPipelineClient from corehttp.runtime.pipeline import PipelineResponse from corehttp.utils import case_insensitive_dict from ... import models as _models -from ..._model_base import SdkJSONEncoder, _deserialize from ..._operations._operations import ( build_empty_get_empty_request, build_empty_post_round_trip_empty_request, build_empty_put_empty_request, ) -from .._vendor import EmptyClientMixinABC +from ..._utils.model_base import SdkJSONEncoder, _deserialize +from ..._utils.utils import ClientMixinABC +from .._configuration import EmptyClientConfiguration JSON = MutableMapping[str, Any] T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, AsyncHttpResponse], T, Dict[str, Any]], Any]] -class EmptyClientOperationsMixin(EmptyClientMixinABC): +class EmptyClientOperationsMixin(ClientMixinABC[AsyncPipelineClient, EmptyClientConfiguration]): @overload async def put_empty( diff --git a/packages/typespec-python/test/unbranded/generated/typetest-model-empty/typetest/model/empty/aio/_vendor.py b/packages/typespec-python/test/unbranded/generated/typetest-model-empty/typetest/model/empty/aio/_vendor.py deleted file mode 100644 index e9990a8b1eb..00000000000 --- a/packages/typespec-python/test/unbranded/generated/typetest-model-empty/typetest/model/empty/aio/_vendor.py +++ /dev/null @@ -1,18 +0,0 @@ -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import EmptyClientConfiguration - -if TYPE_CHECKING: - from corehttp.runtime import AsyncPipelineClient - - from .._serialization import Deserializer, Serializer - - -class EmptyClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "AsyncPipelineClient" - _config: EmptyClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/unbranded/generated/typetest-model-empty/typetest/model/empty/models/_models.py b/packages/typespec-python/test/unbranded/generated/typetest-model-empty/typetest/model/empty/models/_models.py index ece8028edf6..8e7cc574f38 100644 --- a/packages/typespec-python/test/unbranded/generated/typetest-model-empty/typetest/model/empty/models/_models.py +++ b/packages/typespec-python/test/unbranded/generated/typetest-model-empty/typetest/model/empty/models/_models.py @@ -1,15 +1,15 @@ # coding=utf-8 -from .. import _model_base +from .._utils.model_base import Model as _Model -class EmptyInput(_model_base.Model): +class EmptyInput(_Model): """Empty model used in operation parameters.""" -class EmptyInputOutput(_model_base.Model): +class EmptyInputOutput(_Model): """Empty model used in both parameter and return type.""" -class EmptyOutput(_model_base.Model): +class EmptyOutput(_Model): """Empty model used in operation return type.""" diff --git a/packages/typespec-python/test/unbranded/generated/typetest-model-enumdiscriminator/typetest/model/enumdiscriminator/_client.py b/packages/typespec-python/test/unbranded/generated/typetest-model-enumdiscriminator/typetest/model/enumdiscriminator/_client.py index 1837467753e..761db957531 100644 --- a/packages/typespec-python/test/unbranded/generated/typetest-model-enumdiscriminator/typetest/model/enumdiscriminator/_client.py +++ b/packages/typespec-python/test/unbranded/generated/typetest-model-enumdiscriminator/typetest/model/enumdiscriminator/_client.py @@ -9,7 +9,7 @@ from ._configuration import EnumDiscriminatorClientConfiguration from ._operations import EnumDiscriminatorClientOperationsMixin -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer class EnumDiscriminatorClient( diff --git a/packages/typespec-python/test/unbranded/generated/typetest-model-enumdiscriminator/typetest/model/enumdiscriminator/_operations/_operations.py b/packages/typespec-python/test/unbranded/generated/typetest-model-enumdiscriminator/typetest/model/enumdiscriminator/_operations/_operations.py index bb7261f880d..47a42230a7b 100644 --- a/packages/typespec-python/test/unbranded/generated/typetest-model-enumdiscriminator/typetest/model/enumdiscriminator/_operations/_operations.py +++ b/packages/typespec-python/test/unbranded/generated/typetest-model-enumdiscriminator/typetest/model/enumdiscriminator/_operations/_operations.py @@ -15,13 +15,15 @@ map_error, ) from corehttp.rest import HttpRequest, HttpResponse +from corehttp.runtime import PipelineClient from corehttp.runtime.pipeline import PipelineResponse from corehttp.utils import case_insensitive_dict from .. import models as _models -from .._model_base import SdkJSONEncoder, _deserialize -from .._serialization import Serializer -from .._vendor import EnumDiscriminatorClientMixinABC +from .._configuration import EnumDiscriminatorClientConfiguration +from .._utils.model_base import SdkJSONEncoder, _deserialize +from .._utils.serialization import Serializer +from .._utils.utils import ClientMixinABC JSON = MutableMapping[str, Any] T = TypeVar("T") @@ -155,7 +157,7 @@ def build_enum_discriminator_get_fixed_model_wrong_discriminator_request( # pyl return HttpRequest(method="GET", url=_url, headers=_headers, **kwargs) -class EnumDiscriminatorClientOperationsMixin(EnumDiscriminatorClientMixinABC): +class EnumDiscriminatorClientOperationsMixin(ClientMixinABC[PipelineClient, EnumDiscriminatorClientConfiguration]): def get_extensible_model(self, **kwargs: Any) -> _models.Dog: """Receive model with extensible enum discriminator type. diff --git a/packages/typespec-python/test/unbranded/generated/typetest-model-enumdiscriminator/typetest/model/enumdiscriminator/_utils/__init__.py b/packages/typespec-python/test/unbranded/generated/typetest-model-enumdiscriminator/typetest/model/enumdiscriminator/_utils/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/packages/typespec-python/test/unbranded/generated/typetest-model-enumdiscriminator/typetest/model/enumdiscriminator/_model_base.py b/packages/typespec-python/test/unbranded/generated/typetest-model-enumdiscriminator/typetest/model/enumdiscriminator/_utils/model_base.py similarity index 100% rename from packages/typespec-python/test/unbranded/generated/typetest-model-enumdiscriminator/typetest/model/enumdiscriminator/_model_base.py rename to packages/typespec-python/test/unbranded/generated/typetest-model-enumdiscriminator/typetest/model/enumdiscriminator/_utils/model_base.py diff --git a/packages/typespec-python/test/unbranded/generated/typetest-model-enumdiscriminator/typetest/model/enumdiscriminator/_serialization.py b/packages/typespec-python/test/unbranded/generated/typetest-model-enumdiscriminator/typetest/model/enumdiscriminator/_utils/serialization.py similarity index 100% rename from packages/typespec-python/test/unbranded/generated/typetest-model-enumdiscriminator/typetest/model/enumdiscriminator/_serialization.py rename to packages/typespec-python/test/unbranded/generated/typetest-model-enumdiscriminator/typetest/model/enumdiscriminator/_utils/serialization.py diff --git a/packages/typespec-python/test/unbranded/generated/typetest-model-enumdiscriminator/typetest/model/enumdiscriminator/_utils/utils.py b/packages/typespec-python/test/unbranded/generated/typetest-model-enumdiscriminator/typetest/model/enumdiscriminator/_utils/utils.py new file mode 100644 index 00000000000..02aa2f816ea --- /dev/null +++ b/packages/typespec-python/test/unbranded/generated/typetest-model-enumdiscriminator/typetest/model/enumdiscriminator/_utils/utils.py @@ -0,0 +1,18 @@ +from abc import ABC +from typing import Generic, TYPE_CHECKING, TypeVar + +if TYPE_CHECKING: + from .serialization import Deserializer, Serializer + + +TClient = TypeVar("TClient") +TConfig = TypeVar("TConfig") + + +class ClientMixinABC(ABC, Generic[TClient, TConfig]): + """DO NOT use this class. It is for internal typing use only.""" + + _client: TClient + _config: TConfig + _serialize: "Serializer" + _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/unbranded/generated/typetest-model-enumdiscriminator/typetest/model/enumdiscriminator/_vendor.py b/packages/typespec-python/test/unbranded/generated/typetest-model-enumdiscriminator/typetest/model/enumdiscriminator/_vendor.py deleted file mode 100644 index 2b9fa86451b..00000000000 --- a/packages/typespec-python/test/unbranded/generated/typetest-model-enumdiscriminator/typetest/model/enumdiscriminator/_vendor.py +++ /dev/null @@ -1,18 +0,0 @@ -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import EnumDiscriminatorClientConfiguration - -if TYPE_CHECKING: - from corehttp.runtime import PipelineClient - - from ._serialization import Deserializer, Serializer - - -class EnumDiscriminatorClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "PipelineClient" - _config: EnumDiscriminatorClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/unbranded/generated/typetest-model-enumdiscriminator/typetest/model/enumdiscriminator/aio/_client.py b/packages/typespec-python/test/unbranded/generated/typetest-model-enumdiscriminator/typetest/model/enumdiscriminator/aio/_client.py index 4fbd4e50e56..3f27b53dc9f 100644 --- a/packages/typespec-python/test/unbranded/generated/typetest-model-enumdiscriminator/typetest/model/enumdiscriminator/aio/_client.py +++ b/packages/typespec-python/test/unbranded/generated/typetest-model-enumdiscriminator/typetest/model/enumdiscriminator/aio/_client.py @@ -7,7 +7,7 @@ from corehttp.rest import AsyncHttpResponse, HttpRequest from corehttp.runtime import AsyncPipelineClient, policies -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import EnumDiscriminatorClientConfiguration from ._operations import EnumDiscriminatorClientOperationsMixin diff --git a/packages/typespec-python/test/unbranded/generated/typetest-model-enumdiscriminator/typetest/model/enumdiscriminator/aio/_operations/_operations.py b/packages/typespec-python/test/unbranded/generated/typetest-model-enumdiscriminator/typetest/model/enumdiscriminator/aio/_operations/_operations.py index 0f27b2dd7ff..069ecc73660 100644 --- a/packages/typespec-python/test/unbranded/generated/typetest-model-enumdiscriminator/typetest/model/enumdiscriminator/aio/_operations/_operations.py +++ b/packages/typespec-python/test/unbranded/generated/typetest-model-enumdiscriminator/typetest/model/enumdiscriminator/aio/_operations/_operations.py @@ -15,11 +15,11 @@ map_error, ) from corehttp.rest import AsyncHttpResponse, HttpRequest +from corehttp.runtime import AsyncPipelineClient from corehttp.runtime.pipeline import PipelineResponse from corehttp.utils import case_insensitive_dict from ... import models as _models -from ..._model_base import SdkJSONEncoder, _deserialize from ..._operations._operations import ( build_enum_discriminator_get_extensible_model_missing_discriminator_request, build_enum_discriminator_get_extensible_model_request, @@ -30,14 +30,16 @@ build_enum_discriminator_put_extensible_model_request, build_enum_discriminator_put_fixed_model_request, ) -from .._vendor import EnumDiscriminatorClientMixinABC +from ..._utils.model_base import SdkJSONEncoder, _deserialize +from ..._utils.utils import ClientMixinABC +from .._configuration import EnumDiscriminatorClientConfiguration JSON = MutableMapping[str, Any] T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, AsyncHttpResponse], T, Dict[str, Any]], Any]] -class EnumDiscriminatorClientOperationsMixin(EnumDiscriminatorClientMixinABC): +class EnumDiscriminatorClientOperationsMixin(ClientMixinABC[AsyncPipelineClient, EnumDiscriminatorClientConfiguration]): async def get_extensible_model(self, **kwargs: Any) -> _models.Dog: """Receive model with extensible enum discriminator type. diff --git a/packages/typespec-python/test/unbranded/generated/typetest-model-enumdiscriminator/typetest/model/enumdiscriminator/aio/_vendor.py b/packages/typespec-python/test/unbranded/generated/typetest-model-enumdiscriminator/typetest/model/enumdiscriminator/aio/_vendor.py deleted file mode 100644 index f8ad0c865ea..00000000000 --- a/packages/typespec-python/test/unbranded/generated/typetest-model-enumdiscriminator/typetest/model/enumdiscriminator/aio/_vendor.py +++ /dev/null @@ -1,18 +0,0 @@ -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import EnumDiscriminatorClientConfiguration - -if TYPE_CHECKING: - from corehttp.runtime import AsyncPipelineClient - - from .._serialization import Deserializer, Serializer - - -class EnumDiscriminatorClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "AsyncPipelineClient" - _config: EnumDiscriminatorClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/unbranded/generated/typetest-model-enumdiscriminator/typetest/model/enumdiscriminator/models/_models.py b/packages/typespec-python/test/unbranded/generated/typetest-model-enumdiscriminator/typetest/model/enumdiscriminator/models/_models.py index 77564305f09..a2a3bb05d00 100644 --- a/packages/typespec-python/test/unbranded/generated/typetest-model-enumdiscriminator/typetest/model/enumdiscriminator/models/_models.py +++ b/packages/typespec-python/test/unbranded/generated/typetest-model-enumdiscriminator/typetest/model/enumdiscriminator/models/_models.py @@ -4,12 +4,11 @@ from typing import Any, Dict, Literal, Mapping, overload -from .. import _model_base -from .._model_base import rest_discriminator, rest_field +from .._utils.model_base import Model as _Model, rest_discriminator, rest_field from ._enums import DogKind, SnakeKind -class Snake(_model_base.Model): +class Snake(_Model): """Test fixed enum type for discriminator. You probably want to use the sub-classes and not this class directly. Known sub-classes are: @@ -21,7 +20,7 @@ class Snake(_model_base.Model): :vartype length: int """ - __mapping__: Dict[str, _model_base.Model] = {} + __mapping__: Dict[str, _Model] = {} kind: str = rest_discriminator(name="kind", visibility=["read", "create", "update", "delete", "query"]) """discriminator property. Required. \"cobra\"""" length: int = rest_field(visibility=["read", "create", "update", "delete", "query"]) @@ -76,7 +75,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, kind=SnakeKind.COBRA, **kwargs) -class Dog(_model_base.Model): +class Dog(_Model): """Test extensible enum type for discriminator. You probably want to use the sub-classes and not this class directly. Known sub-classes are: @@ -88,7 +87,7 @@ class Dog(_model_base.Model): :vartype weight: int """ - __mapping__: Dict[str, _model_base.Model] = {} + __mapping__: Dict[str, _Model] = {} kind: str = rest_discriminator(name="kind", visibility=["read", "create", "update", "delete", "query"]) """discriminator property. Required. \"golden\"""" weight: int = rest_field(visibility=["read", "create", "update", "delete", "query"]) diff --git a/packages/typespec-python/test/unbranded/generated/typetest-model-nesteddiscriminator/typetest/model/nesteddiscriminator/_client.py b/packages/typespec-python/test/unbranded/generated/typetest-model-nesteddiscriminator/typetest/model/nesteddiscriminator/_client.py index cd28877642d..7dd5f4fce5d 100644 --- a/packages/typespec-python/test/unbranded/generated/typetest-model-nesteddiscriminator/typetest/model/nesteddiscriminator/_client.py +++ b/packages/typespec-python/test/unbranded/generated/typetest-model-nesteddiscriminator/typetest/model/nesteddiscriminator/_client.py @@ -9,7 +9,7 @@ from ._configuration import NestedDiscriminatorClientConfiguration from ._operations import NestedDiscriminatorClientOperationsMixin -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer class NestedDiscriminatorClient( diff --git a/packages/typespec-python/test/unbranded/generated/typetest-model-nesteddiscriminator/typetest/model/nesteddiscriminator/_operations/_operations.py b/packages/typespec-python/test/unbranded/generated/typetest-model-nesteddiscriminator/typetest/model/nesteddiscriminator/_operations/_operations.py index 6994a8ab86d..7a451c09f4e 100644 --- a/packages/typespec-python/test/unbranded/generated/typetest-model-nesteddiscriminator/typetest/model/nesteddiscriminator/_operations/_operations.py +++ b/packages/typespec-python/test/unbranded/generated/typetest-model-nesteddiscriminator/typetest/model/nesteddiscriminator/_operations/_operations.py @@ -15,13 +15,15 @@ map_error, ) from corehttp.rest import HttpRequest, HttpResponse +from corehttp.runtime import PipelineClient from corehttp.runtime.pipeline import PipelineResponse from corehttp.utils import case_insensitive_dict from .. import models as _models -from .._model_base import SdkJSONEncoder, _deserialize -from .._serialization import Serializer -from .._vendor import NestedDiscriminatorClientMixinABC +from .._configuration import NestedDiscriminatorClientConfiguration +from .._utils.model_base import SdkJSONEncoder, _deserialize +from .._utils.serialization import Serializer +from .._utils.utils import ClientMixinABC JSON = MutableMapping[str, Any] T = TypeVar("T") @@ -123,7 +125,7 @@ def build_nested_discriminator_get_wrong_discriminator_request( # pylint: disab return HttpRequest(method="GET", url=_url, headers=_headers, **kwargs) -class NestedDiscriminatorClientOperationsMixin(NestedDiscriminatorClientMixinABC): +class NestedDiscriminatorClientOperationsMixin(ClientMixinABC[PipelineClient, NestedDiscriminatorClientConfiguration]): def get_model(self, **kwargs: Any) -> _models.Fish: """get_model. diff --git a/packages/typespec-python/test/unbranded/generated/typetest-model-nesteddiscriminator/typetest/model/nesteddiscriminator/_utils/__init__.py b/packages/typespec-python/test/unbranded/generated/typetest-model-nesteddiscriminator/typetest/model/nesteddiscriminator/_utils/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/packages/typespec-python/test/unbranded/generated/typetest-model-nesteddiscriminator/typetest/model/nesteddiscriminator/_model_base.py b/packages/typespec-python/test/unbranded/generated/typetest-model-nesteddiscriminator/typetest/model/nesteddiscriminator/_utils/model_base.py similarity index 100% rename from packages/typespec-python/test/unbranded/generated/typetest-model-nesteddiscriminator/typetest/model/nesteddiscriminator/_model_base.py rename to packages/typespec-python/test/unbranded/generated/typetest-model-nesteddiscriminator/typetest/model/nesteddiscriminator/_utils/model_base.py diff --git a/packages/typespec-python/test/unbranded/generated/typetest-model-nesteddiscriminator/typetest/model/nesteddiscriminator/_serialization.py b/packages/typespec-python/test/unbranded/generated/typetest-model-nesteddiscriminator/typetest/model/nesteddiscriminator/_utils/serialization.py similarity index 100% rename from packages/typespec-python/test/unbranded/generated/typetest-model-nesteddiscriminator/typetest/model/nesteddiscriminator/_serialization.py rename to packages/typespec-python/test/unbranded/generated/typetest-model-nesteddiscriminator/typetest/model/nesteddiscriminator/_utils/serialization.py diff --git a/packages/typespec-python/test/unbranded/generated/typetest-model-nesteddiscriminator/typetest/model/nesteddiscriminator/_utils/utils.py b/packages/typespec-python/test/unbranded/generated/typetest-model-nesteddiscriminator/typetest/model/nesteddiscriminator/_utils/utils.py new file mode 100644 index 00000000000..02aa2f816ea --- /dev/null +++ b/packages/typespec-python/test/unbranded/generated/typetest-model-nesteddiscriminator/typetest/model/nesteddiscriminator/_utils/utils.py @@ -0,0 +1,18 @@ +from abc import ABC +from typing import Generic, TYPE_CHECKING, TypeVar + +if TYPE_CHECKING: + from .serialization import Deserializer, Serializer + + +TClient = TypeVar("TClient") +TConfig = TypeVar("TConfig") + + +class ClientMixinABC(ABC, Generic[TClient, TConfig]): + """DO NOT use this class. It is for internal typing use only.""" + + _client: TClient + _config: TConfig + _serialize: "Serializer" + _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/unbranded/generated/typetest-model-nesteddiscriminator/typetest/model/nesteddiscriminator/_vendor.py b/packages/typespec-python/test/unbranded/generated/typetest-model-nesteddiscriminator/typetest/model/nesteddiscriminator/_vendor.py deleted file mode 100644 index 1fb9b550299..00000000000 --- a/packages/typespec-python/test/unbranded/generated/typetest-model-nesteddiscriminator/typetest/model/nesteddiscriminator/_vendor.py +++ /dev/null @@ -1,18 +0,0 @@ -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import NestedDiscriminatorClientConfiguration - -if TYPE_CHECKING: - from corehttp.runtime import PipelineClient - - from ._serialization import Deserializer, Serializer - - -class NestedDiscriminatorClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "PipelineClient" - _config: NestedDiscriminatorClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/unbranded/generated/typetest-model-nesteddiscriminator/typetest/model/nesteddiscriminator/aio/_client.py b/packages/typespec-python/test/unbranded/generated/typetest-model-nesteddiscriminator/typetest/model/nesteddiscriminator/aio/_client.py index cdce6664b0e..549567a64ef 100644 --- a/packages/typespec-python/test/unbranded/generated/typetest-model-nesteddiscriminator/typetest/model/nesteddiscriminator/aio/_client.py +++ b/packages/typespec-python/test/unbranded/generated/typetest-model-nesteddiscriminator/typetest/model/nesteddiscriminator/aio/_client.py @@ -7,7 +7,7 @@ from corehttp.rest import AsyncHttpResponse, HttpRequest from corehttp.runtime import AsyncPipelineClient, policies -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import NestedDiscriminatorClientConfiguration from ._operations import NestedDiscriminatorClientOperationsMixin diff --git a/packages/typespec-python/test/unbranded/generated/typetest-model-nesteddiscriminator/typetest/model/nesteddiscriminator/aio/_operations/_operations.py b/packages/typespec-python/test/unbranded/generated/typetest-model-nesteddiscriminator/typetest/model/nesteddiscriminator/aio/_operations/_operations.py index 10f56d0f717..7722e640529 100644 --- a/packages/typespec-python/test/unbranded/generated/typetest-model-nesteddiscriminator/typetest/model/nesteddiscriminator/aio/_operations/_operations.py +++ b/packages/typespec-python/test/unbranded/generated/typetest-model-nesteddiscriminator/typetest/model/nesteddiscriminator/aio/_operations/_operations.py @@ -15,11 +15,11 @@ map_error, ) from corehttp.rest import AsyncHttpResponse, HttpRequest +from corehttp.runtime import AsyncPipelineClient from corehttp.runtime.pipeline import PipelineResponse from corehttp.utils import case_insensitive_dict from ... import models as _models -from ..._model_base import SdkJSONEncoder, _deserialize from ..._operations._operations import ( build_nested_discriminator_get_missing_discriminator_request, build_nested_discriminator_get_model_request, @@ -28,14 +28,18 @@ build_nested_discriminator_put_model_request, build_nested_discriminator_put_recursive_model_request, ) -from .._vendor import NestedDiscriminatorClientMixinABC +from ..._utils.model_base import SdkJSONEncoder, _deserialize +from ..._utils.utils import ClientMixinABC +from .._configuration import NestedDiscriminatorClientConfiguration JSON = MutableMapping[str, Any] T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, AsyncHttpResponse], T, Dict[str, Any]], Any]] -class NestedDiscriminatorClientOperationsMixin(NestedDiscriminatorClientMixinABC): +class NestedDiscriminatorClientOperationsMixin( + ClientMixinABC[AsyncPipelineClient, NestedDiscriminatorClientConfiguration] +): async def get_model(self, **kwargs: Any) -> _models.Fish: """get_model. diff --git a/packages/typespec-python/test/unbranded/generated/typetest-model-nesteddiscriminator/typetest/model/nesteddiscriminator/aio/_vendor.py b/packages/typespec-python/test/unbranded/generated/typetest-model-nesteddiscriminator/typetest/model/nesteddiscriminator/aio/_vendor.py deleted file mode 100644 index 2e9c25cd7e7..00000000000 --- a/packages/typespec-python/test/unbranded/generated/typetest-model-nesteddiscriminator/typetest/model/nesteddiscriminator/aio/_vendor.py +++ /dev/null @@ -1,18 +0,0 @@ -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import NestedDiscriminatorClientConfiguration - -if TYPE_CHECKING: - from corehttp.runtime import AsyncPipelineClient - - from .._serialization import Deserializer, Serializer - - -class NestedDiscriminatorClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "AsyncPipelineClient" - _config: NestedDiscriminatorClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/unbranded/generated/typetest-model-nesteddiscriminator/typetest/model/nesteddiscriminator/models/_models.py b/packages/typespec-python/test/unbranded/generated/typetest-model-nesteddiscriminator/typetest/model/nesteddiscriminator/models/_models.py index d64f96eac48..a16d91d327b 100644 --- a/packages/typespec-python/test/unbranded/generated/typetest-model-nesteddiscriminator/typetest/model/nesteddiscriminator/models/_models.py +++ b/packages/typespec-python/test/unbranded/generated/typetest-model-nesteddiscriminator/typetest/model/nesteddiscriminator/models/_models.py @@ -4,14 +4,13 @@ from typing import Any, Dict, List, Literal, Mapping, Optional, TYPE_CHECKING, overload -from .. import _model_base -from .._model_base import rest_discriminator, rest_field +from .._utils.model_base import Model as _Model, rest_discriminator, rest_field if TYPE_CHECKING: from .. import models as _models -class Fish(_model_base.Model): +class Fish(_Model): """This is base model for polymorphic multiple levels inheritance with a discriminator. You probably want to use the sub-classes and not this class directly. Known sub-classes are: @@ -23,7 +22,7 @@ class Fish(_model_base.Model): :vartype age: int """ - __mapping__: Dict[str, _model_base.Model] = {} + __mapping__: Dict[str, _Model] = {} kind: str = rest_discriminator(name="kind") """Discriminator property for Fish. Required. Default value is None.""" age: int = rest_field(visibility=["read", "create", "update", "delete", "query"]) @@ -63,7 +62,7 @@ class Shark(Fish, discriminator="shark"): :vartype sharktype: str """ - __mapping__: Dict[str, _model_base.Model] = {} + __mapping__: Dict[str, _Model] = {} kind: Literal["shark"] = rest_discriminator(name="kind", visibility=["read", "create", "update", "delete", "query"]) # type: ignore """Required. Default value is \"shark\".""" sharktype: str = rest_discriminator(name="sharktype", visibility=["read", "create", "update", "delete", "query"]) @@ -99,7 +98,7 @@ class GoblinShark(Shark, discriminator="goblin"): :vartype sharktype: str """ - __mapping__: Dict[str, _model_base.Model] = {} + __mapping__: Dict[str, _Model] = {} sharktype: Literal["goblin"] = rest_discriminator(name="sharktype", visibility=["read", "create", "update", "delete", "query"]) # type: ignore """Required. Default value is \"goblin\".""" @@ -175,7 +174,7 @@ class SawShark(Shark, discriminator="saw"): :vartype sharktype: str """ - __mapping__: Dict[str, _model_base.Model] = {} + __mapping__: Dict[str, _Model] = {} sharktype: Literal["saw"] = rest_discriminator(name="sharktype", visibility=["read", "create", "update", "delete", "query"]) # type: ignore """Required. Default value is \"saw\".""" diff --git a/packages/typespec-python/test/unbranded/generated/typetest-model-notdiscriminated/typetest/model/notdiscriminated/_client.py b/packages/typespec-python/test/unbranded/generated/typetest-model-notdiscriminated/typetest/model/notdiscriminated/_client.py index faa3da5885f..0226f54bb38 100644 --- a/packages/typespec-python/test/unbranded/generated/typetest-model-notdiscriminated/typetest/model/notdiscriminated/_client.py +++ b/packages/typespec-python/test/unbranded/generated/typetest-model-notdiscriminated/typetest/model/notdiscriminated/_client.py @@ -9,7 +9,7 @@ from ._configuration import NotDiscriminatedClientConfiguration from ._operations import NotDiscriminatedClientOperationsMixin -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer class NotDiscriminatedClient( diff --git a/packages/typespec-python/test/unbranded/generated/typetest-model-notdiscriminated/typetest/model/notdiscriminated/_operations/_operations.py b/packages/typespec-python/test/unbranded/generated/typetest-model-notdiscriminated/typetest/model/notdiscriminated/_operations/_operations.py index 681e0be0ef5..719056e5e80 100644 --- a/packages/typespec-python/test/unbranded/generated/typetest-model-notdiscriminated/typetest/model/notdiscriminated/_operations/_operations.py +++ b/packages/typespec-python/test/unbranded/generated/typetest-model-notdiscriminated/typetest/model/notdiscriminated/_operations/_operations.py @@ -15,13 +15,15 @@ map_error, ) from corehttp.rest import HttpRequest, HttpResponse +from corehttp.runtime import PipelineClient from corehttp.runtime.pipeline import PipelineResponse from corehttp.utils import case_insensitive_dict from .. import models as _models -from .._model_base import SdkJSONEncoder, _deserialize -from .._serialization import Serializer -from .._vendor import NotDiscriminatedClientMixinABC +from .._configuration import NotDiscriminatedClientConfiguration +from .._utils.model_base import SdkJSONEncoder, _deserialize +from .._utils.serialization import Serializer +from .._utils.utils import ClientMixinABC JSON = MutableMapping[str, Any] T = TypeVar("T") @@ -76,7 +78,7 @@ def build_not_discriminated_put_valid_request(**kwargs: Any) -> HttpRequest: # return HttpRequest(method="PUT", url=_url, headers=_headers, **kwargs) -class NotDiscriminatedClientOperationsMixin(NotDiscriminatedClientMixinABC): +class NotDiscriminatedClientOperationsMixin(ClientMixinABC[PipelineClient, NotDiscriminatedClientConfiguration]): @overload def post_valid(self, input: _models.Siamese, *, content_type: str = "application/json", **kwargs: Any) -> None: diff --git a/packages/typespec-python/test/unbranded/generated/typetest-model-notdiscriminated/typetest/model/notdiscriminated/_utils/__init__.py b/packages/typespec-python/test/unbranded/generated/typetest-model-notdiscriminated/typetest/model/notdiscriminated/_utils/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/packages/typespec-python/test/unbranded/generated/typetest-model-notdiscriminated/typetest/model/notdiscriminated/_model_base.py b/packages/typespec-python/test/unbranded/generated/typetest-model-notdiscriminated/typetest/model/notdiscriminated/_utils/model_base.py similarity index 100% rename from packages/typespec-python/test/unbranded/generated/typetest-model-notdiscriminated/typetest/model/notdiscriminated/_model_base.py rename to packages/typespec-python/test/unbranded/generated/typetest-model-notdiscriminated/typetest/model/notdiscriminated/_utils/model_base.py diff --git a/packages/typespec-python/test/unbranded/generated/typetest-model-notdiscriminated/typetest/model/notdiscriminated/_serialization.py b/packages/typespec-python/test/unbranded/generated/typetest-model-notdiscriminated/typetest/model/notdiscriminated/_utils/serialization.py similarity index 100% rename from packages/typespec-python/test/unbranded/generated/typetest-model-notdiscriminated/typetest/model/notdiscriminated/_serialization.py rename to packages/typespec-python/test/unbranded/generated/typetest-model-notdiscriminated/typetest/model/notdiscriminated/_utils/serialization.py diff --git a/packages/typespec-python/test/unbranded/generated/typetest-model-notdiscriminated/typetest/model/notdiscriminated/_utils/utils.py b/packages/typespec-python/test/unbranded/generated/typetest-model-notdiscriminated/typetest/model/notdiscriminated/_utils/utils.py new file mode 100644 index 00000000000..02aa2f816ea --- /dev/null +++ b/packages/typespec-python/test/unbranded/generated/typetest-model-notdiscriminated/typetest/model/notdiscriminated/_utils/utils.py @@ -0,0 +1,18 @@ +from abc import ABC +from typing import Generic, TYPE_CHECKING, TypeVar + +if TYPE_CHECKING: + from .serialization import Deserializer, Serializer + + +TClient = TypeVar("TClient") +TConfig = TypeVar("TConfig") + + +class ClientMixinABC(ABC, Generic[TClient, TConfig]): + """DO NOT use this class. It is for internal typing use only.""" + + _client: TClient + _config: TConfig + _serialize: "Serializer" + _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/unbranded/generated/typetest-model-notdiscriminated/typetest/model/notdiscriminated/_vendor.py b/packages/typespec-python/test/unbranded/generated/typetest-model-notdiscriminated/typetest/model/notdiscriminated/_vendor.py deleted file mode 100644 index 880e77471f9..00000000000 --- a/packages/typespec-python/test/unbranded/generated/typetest-model-notdiscriminated/typetest/model/notdiscriminated/_vendor.py +++ /dev/null @@ -1,18 +0,0 @@ -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import NotDiscriminatedClientConfiguration - -if TYPE_CHECKING: - from corehttp.runtime import PipelineClient - - from ._serialization import Deserializer, Serializer - - -class NotDiscriminatedClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "PipelineClient" - _config: NotDiscriminatedClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/unbranded/generated/typetest-model-notdiscriminated/typetest/model/notdiscriminated/aio/_client.py b/packages/typespec-python/test/unbranded/generated/typetest-model-notdiscriminated/typetest/model/notdiscriminated/aio/_client.py index 2c2a62c069e..7c262899509 100644 --- a/packages/typespec-python/test/unbranded/generated/typetest-model-notdiscriminated/typetest/model/notdiscriminated/aio/_client.py +++ b/packages/typespec-python/test/unbranded/generated/typetest-model-notdiscriminated/typetest/model/notdiscriminated/aio/_client.py @@ -7,7 +7,7 @@ from corehttp.rest import AsyncHttpResponse, HttpRequest from corehttp.runtime import AsyncPipelineClient, policies -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import NotDiscriminatedClientConfiguration from ._operations import NotDiscriminatedClientOperationsMixin diff --git a/packages/typespec-python/test/unbranded/generated/typetest-model-notdiscriminated/typetest/model/notdiscriminated/aio/_operations/_operations.py b/packages/typespec-python/test/unbranded/generated/typetest-model-notdiscriminated/typetest/model/notdiscriminated/aio/_operations/_operations.py index 9ff19a86ac5..58d98b4b0dd 100644 --- a/packages/typespec-python/test/unbranded/generated/typetest-model-notdiscriminated/typetest/model/notdiscriminated/aio/_operations/_operations.py +++ b/packages/typespec-python/test/unbranded/generated/typetest-model-notdiscriminated/typetest/model/notdiscriminated/aio/_operations/_operations.py @@ -15,24 +15,26 @@ map_error, ) from corehttp.rest import AsyncHttpResponse, HttpRequest +from corehttp.runtime import AsyncPipelineClient from corehttp.runtime.pipeline import PipelineResponse from corehttp.utils import case_insensitive_dict from ... import models as _models -from ..._model_base import SdkJSONEncoder, _deserialize from ..._operations._operations import ( build_not_discriminated_get_valid_request, build_not_discriminated_post_valid_request, build_not_discriminated_put_valid_request, ) -from .._vendor import NotDiscriminatedClientMixinABC +from ..._utils.model_base import SdkJSONEncoder, _deserialize +from ..._utils.utils import ClientMixinABC +from .._configuration import NotDiscriminatedClientConfiguration JSON = MutableMapping[str, Any] T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, AsyncHttpResponse], T, Dict[str, Any]], Any]] -class NotDiscriminatedClientOperationsMixin(NotDiscriminatedClientMixinABC): +class NotDiscriminatedClientOperationsMixin(ClientMixinABC[AsyncPipelineClient, NotDiscriminatedClientConfiguration]): @overload async def post_valid( diff --git a/packages/typespec-python/test/unbranded/generated/typetest-model-notdiscriminated/typetest/model/notdiscriminated/aio/_vendor.py b/packages/typespec-python/test/unbranded/generated/typetest-model-notdiscriminated/typetest/model/notdiscriminated/aio/_vendor.py deleted file mode 100644 index 628b51c08ea..00000000000 --- a/packages/typespec-python/test/unbranded/generated/typetest-model-notdiscriminated/typetest/model/notdiscriminated/aio/_vendor.py +++ /dev/null @@ -1,18 +0,0 @@ -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import NotDiscriminatedClientConfiguration - -if TYPE_CHECKING: - from corehttp.runtime import AsyncPipelineClient - - from .._serialization import Deserializer, Serializer - - -class NotDiscriminatedClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "AsyncPipelineClient" - _config: NotDiscriminatedClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/unbranded/generated/typetest-model-notdiscriminated/typetest/model/notdiscriminated/models/_models.py b/packages/typespec-python/test/unbranded/generated/typetest-model-notdiscriminated/typetest/model/notdiscriminated/models/_models.py index 42616bbc4e3..838cd399fb6 100644 --- a/packages/typespec-python/test/unbranded/generated/typetest-model-notdiscriminated/typetest/model/notdiscriminated/models/_models.py +++ b/packages/typespec-python/test/unbranded/generated/typetest-model-notdiscriminated/typetest/model/notdiscriminated/models/_models.py @@ -3,11 +3,10 @@ from typing import Any, Mapping, overload -from .. import _model_base -from .._model_base import rest_field +from .._utils.model_base import Model as _Model, rest_field -class Pet(_model_base.Model): +class Pet(_Model): """This is base model for not-discriminated normal multiple levels inheritance. :ivar name: Required. diff --git a/packages/typespec-python/test/unbranded/generated/typetest-model-recursive/typetest/model/recursive/_client.py b/packages/typespec-python/test/unbranded/generated/typetest-model-recursive/typetest/model/recursive/_client.py index 66ee7e05be8..ffa0c755772 100644 --- a/packages/typespec-python/test/unbranded/generated/typetest-model-recursive/typetest/model/recursive/_client.py +++ b/packages/typespec-python/test/unbranded/generated/typetest-model-recursive/typetest/model/recursive/_client.py @@ -9,7 +9,7 @@ from ._configuration import RecursiveClientConfiguration from ._operations import RecursiveClientOperationsMixin -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer class RecursiveClient(RecursiveClientOperationsMixin): # pylint: disable=client-accepts-api-version-keyword diff --git a/packages/typespec-python/test/unbranded/generated/typetest-model-recursive/typetest/model/recursive/_operations/_operations.py b/packages/typespec-python/test/unbranded/generated/typetest-model-recursive/typetest/model/recursive/_operations/_operations.py index ec73c16397a..c599c2ec111 100644 --- a/packages/typespec-python/test/unbranded/generated/typetest-model-recursive/typetest/model/recursive/_operations/_operations.py +++ b/packages/typespec-python/test/unbranded/generated/typetest-model-recursive/typetest/model/recursive/_operations/_operations.py @@ -15,13 +15,15 @@ map_error, ) from corehttp.rest import HttpRequest, HttpResponse +from corehttp.runtime import PipelineClient from corehttp.runtime.pipeline import PipelineResponse from corehttp.utils import case_insensitive_dict from .. import models as _models -from .._model_base import SdkJSONEncoder, _deserialize -from .._serialization import Serializer -from .._vendor import RecursiveClientMixinABC +from .._configuration import RecursiveClientConfiguration +from .._utils.model_base import SdkJSONEncoder, _deserialize +from .._utils.serialization import Serializer +from .._utils.utils import ClientMixinABC JSON = MutableMapping[str, Any] T = TypeVar("T") @@ -59,7 +61,7 @@ def build_recursive_get_request(**kwargs: Any) -> HttpRequest: return HttpRequest(method="GET", url=_url, headers=_headers, **kwargs) -class RecursiveClientOperationsMixin(RecursiveClientMixinABC): +class RecursiveClientOperationsMixin(ClientMixinABC[PipelineClient, RecursiveClientConfiguration]): @overload def put(self, input: _models.Extension, *, content_type: str = "application/json", **kwargs: Any) -> None: diff --git a/packages/typespec-python/test/unbranded/generated/typetest-model-recursive/typetest/model/recursive/_utils/__init__.py b/packages/typespec-python/test/unbranded/generated/typetest-model-recursive/typetest/model/recursive/_utils/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/packages/typespec-python/test/unbranded/generated/typetest-model-recursive/typetest/model/recursive/_model_base.py b/packages/typespec-python/test/unbranded/generated/typetest-model-recursive/typetest/model/recursive/_utils/model_base.py similarity index 100% rename from packages/typespec-python/test/unbranded/generated/typetest-model-recursive/typetest/model/recursive/_model_base.py rename to packages/typespec-python/test/unbranded/generated/typetest-model-recursive/typetest/model/recursive/_utils/model_base.py diff --git a/packages/typespec-python/test/unbranded/generated/typetest-model-recursive/typetest/model/recursive/_serialization.py b/packages/typespec-python/test/unbranded/generated/typetest-model-recursive/typetest/model/recursive/_utils/serialization.py similarity index 100% rename from packages/typespec-python/test/unbranded/generated/typetest-model-recursive/typetest/model/recursive/_serialization.py rename to packages/typespec-python/test/unbranded/generated/typetest-model-recursive/typetest/model/recursive/_utils/serialization.py diff --git a/packages/typespec-python/test/unbranded/generated/typetest-model-recursive/typetest/model/recursive/_utils/utils.py b/packages/typespec-python/test/unbranded/generated/typetest-model-recursive/typetest/model/recursive/_utils/utils.py new file mode 100644 index 00000000000..02aa2f816ea --- /dev/null +++ b/packages/typespec-python/test/unbranded/generated/typetest-model-recursive/typetest/model/recursive/_utils/utils.py @@ -0,0 +1,18 @@ +from abc import ABC +from typing import Generic, TYPE_CHECKING, TypeVar + +if TYPE_CHECKING: + from .serialization import Deserializer, Serializer + + +TClient = TypeVar("TClient") +TConfig = TypeVar("TConfig") + + +class ClientMixinABC(ABC, Generic[TClient, TConfig]): + """DO NOT use this class. It is for internal typing use only.""" + + _client: TClient + _config: TConfig + _serialize: "Serializer" + _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/unbranded/generated/typetest-model-recursive/typetest/model/recursive/_vendor.py b/packages/typespec-python/test/unbranded/generated/typetest-model-recursive/typetest/model/recursive/_vendor.py deleted file mode 100644 index b70f671d458..00000000000 --- a/packages/typespec-python/test/unbranded/generated/typetest-model-recursive/typetest/model/recursive/_vendor.py +++ /dev/null @@ -1,18 +0,0 @@ -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import RecursiveClientConfiguration - -if TYPE_CHECKING: - from corehttp.runtime import PipelineClient - - from ._serialization import Deserializer, Serializer - - -class RecursiveClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "PipelineClient" - _config: RecursiveClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/unbranded/generated/typetest-model-recursive/typetest/model/recursive/aio/_client.py b/packages/typespec-python/test/unbranded/generated/typetest-model-recursive/typetest/model/recursive/aio/_client.py index 8d701293d64..efa331ea433 100644 --- a/packages/typespec-python/test/unbranded/generated/typetest-model-recursive/typetest/model/recursive/aio/_client.py +++ b/packages/typespec-python/test/unbranded/generated/typetest-model-recursive/typetest/model/recursive/aio/_client.py @@ -7,7 +7,7 @@ from corehttp.rest import AsyncHttpResponse, HttpRequest from corehttp.runtime import AsyncPipelineClient, policies -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import RecursiveClientConfiguration from ._operations import RecursiveClientOperationsMixin diff --git a/packages/typespec-python/test/unbranded/generated/typetest-model-recursive/typetest/model/recursive/aio/_operations/_operations.py b/packages/typespec-python/test/unbranded/generated/typetest-model-recursive/typetest/model/recursive/aio/_operations/_operations.py index e8ce82753ea..e1ff53eeec7 100644 --- a/packages/typespec-python/test/unbranded/generated/typetest-model-recursive/typetest/model/recursive/aio/_operations/_operations.py +++ b/packages/typespec-python/test/unbranded/generated/typetest-model-recursive/typetest/model/recursive/aio/_operations/_operations.py @@ -15,20 +15,22 @@ map_error, ) from corehttp.rest import AsyncHttpResponse, HttpRequest +from corehttp.runtime import AsyncPipelineClient from corehttp.runtime.pipeline import PipelineResponse from corehttp.utils import case_insensitive_dict from ... import models as _models -from ..._model_base import SdkJSONEncoder, _deserialize from ..._operations._operations import build_recursive_get_request, build_recursive_put_request -from .._vendor import RecursiveClientMixinABC +from ..._utils.model_base import SdkJSONEncoder, _deserialize +from ..._utils.utils import ClientMixinABC +from .._configuration import RecursiveClientConfiguration JSON = MutableMapping[str, Any] T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, AsyncHttpResponse], T, Dict[str, Any]], Any]] -class RecursiveClientOperationsMixin(RecursiveClientMixinABC): +class RecursiveClientOperationsMixin(ClientMixinABC[AsyncPipelineClient, RecursiveClientConfiguration]): @overload async def put(self, input: _models.Extension, *, content_type: str = "application/json", **kwargs: Any) -> None: diff --git a/packages/typespec-python/test/unbranded/generated/typetest-model-recursive/typetest/model/recursive/aio/_vendor.py b/packages/typespec-python/test/unbranded/generated/typetest-model-recursive/typetest/model/recursive/aio/_vendor.py deleted file mode 100644 index 52ec6a6e8ad..00000000000 --- a/packages/typespec-python/test/unbranded/generated/typetest-model-recursive/typetest/model/recursive/aio/_vendor.py +++ /dev/null @@ -1,18 +0,0 @@ -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import RecursiveClientConfiguration - -if TYPE_CHECKING: - from corehttp.runtime import AsyncPipelineClient - - from .._serialization import Deserializer, Serializer - - -class RecursiveClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "AsyncPipelineClient" - _config: RecursiveClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/unbranded/generated/typetest-model-recursive/typetest/model/recursive/models/_models.py b/packages/typespec-python/test/unbranded/generated/typetest-model-recursive/typetest/model/recursive/models/_models.py index a4c192e0bb3..1daf06af3f4 100644 --- a/packages/typespec-python/test/unbranded/generated/typetest-model-recursive/typetest/model/recursive/models/_models.py +++ b/packages/typespec-python/test/unbranded/generated/typetest-model-recursive/typetest/model/recursive/models/_models.py @@ -3,14 +3,13 @@ from typing import Any, List, Mapping, Optional, TYPE_CHECKING, overload -from .. import _model_base -from .._model_base import rest_field +from .._utils.model_base import Model as _Model, rest_field if TYPE_CHECKING: from .. import models as _models -class Element(_model_base.Model): +class Element(_Model): """element. :ivar extension: diff --git a/packages/typespec-python/test/unbranded/generated/typetest-model-singlediscriminator/typetest/model/singlediscriminator/_client.py b/packages/typespec-python/test/unbranded/generated/typetest-model-singlediscriminator/typetest/model/singlediscriminator/_client.py index 18cf23b0c5c..7bf0ef946db 100644 --- a/packages/typespec-python/test/unbranded/generated/typetest-model-singlediscriminator/typetest/model/singlediscriminator/_client.py +++ b/packages/typespec-python/test/unbranded/generated/typetest-model-singlediscriminator/typetest/model/singlediscriminator/_client.py @@ -9,7 +9,7 @@ from ._configuration import SingleDiscriminatorClientConfiguration from ._operations import SingleDiscriminatorClientOperationsMixin -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer class SingleDiscriminatorClient( diff --git a/packages/typespec-python/test/unbranded/generated/typetest-model-singlediscriminator/typetest/model/singlediscriminator/_operations/_operations.py b/packages/typespec-python/test/unbranded/generated/typetest-model-singlediscriminator/typetest/model/singlediscriminator/_operations/_operations.py index e90a1974d1f..71144fbe9e7 100644 --- a/packages/typespec-python/test/unbranded/generated/typetest-model-singlediscriminator/typetest/model/singlediscriminator/_operations/_operations.py +++ b/packages/typespec-python/test/unbranded/generated/typetest-model-singlediscriminator/typetest/model/singlediscriminator/_operations/_operations.py @@ -15,13 +15,15 @@ map_error, ) from corehttp.rest import HttpRequest, HttpResponse +from corehttp.runtime import PipelineClient from corehttp.runtime.pipeline import PipelineResponse from corehttp.utils import case_insensitive_dict from .. import models as _models -from .._model_base import SdkJSONEncoder, _deserialize -from .._serialization import Serializer -from .._vendor import SingleDiscriminatorClientMixinABC +from .._configuration import SingleDiscriminatorClientConfiguration +from .._utils.model_base import SdkJSONEncoder, _deserialize +from .._utils.serialization import Serializer +from .._utils.utils import ClientMixinABC JSON = MutableMapping[str, Any] T = TypeVar("T") @@ -137,7 +139,7 @@ def build_single_discriminator_get_legacy_model_request(**kwargs: Any) -> HttpRe return HttpRequest(method="GET", url=_url, headers=_headers, **kwargs) -class SingleDiscriminatorClientOperationsMixin(SingleDiscriminatorClientMixinABC): +class SingleDiscriminatorClientOperationsMixin(ClientMixinABC[PipelineClient, SingleDiscriminatorClientConfiguration]): def get_model(self, **kwargs: Any) -> _models.Bird: """get_model. diff --git a/packages/typespec-python/test/unbranded/generated/typetest-model-singlediscriminator/typetest/model/singlediscriminator/_utils/__init__.py b/packages/typespec-python/test/unbranded/generated/typetest-model-singlediscriminator/typetest/model/singlediscriminator/_utils/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/packages/typespec-python/test/unbranded/generated/typetest-model-singlediscriminator/typetest/model/singlediscriminator/_model_base.py b/packages/typespec-python/test/unbranded/generated/typetest-model-singlediscriminator/typetest/model/singlediscriminator/_utils/model_base.py similarity index 100% rename from packages/typespec-python/test/unbranded/generated/typetest-model-singlediscriminator/typetest/model/singlediscriminator/_model_base.py rename to packages/typespec-python/test/unbranded/generated/typetest-model-singlediscriminator/typetest/model/singlediscriminator/_utils/model_base.py diff --git a/packages/typespec-python/test/unbranded/generated/typetest-model-singlediscriminator/typetest/model/singlediscriminator/_serialization.py b/packages/typespec-python/test/unbranded/generated/typetest-model-singlediscriminator/typetest/model/singlediscriminator/_utils/serialization.py similarity index 100% rename from packages/typespec-python/test/unbranded/generated/typetest-model-singlediscriminator/typetest/model/singlediscriminator/_serialization.py rename to packages/typespec-python/test/unbranded/generated/typetest-model-singlediscriminator/typetest/model/singlediscriminator/_utils/serialization.py diff --git a/packages/typespec-python/test/unbranded/generated/typetest-model-singlediscriminator/typetest/model/singlediscriminator/_utils/utils.py b/packages/typespec-python/test/unbranded/generated/typetest-model-singlediscriminator/typetest/model/singlediscriminator/_utils/utils.py new file mode 100644 index 00000000000..02aa2f816ea --- /dev/null +++ b/packages/typespec-python/test/unbranded/generated/typetest-model-singlediscriminator/typetest/model/singlediscriminator/_utils/utils.py @@ -0,0 +1,18 @@ +from abc import ABC +from typing import Generic, TYPE_CHECKING, TypeVar + +if TYPE_CHECKING: + from .serialization import Deserializer, Serializer + + +TClient = TypeVar("TClient") +TConfig = TypeVar("TConfig") + + +class ClientMixinABC(ABC, Generic[TClient, TConfig]): + """DO NOT use this class. It is for internal typing use only.""" + + _client: TClient + _config: TConfig + _serialize: "Serializer" + _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/unbranded/generated/typetest-model-singlediscriminator/typetest/model/singlediscriminator/_vendor.py b/packages/typespec-python/test/unbranded/generated/typetest-model-singlediscriminator/typetest/model/singlediscriminator/_vendor.py deleted file mode 100644 index 11435c226b1..00000000000 --- a/packages/typespec-python/test/unbranded/generated/typetest-model-singlediscriminator/typetest/model/singlediscriminator/_vendor.py +++ /dev/null @@ -1,18 +0,0 @@ -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import SingleDiscriminatorClientConfiguration - -if TYPE_CHECKING: - from corehttp.runtime import PipelineClient - - from ._serialization import Deserializer, Serializer - - -class SingleDiscriminatorClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "PipelineClient" - _config: SingleDiscriminatorClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/unbranded/generated/typetest-model-singlediscriminator/typetest/model/singlediscriminator/aio/_client.py b/packages/typespec-python/test/unbranded/generated/typetest-model-singlediscriminator/typetest/model/singlediscriminator/aio/_client.py index 7d67b7082f6..e89230ee977 100644 --- a/packages/typespec-python/test/unbranded/generated/typetest-model-singlediscriminator/typetest/model/singlediscriminator/aio/_client.py +++ b/packages/typespec-python/test/unbranded/generated/typetest-model-singlediscriminator/typetest/model/singlediscriminator/aio/_client.py @@ -7,7 +7,7 @@ from corehttp.rest import AsyncHttpResponse, HttpRequest from corehttp.runtime import AsyncPipelineClient, policies -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import SingleDiscriminatorClientConfiguration from ._operations import SingleDiscriminatorClientOperationsMixin diff --git a/packages/typespec-python/test/unbranded/generated/typetest-model-singlediscriminator/typetest/model/singlediscriminator/aio/_operations/_operations.py b/packages/typespec-python/test/unbranded/generated/typetest-model-singlediscriminator/typetest/model/singlediscriminator/aio/_operations/_operations.py index 89c3010b43c..79bd0d625c7 100644 --- a/packages/typespec-python/test/unbranded/generated/typetest-model-singlediscriminator/typetest/model/singlediscriminator/aio/_operations/_operations.py +++ b/packages/typespec-python/test/unbranded/generated/typetest-model-singlediscriminator/typetest/model/singlediscriminator/aio/_operations/_operations.py @@ -15,11 +15,11 @@ map_error, ) from corehttp.rest import AsyncHttpResponse, HttpRequest +from corehttp.runtime import AsyncPipelineClient from corehttp.runtime.pipeline import PipelineResponse from corehttp.utils import case_insensitive_dict from ... import models as _models -from ..._model_base import SdkJSONEncoder, _deserialize from ..._operations._operations import ( build_single_discriminator_get_legacy_model_request, build_single_discriminator_get_missing_discriminator_request, @@ -29,14 +29,18 @@ build_single_discriminator_put_model_request, build_single_discriminator_put_recursive_model_request, ) -from .._vendor import SingleDiscriminatorClientMixinABC +from ..._utils.model_base import SdkJSONEncoder, _deserialize +from ..._utils.utils import ClientMixinABC +from .._configuration import SingleDiscriminatorClientConfiguration JSON = MutableMapping[str, Any] T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, AsyncHttpResponse], T, Dict[str, Any]], Any]] -class SingleDiscriminatorClientOperationsMixin(SingleDiscriminatorClientMixinABC): +class SingleDiscriminatorClientOperationsMixin( + ClientMixinABC[AsyncPipelineClient, SingleDiscriminatorClientConfiguration] +): async def get_model(self, **kwargs: Any) -> _models.Bird: """get_model. diff --git a/packages/typespec-python/test/unbranded/generated/typetest-model-singlediscriminator/typetest/model/singlediscriminator/aio/_vendor.py b/packages/typespec-python/test/unbranded/generated/typetest-model-singlediscriminator/typetest/model/singlediscriminator/aio/_vendor.py deleted file mode 100644 index ab35db0d0bb..00000000000 --- a/packages/typespec-python/test/unbranded/generated/typetest-model-singlediscriminator/typetest/model/singlediscriminator/aio/_vendor.py +++ /dev/null @@ -1,18 +0,0 @@ -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import SingleDiscriminatorClientConfiguration - -if TYPE_CHECKING: - from corehttp.runtime import AsyncPipelineClient - - from .._serialization import Deserializer, Serializer - - -class SingleDiscriminatorClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "AsyncPipelineClient" - _config: SingleDiscriminatorClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/unbranded/generated/typetest-model-singlediscriminator/typetest/model/singlediscriminator/models/_models.py b/packages/typespec-python/test/unbranded/generated/typetest-model-singlediscriminator/typetest/model/singlediscriminator/models/_models.py index 3abbcdbb093..e281838f283 100644 --- a/packages/typespec-python/test/unbranded/generated/typetest-model-singlediscriminator/typetest/model/singlediscriminator/models/_models.py +++ b/packages/typespec-python/test/unbranded/generated/typetest-model-singlediscriminator/typetest/model/singlediscriminator/models/_models.py @@ -4,14 +4,13 @@ from typing import Any, Dict, List, Literal, Mapping, Optional, TYPE_CHECKING, overload -from .. import _model_base -from .._model_base import rest_discriminator, rest_field +from .._utils.model_base import Model as _Model, rest_discriminator, rest_field if TYPE_CHECKING: from .. import models as _models -class Bird(_model_base.Model): +class Bird(_Model): """This is base model for polymorphic single level inheritance with a discriminator. You probably want to use the sub-classes and not this class directly. Known sub-classes are: @@ -23,7 +22,7 @@ class Bird(_model_base.Model): :vartype wingspan: int """ - __mapping__: Dict[str, _model_base.Model] = {} + __mapping__: Dict[str, _Model] = {} kind: str = rest_discriminator(name="kind", visibility=["read", "create", "update", "delete", "query"]) """Required. Default value is None.""" wingspan: int = rest_field(visibility=["read", "create", "update", "delete", "query"]) @@ -48,7 +47,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class Dinosaur(_model_base.Model): +class Dinosaur(_Model): """Define a base class in the legacy way. Discriminator property is not explicitly defined in the model. @@ -61,7 +60,7 @@ class Dinosaur(_model_base.Model): :vartype size: int """ - __mapping__: Dict[str, _model_base.Model] = {} + __mapping__: Dict[str, _Model] = {} kind: str = rest_discriminator(name="kind") """Discriminator property for Dinosaur. Required. Default value is None.""" size: int = rest_field(visibility=["read", "create", "update", "delete", "query"]) diff --git a/packages/typespec-python/test/unbranded/generated/typetest-model-usage/typetest/model/usage/_client.py b/packages/typespec-python/test/unbranded/generated/typetest-model-usage/typetest/model/usage/_client.py index 7a2af8f7932..6e3d4b5ea9f 100644 --- a/packages/typespec-python/test/unbranded/generated/typetest-model-usage/typetest/model/usage/_client.py +++ b/packages/typespec-python/test/unbranded/generated/typetest-model-usage/typetest/model/usage/_client.py @@ -9,7 +9,7 @@ from ._configuration import UsageClientConfiguration from ._operations import UsageClientOperationsMixin -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer class UsageClient(UsageClientOperationsMixin): # pylint: disable=client-accepts-api-version-keyword diff --git a/packages/typespec-python/test/unbranded/generated/typetest-model-usage/typetest/model/usage/_operations/_operations.py b/packages/typespec-python/test/unbranded/generated/typetest-model-usage/typetest/model/usage/_operations/_operations.py index 8974768ed6a..109fcfd9fe1 100644 --- a/packages/typespec-python/test/unbranded/generated/typetest-model-usage/typetest/model/usage/_operations/_operations.py +++ b/packages/typespec-python/test/unbranded/generated/typetest-model-usage/typetest/model/usage/_operations/_operations.py @@ -15,13 +15,15 @@ map_error, ) from corehttp.rest import HttpRequest, HttpResponse +from corehttp.runtime import PipelineClient from corehttp.runtime.pipeline import PipelineResponse from corehttp.utils import case_insensitive_dict from .. import models as _models -from .._model_base import SdkJSONEncoder, _deserialize -from .._serialization import Serializer -from .._vendor import UsageClientMixinABC +from .._configuration import UsageClientConfiguration +from .._utils.model_base import SdkJSONEncoder, _deserialize +from .._utils.serialization import Serializer +from .._utils.utils import ClientMixinABC JSON = MutableMapping[str, Any] T = TypeVar("T") @@ -76,7 +78,7 @@ def build_usage_input_and_output_request(**kwargs: Any) -> HttpRequest: return HttpRequest(method="POST", url=_url, headers=_headers, **kwargs) -class UsageClientOperationsMixin(UsageClientMixinABC): +class UsageClientOperationsMixin(ClientMixinABC[PipelineClient, UsageClientConfiguration]): @overload def input(self, input: _models.InputRecord, *, content_type: str = "application/json", **kwargs: Any) -> None: diff --git a/packages/typespec-python/test/unbranded/generated/typetest-model-usage/typetest/model/usage/_utils/__init__.py b/packages/typespec-python/test/unbranded/generated/typetest-model-usage/typetest/model/usage/_utils/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/packages/typespec-python/test/unbranded/generated/typetest-model-usage/typetest/model/usage/_model_base.py b/packages/typespec-python/test/unbranded/generated/typetest-model-usage/typetest/model/usage/_utils/model_base.py similarity index 100% rename from packages/typespec-python/test/unbranded/generated/typetest-model-usage/typetest/model/usage/_model_base.py rename to packages/typespec-python/test/unbranded/generated/typetest-model-usage/typetest/model/usage/_utils/model_base.py diff --git a/packages/typespec-python/test/unbranded/generated/typetest-model-usage/typetest/model/usage/_serialization.py b/packages/typespec-python/test/unbranded/generated/typetest-model-usage/typetest/model/usage/_utils/serialization.py similarity index 100% rename from packages/typespec-python/test/unbranded/generated/typetest-model-usage/typetest/model/usage/_serialization.py rename to packages/typespec-python/test/unbranded/generated/typetest-model-usage/typetest/model/usage/_utils/serialization.py diff --git a/packages/typespec-python/test/unbranded/generated/typetest-model-usage/typetest/model/usage/_utils/utils.py b/packages/typespec-python/test/unbranded/generated/typetest-model-usage/typetest/model/usage/_utils/utils.py new file mode 100644 index 00000000000..02aa2f816ea --- /dev/null +++ b/packages/typespec-python/test/unbranded/generated/typetest-model-usage/typetest/model/usage/_utils/utils.py @@ -0,0 +1,18 @@ +from abc import ABC +from typing import Generic, TYPE_CHECKING, TypeVar + +if TYPE_CHECKING: + from .serialization import Deserializer, Serializer + + +TClient = TypeVar("TClient") +TConfig = TypeVar("TConfig") + + +class ClientMixinABC(ABC, Generic[TClient, TConfig]): + """DO NOT use this class. It is for internal typing use only.""" + + _client: TClient + _config: TConfig + _serialize: "Serializer" + _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/unbranded/generated/typetest-model-usage/typetest/model/usage/_vendor.py b/packages/typespec-python/test/unbranded/generated/typetest-model-usage/typetest/model/usage/_vendor.py deleted file mode 100644 index 787cf976ada..00000000000 --- a/packages/typespec-python/test/unbranded/generated/typetest-model-usage/typetest/model/usage/_vendor.py +++ /dev/null @@ -1,18 +0,0 @@ -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import UsageClientConfiguration - -if TYPE_CHECKING: - from corehttp.runtime import PipelineClient - - from ._serialization import Deserializer, Serializer - - -class UsageClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "PipelineClient" - _config: UsageClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/unbranded/generated/typetest-model-usage/typetest/model/usage/aio/_client.py b/packages/typespec-python/test/unbranded/generated/typetest-model-usage/typetest/model/usage/aio/_client.py index 68594cb9ac1..c9523a5c3e2 100644 --- a/packages/typespec-python/test/unbranded/generated/typetest-model-usage/typetest/model/usage/aio/_client.py +++ b/packages/typespec-python/test/unbranded/generated/typetest-model-usage/typetest/model/usage/aio/_client.py @@ -7,7 +7,7 @@ from corehttp.rest import AsyncHttpResponse, HttpRequest from corehttp.runtime import AsyncPipelineClient, policies -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import UsageClientConfiguration from ._operations import UsageClientOperationsMixin diff --git a/packages/typespec-python/test/unbranded/generated/typetest-model-usage/typetest/model/usage/aio/_operations/_operations.py b/packages/typespec-python/test/unbranded/generated/typetest-model-usage/typetest/model/usage/aio/_operations/_operations.py index 2d56fd9260e..e5fb6cdb961 100644 --- a/packages/typespec-python/test/unbranded/generated/typetest-model-usage/typetest/model/usage/aio/_operations/_operations.py +++ b/packages/typespec-python/test/unbranded/generated/typetest-model-usage/typetest/model/usage/aio/_operations/_operations.py @@ -15,24 +15,26 @@ map_error, ) from corehttp.rest import AsyncHttpResponse, HttpRequest +from corehttp.runtime import AsyncPipelineClient from corehttp.runtime.pipeline import PipelineResponse from corehttp.utils import case_insensitive_dict from ... import models as _models -from ..._model_base import SdkJSONEncoder, _deserialize from ..._operations._operations import ( build_usage_input_and_output_request, build_usage_input_request, build_usage_output_request, ) -from .._vendor import UsageClientMixinABC +from ..._utils.model_base import SdkJSONEncoder, _deserialize +from ..._utils.utils import ClientMixinABC +from .._configuration import UsageClientConfiguration JSON = MutableMapping[str, Any] T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, AsyncHttpResponse], T, Dict[str, Any]], Any]] -class UsageClientOperationsMixin(UsageClientMixinABC): +class UsageClientOperationsMixin(ClientMixinABC[AsyncPipelineClient, UsageClientConfiguration]): @overload async def input(self, input: _models.InputRecord, *, content_type: str = "application/json", **kwargs: Any) -> None: diff --git a/packages/typespec-python/test/unbranded/generated/typetest-model-usage/typetest/model/usage/aio/_vendor.py b/packages/typespec-python/test/unbranded/generated/typetest-model-usage/typetest/model/usage/aio/_vendor.py deleted file mode 100644 index 3330e55f580..00000000000 --- a/packages/typespec-python/test/unbranded/generated/typetest-model-usage/typetest/model/usage/aio/_vendor.py +++ /dev/null @@ -1,18 +0,0 @@ -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import UsageClientConfiguration - -if TYPE_CHECKING: - from corehttp.runtime import AsyncPipelineClient - - from .._serialization import Deserializer, Serializer - - -class UsageClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "AsyncPipelineClient" - _config: UsageClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/unbranded/generated/typetest-model-usage/typetest/model/usage/models/_models.py b/packages/typespec-python/test/unbranded/generated/typetest-model-usage/typetest/model/usage/models/_models.py index 8eada1c6668..f4d65176bb5 100644 --- a/packages/typespec-python/test/unbranded/generated/typetest-model-usage/typetest/model/usage/models/_models.py +++ b/packages/typespec-python/test/unbranded/generated/typetest-model-usage/typetest/model/usage/models/_models.py @@ -3,11 +3,10 @@ from typing import Any, Mapping, overload -from .. import _model_base -from .._model_base import rest_field +from .._utils.model_base import Model as _Model, rest_field -class InputOutputRecord(_model_base.Model): +class InputOutputRecord(_Model): """Record used both as operation parameter and return type. :ivar required_prop: Required. @@ -35,7 +34,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class InputRecord(_model_base.Model): +class InputRecord(_Model): """Record used in operation parameters. :ivar required_prop: Required. @@ -63,7 +62,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class OutputRecord(_model_base.Model): +class OutputRecord(_Model): """Record used in operation return type. :ivar required_prop: Required. diff --git a/packages/typespec-python/test/unbranded/generated/typetest-model-visibility/typetest/model/visibility/_client.py b/packages/typespec-python/test/unbranded/generated/typetest-model-visibility/typetest/model/visibility/_client.py index 5af8c176484..2eb2697b7a0 100644 --- a/packages/typespec-python/test/unbranded/generated/typetest-model-visibility/typetest/model/visibility/_client.py +++ b/packages/typespec-python/test/unbranded/generated/typetest-model-visibility/typetest/model/visibility/_client.py @@ -9,7 +9,7 @@ from ._configuration import VisibilityClientConfiguration from ._operations import VisibilityClientOperationsMixin -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer class VisibilityClient(VisibilityClientOperationsMixin): # pylint: disable=client-accepts-api-version-keyword diff --git a/packages/typespec-python/test/unbranded/generated/typetest-model-visibility/typetest/model/visibility/_operations/_operations.py b/packages/typespec-python/test/unbranded/generated/typetest-model-visibility/typetest/model/visibility/_operations/_operations.py index 429c2b5780a..49fb2469e7a 100644 --- a/packages/typespec-python/test/unbranded/generated/typetest-model-visibility/typetest/model/visibility/_operations/_operations.py +++ b/packages/typespec-python/test/unbranded/generated/typetest-model-visibility/typetest/model/visibility/_operations/_operations.py @@ -15,13 +15,15 @@ map_error, ) from corehttp.rest import HttpRequest, HttpResponse +from corehttp.runtime import PipelineClient from corehttp.runtime.pipeline import PipelineResponse from corehttp.utils import case_insensitive_dict from .. import models as _models -from .._model_base import SdkJSONEncoder, _deserialize -from .._serialization import Serializer -from .._vendor import VisibilityClientMixinABC +from .._configuration import VisibilityClientConfiguration +from .._utils.model_base import SdkJSONEncoder, _deserialize +from .._utils.serialization import Serializer +from .._utils.utils import ClientMixinABC JSON = MutableMapping[str, Any] T = TypeVar("T") @@ -143,7 +145,7 @@ def build_visibility_put_read_only_model_request(**kwargs: Any) -> HttpRequest: return HttpRequest(method="PUT", url=_url, headers=_headers, **kwargs) -class VisibilityClientOperationsMixin(VisibilityClientMixinABC): +class VisibilityClientOperationsMixin(ClientMixinABC[PipelineClient, VisibilityClientConfiguration]): @overload def get_model( diff --git a/packages/typespec-python/test/unbranded/generated/typetest-model-visibility/typetest/model/visibility/_utils/__init__.py b/packages/typespec-python/test/unbranded/generated/typetest-model-visibility/typetest/model/visibility/_utils/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/packages/typespec-python/test/unbranded/generated/typetest-model-visibility/typetest/model/visibility/_model_base.py b/packages/typespec-python/test/unbranded/generated/typetest-model-visibility/typetest/model/visibility/_utils/model_base.py similarity index 100% rename from packages/typespec-python/test/unbranded/generated/typetest-model-visibility/typetest/model/visibility/_model_base.py rename to packages/typespec-python/test/unbranded/generated/typetest-model-visibility/typetest/model/visibility/_utils/model_base.py diff --git a/packages/typespec-python/test/unbranded/generated/typetest-model-visibility/typetest/model/visibility/_serialization.py b/packages/typespec-python/test/unbranded/generated/typetest-model-visibility/typetest/model/visibility/_utils/serialization.py similarity index 100% rename from packages/typespec-python/test/unbranded/generated/typetest-model-visibility/typetest/model/visibility/_serialization.py rename to packages/typespec-python/test/unbranded/generated/typetest-model-visibility/typetest/model/visibility/_utils/serialization.py diff --git a/packages/typespec-python/test/unbranded/generated/typetest-model-visibility/typetest/model/visibility/_utils/utils.py b/packages/typespec-python/test/unbranded/generated/typetest-model-visibility/typetest/model/visibility/_utils/utils.py new file mode 100644 index 00000000000..02aa2f816ea --- /dev/null +++ b/packages/typespec-python/test/unbranded/generated/typetest-model-visibility/typetest/model/visibility/_utils/utils.py @@ -0,0 +1,18 @@ +from abc import ABC +from typing import Generic, TYPE_CHECKING, TypeVar + +if TYPE_CHECKING: + from .serialization import Deserializer, Serializer + + +TClient = TypeVar("TClient") +TConfig = TypeVar("TConfig") + + +class ClientMixinABC(ABC, Generic[TClient, TConfig]): + """DO NOT use this class. It is for internal typing use only.""" + + _client: TClient + _config: TConfig + _serialize: "Serializer" + _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/unbranded/generated/typetest-model-visibility/typetest/model/visibility/_vendor.py b/packages/typespec-python/test/unbranded/generated/typetest-model-visibility/typetest/model/visibility/_vendor.py deleted file mode 100644 index 68cde436eed..00000000000 --- a/packages/typespec-python/test/unbranded/generated/typetest-model-visibility/typetest/model/visibility/_vendor.py +++ /dev/null @@ -1,18 +0,0 @@ -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import VisibilityClientConfiguration - -if TYPE_CHECKING: - from corehttp.runtime import PipelineClient - - from ._serialization import Deserializer, Serializer - - -class VisibilityClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "PipelineClient" - _config: VisibilityClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/unbranded/generated/typetest-model-visibility/typetest/model/visibility/aio/_client.py b/packages/typespec-python/test/unbranded/generated/typetest-model-visibility/typetest/model/visibility/aio/_client.py index e551c484690..231c07fd58f 100644 --- a/packages/typespec-python/test/unbranded/generated/typetest-model-visibility/typetest/model/visibility/aio/_client.py +++ b/packages/typespec-python/test/unbranded/generated/typetest-model-visibility/typetest/model/visibility/aio/_client.py @@ -7,7 +7,7 @@ from corehttp.rest import AsyncHttpResponse, HttpRequest from corehttp.runtime import AsyncPipelineClient, policies -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import VisibilityClientConfiguration from ._operations import VisibilityClientOperationsMixin diff --git a/packages/typespec-python/test/unbranded/generated/typetest-model-visibility/typetest/model/visibility/aio/_operations/_operations.py b/packages/typespec-python/test/unbranded/generated/typetest-model-visibility/typetest/model/visibility/aio/_operations/_operations.py index ae3f6d633e9..f17f8289a18 100644 --- a/packages/typespec-python/test/unbranded/generated/typetest-model-visibility/typetest/model/visibility/aio/_operations/_operations.py +++ b/packages/typespec-python/test/unbranded/generated/typetest-model-visibility/typetest/model/visibility/aio/_operations/_operations.py @@ -15,11 +15,11 @@ map_error, ) from corehttp.rest import AsyncHttpResponse, HttpRequest +from corehttp.runtime import AsyncPipelineClient from corehttp.runtime.pipeline import PipelineResponse from corehttp.utils import case_insensitive_dict from ... import models as _models -from ..._model_base import SdkJSONEncoder, _deserialize from ..._operations._operations import ( build_visibility_delete_model_request, build_visibility_get_model_request, @@ -29,14 +29,16 @@ build_visibility_put_model_request, build_visibility_put_read_only_model_request, ) -from .._vendor import VisibilityClientMixinABC +from ..._utils.model_base import SdkJSONEncoder, _deserialize +from ..._utils.utils import ClientMixinABC +from .._configuration import VisibilityClientConfiguration JSON = MutableMapping[str, Any] T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, AsyncHttpResponse], T, Dict[str, Any]], Any]] -class VisibilityClientOperationsMixin(VisibilityClientMixinABC): +class VisibilityClientOperationsMixin(ClientMixinABC[AsyncPipelineClient, VisibilityClientConfiguration]): @overload async def get_model( diff --git a/packages/typespec-python/test/unbranded/generated/typetest-model-visibility/typetest/model/visibility/aio/_vendor.py b/packages/typespec-python/test/unbranded/generated/typetest-model-visibility/typetest/model/visibility/aio/_vendor.py deleted file mode 100644 index 408dc6b99ca..00000000000 --- a/packages/typespec-python/test/unbranded/generated/typetest-model-visibility/typetest/model/visibility/aio/_vendor.py +++ /dev/null @@ -1,18 +0,0 @@ -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import VisibilityClientConfiguration - -if TYPE_CHECKING: - from corehttp.runtime import AsyncPipelineClient - - from .._serialization import Deserializer, Serializer - - -class VisibilityClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "AsyncPipelineClient" - _config: VisibilityClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/unbranded/generated/typetest-model-visibility/typetest/model/visibility/models/_models.py b/packages/typespec-python/test/unbranded/generated/typetest-model-visibility/typetest/model/visibility/models/_models.py index a302369b8a6..8afead9dc15 100644 --- a/packages/typespec-python/test/unbranded/generated/typetest-model-visibility/typetest/model/visibility/models/_models.py +++ b/packages/typespec-python/test/unbranded/generated/typetest-model-visibility/typetest/model/visibility/models/_models.py @@ -3,11 +3,10 @@ from typing import Any, Dict, List, Mapping, Optional, overload -from .. import _model_base -from .._model_base import rest_field +from .._utils.model_base import Model as _Model, rest_field -class ReadOnlyModel(_model_base.Model): +class ReadOnlyModel(_Model): """RoundTrip model with readonly optional properties. :ivar optional_nullable_int_list: Optional readonly nullable int list. @@ -22,7 +21,7 @@ class ReadOnlyModel(_model_base.Model): """Optional readonly string dictionary.""" -class VisibilityModel(_model_base.Model): +class VisibilityModel(_Model): """Output model with visibility properties. :ivar read_prop: Required string, illustrating a readonly property. Required. diff --git a/packages/typespec-python/test/unbranded/generated/typetest-property-additionalproperties/typetest/property/additionalproperties/_client.py b/packages/typespec-python/test/unbranded/generated/typetest-property-additionalproperties/typetest/property/additionalproperties/_client.py index 76479695e81..3c9588ace34 100644 --- a/packages/typespec-python/test/unbranded/generated/typetest-property-additionalproperties/typetest/property/additionalproperties/_client.py +++ b/packages/typespec-python/test/unbranded/generated/typetest-property-additionalproperties/typetest/property/additionalproperties/_client.py @@ -8,7 +8,7 @@ from corehttp.runtime import PipelineClient, policies from ._configuration import AdditionalPropertiesClientConfiguration -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer from .operations import ( ExtendsDifferentSpreadFloatOperations, ExtendsDifferentSpreadModelArrayOperations, diff --git a/packages/typespec-python/test/unbranded/generated/typetest-property-additionalproperties/typetest/property/additionalproperties/_utils/__init__.py b/packages/typespec-python/test/unbranded/generated/typetest-property-additionalproperties/typetest/property/additionalproperties/_utils/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/packages/typespec-python/test/unbranded/generated/typetest-property-additionalproperties/typetest/property/additionalproperties/_model_base.py b/packages/typespec-python/test/unbranded/generated/typetest-property-additionalproperties/typetest/property/additionalproperties/_utils/model_base.py similarity index 100% rename from packages/typespec-python/test/unbranded/generated/typetest-property-additionalproperties/typetest/property/additionalproperties/_model_base.py rename to packages/typespec-python/test/unbranded/generated/typetest-property-additionalproperties/typetest/property/additionalproperties/_utils/model_base.py diff --git a/packages/typespec-python/test/unbranded/generated/typetest-property-additionalproperties/typetest/property/additionalproperties/_serialization.py b/packages/typespec-python/test/unbranded/generated/typetest-property-additionalproperties/typetest/property/additionalproperties/_utils/serialization.py similarity index 100% rename from packages/typespec-python/test/unbranded/generated/typetest-property-additionalproperties/typetest/property/additionalproperties/_serialization.py rename to packages/typespec-python/test/unbranded/generated/typetest-property-additionalproperties/typetest/property/additionalproperties/_utils/serialization.py diff --git a/packages/typespec-python/test/unbranded/generated/typetest-property-additionalproperties/typetest/property/additionalproperties/aio/_client.py b/packages/typespec-python/test/unbranded/generated/typetest-property-additionalproperties/typetest/property/additionalproperties/aio/_client.py index ebf8d1ccb21..944cc1e8314 100644 --- a/packages/typespec-python/test/unbranded/generated/typetest-property-additionalproperties/typetest/property/additionalproperties/aio/_client.py +++ b/packages/typespec-python/test/unbranded/generated/typetest-property-additionalproperties/typetest/property/additionalproperties/aio/_client.py @@ -7,7 +7,7 @@ from corehttp.rest import AsyncHttpResponse, HttpRequest from corehttp.runtime import AsyncPipelineClient, policies -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import AdditionalPropertiesClientConfiguration from .operations import ( ExtendsDifferentSpreadFloatOperations, diff --git a/packages/typespec-python/test/unbranded/generated/typetest-property-additionalproperties/typetest/property/additionalproperties/aio/operations/_operations.py b/packages/typespec-python/test/unbranded/generated/typetest-property-additionalproperties/typetest/property/additionalproperties/aio/operations/_operations.py index 9c2281d9191..4829e149883 100644 --- a/packages/typespec-python/test/unbranded/generated/typetest-property-additionalproperties/typetest/property/additionalproperties/aio/operations/_operations.py +++ b/packages/typespec-python/test/unbranded/generated/typetest-property-additionalproperties/typetest/property/additionalproperties/aio/operations/_operations.py @@ -21,8 +21,8 @@ from corehttp.utils import case_insensitive_dict from ... import models as _models -from ..._model_base import SdkJSONEncoder, _deserialize -from ..._serialization import Deserializer, Serializer +from ..._utils.model_base import SdkJSONEncoder, _deserialize +from ..._utils.serialization import Deserializer, Serializer from ...operations._operations import ( build_extends_different_spread_float_get_request, build_extends_different_spread_float_put_request, diff --git a/packages/typespec-python/test/unbranded/generated/typetest-property-additionalproperties/typetest/property/additionalproperties/models/_models.py b/packages/typespec-python/test/unbranded/generated/typetest-property-additionalproperties/typetest/property/additionalproperties/models/_models.py index 77eb632ed8b..c5373cd8831 100644 --- a/packages/typespec-python/test/unbranded/generated/typetest-property-additionalproperties/typetest/property/additionalproperties/models/_models.py +++ b/packages/typespec-python/test/unbranded/generated/typetest-property-additionalproperties/typetest/property/additionalproperties/models/_models.py @@ -5,14 +5,13 @@ import datetime from typing import Any, Dict, List, Literal, Mapping, Optional, TYPE_CHECKING, overload -from .. import _model_base -from .._model_base import rest_discriminator, rest_field +from .._utils.model_base import Model as _Model, rest_discriminator, rest_field if TYPE_CHECKING: from .. import models as _models -class DifferentSpreadFloatRecord(_model_base.Model): +class DifferentSpreadFloatRecord(_Model): """The model spread Record with the different known property type. :ivar name: The id property. Required. @@ -72,7 +71,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class DifferentSpreadModelArrayRecord(_model_base.Model): +class DifferentSpreadModelArrayRecord(_Model): """The model spread Record with the different known property type. :ivar known_prop: Required. @@ -134,7 +133,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class DifferentSpreadModelRecord(_model_base.Model): +class DifferentSpreadModelRecord(_Model): """The model spread Record with the different known property type. :ivar known_prop: Required. @@ -196,7 +195,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class DifferentSpreadStringRecord(_model_base.Model): +class DifferentSpreadStringRecord(_Model): """The model spread Record with the different known property type. :ivar id: The name property. Required. @@ -256,7 +255,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class ExtendsFloatAdditionalProperties(_model_base.Model): +class ExtendsFloatAdditionalProperties(_Model): """The model extends from Record type. :ivar id: The id property. Required. @@ -284,7 +283,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class ExtendsModelAdditionalProperties(_model_base.Model): +class ExtendsModelAdditionalProperties(_Model): """The model extends from Record type. :ivar known_prop: Required. @@ -314,7 +313,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class ExtendsModelArrayAdditionalProperties(_model_base.Model): +class ExtendsModelArrayAdditionalProperties(_Model): """The model extends from Record type. :ivar known_prop: Required. @@ -344,7 +343,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class ExtendsStringAdditionalProperties(_model_base.Model): +class ExtendsStringAdditionalProperties(_Model): """The model extends from Record type. :ivar name: The name property. Required. @@ -372,7 +371,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class ExtendsUnknownAdditionalProperties(_model_base.Model): +class ExtendsUnknownAdditionalProperties(_Model): """The model extends from Record type. :ivar name: The name property. Required. @@ -436,7 +435,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class ExtendsUnknownAdditionalPropertiesDiscriminated(_model_base.Model): # pylint: disable=name-too-long +class ExtendsUnknownAdditionalPropertiesDiscriminated(_Model): # pylint: disable=name-too-long """The model extends from Record with a discriminator. You probably want to use the sub-classes and not this class directly. Known sub-classes are: @@ -448,7 +447,7 @@ class ExtendsUnknownAdditionalPropertiesDiscriminated(_model_base.Model): # pyl :vartype kind: str """ - __mapping__: Dict[str, _model_base.Model] = {} + __mapping__: Dict[str, _Model] = {} name: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) """The name property. Required.""" kind: str = rest_discriminator(name="kind", visibility=["read", "create", "update", "delete", "query"]) @@ -515,7 +514,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, kind="derived", **kwargs) -class IsFloatAdditionalProperties(_model_base.Model): +class IsFloatAdditionalProperties(_Model): """The model is from Record type. :ivar id: The id property. Required. @@ -543,7 +542,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class IsModelAdditionalProperties(_model_base.Model): +class IsModelAdditionalProperties(_Model): """The model is from Record type. :ivar known_prop: Required. @@ -573,7 +572,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class IsModelArrayAdditionalProperties(_model_base.Model): +class IsModelArrayAdditionalProperties(_Model): """The model is from Record type. :ivar known_prop: Required. @@ -603,7 +602,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class IsStringAdditionalProperties(_model_base.Model): +class IsStringAdditionalProperties(_Model): """The model is from Record type. :ivar name: The name property. Required. @@ -631,7 +630,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class IsUnknownAdditionalProperties(_model_base.Model): +class IsUnknownAdditionalProperties(_Model): """The model is from Record type. :ivar name: The name property. Required. @@ -695,7 +694,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class IsUnknownAdditionalPropertiesDiscriminated(_model_base.Model): # pylint: disable=name-too-long +class IsUnknownAdditionalPropertiesDiscriminated(_Model): # pylint: disable=name-too-long """The model is Record with a discriminator. You probably want to use the sub-classes and not this class directly. Known sub-classes are: @@ -707,7 +706,7 @@ class IsUnknownAdditionalPropertiesDiscriminated(_model_base.Model): # pylint: :vartype kind: str """ - __mapping__: Dict[str, _model_base.Model] = {} + __mapping__: Dict[str, _Model] = {} name: str = rest_field(visibility=["read", "create", "update", "delete", "query"]) """The name property. Required.""" kind: str = rest_discriminator(name="kind", visibility=["read", "create", "update", "delete", "query"]) @@ -774,7 +773,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, kind="derived", **kwargs) -class ModelForRecord(_model_base.Model): +class ModelForRecord(_Model): """model for record. :ivar state: The state property. Required. @@ -802,7 +801,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class MultipleSpreadRecord(_model_base.Model): +class MultipleSpreadRecord(_Model): """The model spread Record and Record. :ivar flag: The name property. Required. @@ -830,7 +829,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class SpreadFloatRecord(_model_base.Model): +class SpreadFloatRecord(_Model): """The model spread Record with the same known property type. :ivar id: The id property. Required. @@ -858,7 +857,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class SpreadModelArrayRecord(_model_base.Model): +class SpreadModelArrayRecord(_Model): """SpreadModelArrayRecord. :ivar known_prop: Required. @@ -888,7 +887,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class SpreadModelRecord(_model_base.Model): +class SpreadModelRecord(_Model): """The model spread Record with the same known property type. :ivar known_prop: Required. @@ -918,7 +917,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class SpreadRecordForNonDiscriminatedUnion(_model_base.Model): +class SpreadRecordForNonDiscriminatedUnion(_Model): """The model spread Record. :ivar name: The name property. Required. @@ -946,7 +945,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class SpreadRecordForNonDiscriminatedUnion2(_model_base.Model): +class SpreadRecordForNonDiscriminatedUnion2(_Model): """The model spread Record. :ivar name: The name property. Required. @@ -974,7 +973,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class SpreadRecordForNonDiscriminatedUnion3(_model_base.Model): +class SpreadRecordForNonDiscriminatedUnion3(_Model): """The model spread Record. :ivar name: The name property. Required. @@ -1002,7 +1001,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class SpreadRecordForUnion(_model_base.Model): +class SpreadRecordForUnion(_Model): """The model spread Record. :ivar flag: The name property. Required. @@ -1030,7 +1029,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class SpreadStringRecord(_model_base.Model): +class SpreadStringRecord(_Model): """The model spread Record with the same known property type. :ivar name: The name property. Required. @@ -1058,7 +1057,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class WidgetData0(_model_base.Model): +class WidgetData0(_Model): """WidgetData0. :ivar kind: Required. Default value is "kind0". @@ -1091,7 +1090,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: self.kind: Literal["kind0"] = "kind0" -class WidgetData1(_model_base.Model): +class WidgetData1(_Model): """WidgetData1. :ivar kind: Required. Default value is "kind1". @@ -1130,7 +1129,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: self.kind: Literal["kind1"] = "kind1" -class WidgetData2(_model_base.Model): +class WidgetData2(_Model): """WidgetData2. :ivar kind: Required. Default value is "kind1". diff --git a/packages/typespec-python/test/unbranded/generated/typetest-property-additionalproperties/typetest/property/additionalproperties/operations/_operations.py b/packages/typespec-python/test/unbranded/generated/typetest-property-additionalproperties/typetest/property/additionalproperties/operations/_operations.py index 36f0ce17e1e..3d44792db92 100644 --- a/packages/typespec-python/test/unbranded/generated/typetest-property-additionalproperties/typetest/property/additionalproperties/operations/_operations.py +++ b/packages/typespec-python/test/unbranded/generated/typetest-property-additionalproperties/typetest/property/additionalproperties/operations/_operations.py @@ -22,8 +22,8 @@ from .. import models as _models from .._configuration import AdditionalPropertiesClientConfiguration -from .._model_base import SdkJSONEncoder, _deserialize -from .._serialization import Deserializer, Serializer +from .._utils.model_base import SdkJSONEncoder, _deserialize +from .._utils.serialization import Deserializer, Serializer JSON = MutableMapping[str, Any] T = TypeVar("T") diff --git a/packages/typespec-python/test/unbranded/generated/typetest-property-nullable/typetest/property/nullable/_client.py b/packages/typespec-python/test/unbranded/generated/typetest-property-nullable/typetest/property/nullable/_client.py index 6c27526d7e6..8e6bd430676 100644 --- a/packages/typespec-python/test/unbranded/generated/typetest-property-nullable/typetest/property/nullable/_client.py +++ b/packages/typespec-python/test/unbranded/generated/typetest-property-nullable/typetest/property/nullable/_client.py @@ -8,7 +8,7 @@ from corehttp.runtime import PipelineClient, policies from ._configuration import NullableClientConfiguration -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer from .operations import ( BytesOperations, CollectionsByteOperations, diff --git a/packages/typespec-python/test/unbranded/generated/typetest-property-nullable/typetest/property/nullable/_utils/__init__.py b/packages/typespec-python/test/unbranded/generated/typetest-property-nullable/typetest/property/nullable/_utils/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/packages/typespec-python/test/unbranded/generated/typetest-property-nullable/typetest/property/nullable/_model_base.py b/packages/typespec-python/test/unbranded/generated/typetest-property-nullable/typetest/property/nullable/_utils/model_base.py similarity index 100% rename from packages/typespec-python/test/unbranded/generated/typetest-property-nullable/typetest/property/nullable/_model_base.py rename to packages/typespec-python/test/unbranded/generated/typetest-property-nullable/typetest/property/nullable/_utils/model_base.py diff --git a/packages/typespec-python/test/unbranded/generated/typetest-property-nullable/typetest/property/nullable/_serialization.py b/packages/typespec-python/test/unbranded/generated/typetest-property-nullable/typetest/property/nullable/_utils/serialization.py similarity index 100% rename from packages/typespec-python/test/unbranded/generated/typetest-property-nullable/typetest/property/nullable/_serialization.py rename to packages/typespec-python/test/unbranded/generated/typetest-property-nullable/typetest/property/nullable/_utils/serialization.py diff --git a/packages/typespec-python/test/unbranded/generated/typetest-property-nullable/typetest/property/nullable/aio/_client.py b/packages/typespec-python/test/unbranded/generated/typetest-property-nullable/typetest/property/nullable/aio/_client.py index c8f5a31c84d..541493385a2 100644 --- a/packages/typespec-python/test/unbranded/generated/typetest-property-nullable/typetest/property/nullable/aio/_client.py +++ b/packages/typespec-python/test/unbranded/generated/typetest-property-nullable/typetest/property/nullable/aio/_client.py @@ -7,7 +7,7 @@ from corehttp.rest import AsyncHttpResponse, HttpRequest from corehttp.runtime import AsyncPipelineClient, policies -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import NullableClientConfiguration from .operations import ( BytesOperations, diff --git a/packages/typespec-python/test/unbranded/generated/typetest-property-nullable/typetest/property/nullable/aio/operations/_operations.py b/packages/typespec-python/test/unbranded/generated/typetest-property-nullable/typetest/property/nullable/aio/operations/_operations.py index 774cb0e1b0f..3e9c08fbca1 100644 --- a/packages/typespec-python/test/unbranded/generated/typetest-property-nullable/typetest/property/nullable/aio/operations/_operations.py +++ b/packages/typespec-python/test/unbranded/generated/typetest-property-nullable/typetest/property/nullable/aio/operations/_operations.py @@ -21,8 +21,8 @@ from corehttp.utils import case_insensitive_dict from ... import models as _models -from ..._model_base import SdkJSONEncoder, _deserialize -from ..._serialization import Deserializer, Serializer +from ..._utils.model_base import SdkJSONEncoder, _deserialize +from ..._utils.serialization import Deserializer, Serializer from ...operations._operations import ( build_bytes_get_non_null_request, build_bytes_get_null_request, diff --git a/packages/typespec-python/test/unbranded/generated/typetest-property-nullable/typetest/property/nullable/models/_models.py b/packages/typespec-python/test/unbranded/generated/typetest-property-nullable/typetest/property/nullable/models/_models.py index a4c92a0627e..7796a05b6ce 100644 --- a/packages/typespec-python/test/unbranded/generated/typetest-property-nullable/typetest/property/nullable/models/_models.py +++ b/packages/typespec-python/test/unbranded/generated/typetest-property-nullable/typetest/property/nullable/models/_models.py @@ -4,14 +4,13 @@ import datetime from typing import Any, List, Mapping, TYPE_CHECKING, overload -from .. import _model_base -from .._model_base import rest_field +from .._utils.model_base import Model as _Model, rest_field if TYPE_CHECKING: from .. import models as _models -class BytesProperty(_model_base.Model): +class BytesProperty(_Model): """Template type for testing models with nullable property. Pass in the type of the property you are looking for. @@ -49,7 +48,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class CollectionsByteProperty(_model_base.Model): +class CollectionsByteProperty(_Model): """Model with collection bytes properties. :ivar required_property: Required property. Required. @@ -86,7 +85,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class CollectionsModelProperty(_model_base.Model): +class CollectionsModelProperty(_Model): """Model with collection models properties. :ivar required_property: Required property. Required. @@ -123,7 +122,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class CollectionsStringProperty(_model_base.Model): +class CollectionsStringProperty(_Model): """Model with collection string properties. :ivar required_property: Required property. Required. @@ -160,7 +159,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class DatetimeProperty(_model_base.Model): +class DatetimeProperty(_Model): """Model with a datetime property. :ivar required_property: Required property. Required. @@ -197,7 +196,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class DurationProperty(_model_base.Model): +class DurationProperty(_Model): """Model with a duration property. :ivar required_property: Required property. Required. @@ -234,7 +233,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class InnerModel(_model_base.Model): +class InnerModel(_Model): """Inner model used in collections model property. :ivar property: Inner model property. Required. @@ -262,7 +261,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class StringProperty(_model_base.Model): +class StringProperty(_Model): """Template type for testing models with nullable property. Pass in the type of the property you are looking for. diff --git a/packages/typespec-python/test/unbranded/generated/typetest-property-nullable/typetest/property/nullable/operations/_operations.py b/packages/typespec-python/test/unbranded/generated/typetest-property-nullable/typetest/property/nullable/operations/_operations.py index dbe98d598b4..25b0d487d9a 100644 --- a/packages/typespec-python/test/unbranded/generated/typetest-property-nullable/typetest/property/nullable/operations/_operations.py +++ b/packages/typespec-python/test/unbranded/generated/typetest-property-nullable/typetest/property/nullable/operations/_operations.py @@ -22,8 +22,8 @@ from .. import models as _models from .._configuration import NullableClientConfiguration -from .._model_base import SdkJSONEncoder, _deserialize -from .._serialization import Deserializer, Serializer +from .._utils.model_base import SdkJSONEncoder, _deserialize +from .._utils.serialization import Deserializer, Serializer JSON = MutableMapping[str, Any] T = TypeVar("T") diff --git a/packages/typespec-python/test/unbranded/generated/typetest-property-optional/typetest/property/optional/_client.py b/packages/typespec-python/test/unbranded/generated/typetest-property-optional/typetest/property/optional/_client.py index d8924371967..82b4163b386 100644 --- a/packages/typespec-python/test/unbranded/generated/typetest-property-optional/typetest/property/optional/_client.py +++ b/packages/typespec-python/test/unbranded/generated/typetest-property-optional/typetest/property/optional/_client.py @@ -8,7 +8,7 @@ from corehttp.runtime import PipelineClient, policies from ._configuration import OptionalClientConfiguration -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer from .operations import ( BooleanLiteralOperations, BytesOperations, diff --git a/packages/typespec-python/test/unbranded/generated/typetest-property-optional/typetest/property/optional/_utils/__init__.py b/packages/typespec-python/test/unbranded/generated/typetest-property-optional/typetest/property/optional/_utils/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/packages/typespec-python/test/unbranded/generated/typetest-property-optional/typetest/property/optional/_model_base.py b/packages/typespec-python/test/unbranded/generated/typetest-property-optional/typetest/property/optional/_utils/model_base.py similarity index 100% rename from packages/typespec-python/test/unbranded/generated/typetest-property-optional/typetest/property/optional/_model_base.py rename to packages/typespec-python/test/unbranded/generated/typetest-property-optional/typetest/property/optional/_utils/model_base.py diff --git a/packages/typespec-python/test/unbranded/generated/typetest-property-optional/typetest/property/optional/_serialization.py b/packages/typespec-python/test/unbranded/generated/typetest-property-optional/typetest/property/optional/_utils/serialization.py similarity index 100% rename from packages/typespec-python/test/unbranded/generated/typetest-property-optional/typetest/property/optional/_serialization.py rename to packages/typespec-python/test/unbranded/generated/typetest-property-optional/typetest/property/optional/_utils/serialization.py diff --git a/packages/typespec-python/test/unbranded/generated/typetest-property-optional/typetest/property/optional/aio/_client.py b/packages/typespec-python/test/unbranded/generated/typetest-property-optional/typetest/property/optional/aio/_client.py index 393a30e5e8c..39870a4ba8e 100644 --- a/packages/typespec-python/test/unbranded/generated/typetest-property-optional/typetest/property/optional/aio/_client.py +++ b/packages/typespec-python/test/unbranded/generated/typetest-property-optional/typetest/property/optional/aio/_client.py @@ -7,7 +7,7 @@ from corehttp.rest import AsyncHttpResponse, HttpRequest from corehttp.runtime import AsyncPipelineClient, policies -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import OptionalClientConfiguration from .operations import ( BooleanLiteralOperations, diff --git a/packages/typespec-python/test/unbranded/generated/typetest-property-optional/typetest/property/optional/aio/operations/_operations.py b/packages/typespec-python/test/unbranded/generated/typetest-property-optional/typetest/property/optional/aio/operations/_operations.py index 9aa01f2befe..4e77d94917a 100644 --- a/packages/typespec-python/test/unbranded/generated/typetest-property-optional/typetest/property/optional/aio/operations/_operations.py +++ b/packages/typespec-python/test/unbranded/generated/typetest-property-optional/typetest/property/optional/aio/operations/_operations.py @@ -21,8 +21,8 @@ from corehttp.utils import case_insensitive_dict from ... import models as _models -from ..._model_base import SdkJSONEncoder, _deserialize -from ..._serialization import Deserializer, Serializer +from ..._utils.model_base import SdkJSONEncoder, _deserialize +from ..._utils.serialization import Deserializer, Serializer from ...operations._operations import ( build_boolean_literal_get_all_request, build_boolean_literal_get_default_request, diff --git a/packages/typespec-python/test/unbranded/generated/typetest-property-optional/typetest/property/optional/models/_models.py b/packages/typespec-python/test/unbranded/generated/typetest-property-optional/typetest/property/optional/models/_models.py index 0cc9c3838d2..9f2c151a20d 100644 --- a/packages/typespec-python/test/unbranded/generated/typetest-property-optional/typetest/property/optional/models/_models.py +++ b/packages/typespec-python/test/unbranded/generated/typetest-property-optional/typetest/property/optional/models/_models.py @@ -4,14 +4,13 @@ import datetime from typing import Any, List, Literal, Mapping, Optional, TYPE_CHECKING, overload -from .. import _model_base -from .._model_base import rest_field +from .._utils.model_base import Model as _Model, rest_field if TYPE_CHECKING: from .. import models as _models -class BooleanLiteralProperty(_model_base.Model): +class BooleanLiteralProperty(_Model): """Model with boolean literal property. :ivar property: Property. Default value is True. @@ -39,7 +38,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class BytesProperty(_model_base.Model): +class BytesProperty(_Model): """Template type for testing models with optional property. Pass in the type of the property you are looking for. @@ -68,7 +67,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class CollectionsByteProperty(_model_base.Model): +class CollectionsByteProperty(_Model): """Model with collection bytes properties. :ivar property: Property. @@ -98,7 +97,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class CollectionsModelProperty(_model_base.Model): +class CollectionsModelProperty(_Model): """Model with collection models properties. :ivar property: Property. @@ -128,7 +127,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class DatetimeProperty(_model_base.Model): +class DatetimeProperty(_Model): """Model with a datetime property. :ivar property: Property. @@ -158,7 +157,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class DurationProperty(_model_base.Model): +class DurationProperty(_Model): """Model with a duration property. :ivar property: Property. @@ -186,7 +185,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class FloatLiteralProperty(_model_base.Model): +class FloatLiteralProperty(_Model): """Model with float literal property. :ivar property: Property. Default value is 1.25. @@ -214,7 +213,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class IntLiteralProperty(_model_base.Model): +class IntLiteralProperty(_Model): """Model with int literal property. :ivar property: Property. Default value is 1. @@ -242,7 +241,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class PlainDateProperty(_model_base.Model): +class PlainDateProperty(_Model): """Model with a plainDate property. :ivar property: Property. @@ -270,7 +269,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class PlainTimeProperty(_model_base.Model): +class PlainTimeProperty(_Model): """Model with a plainTime property. :ivar property: Property. @@ -298,7 +297,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class RequiredAndOptionalProperty(_model_base.Model): +class RequiredAndOptionalProperty(_Model): """Model with required and optional properties. :ivar optional_property: optional string property. @@ -335,7 +334,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class StringLiteralProperty(_model_base.Model): +class StringLiteralProperty(_Model): """Model with string literal property. :ivar property: Property. Default value is "hello". @@ -363,7 +362,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class StringProperty(_model_base.Model): +class StringProperty(_Model): """Template type for testing models with optional property. Pass in the type of the property you are looking for. @@ -392,7 +391,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class UnionFloatLiteralProperty(_model_base.Model): +class UnionFloatLiteralProperty(_Model): """Model with union of float literal property. :ivar property: Property. Is one of the following types: float @@ -420,7 +419,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class UnionIntLiteralProperty(_model_base.Model): +class UnionIntLiteralProperty(_Model): """Model with union of int literal property. :ivar property: Property. Is either a Literal[1] type or a Literal[2] type. @@ -448,7 +447,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class UnionStringLiteralProperty(_model_base.Model): +class UnionStringLiteralProperty(_Model): """Model with union of string literal property. :ivar property: Property. Is either a Literal["hello"] type or a Literal["world"] type. diff --git a/packages/typespec-python/test/unbranded/generated/typetest-property-optional/typetest/property/optional/operations/_operations.py b/packages/typespec-python/test/unbranded/generated/typetest-property-optional/typetest/property/optional/operations/_operations.py index 9b3c5a027c4..a7a1e385588 100644 --- a/packages/typespec-python/test/unbranded/generated/typetest-property-optional/typetest/property/optional/operations/_operations.py +++ b/packages/typespec-python/test/unbranded/generated/typetest-property-optional/typetest/property/optional/operations/_operations.py @@ -22,8 +22,8 @@ from .. import models as _models from .._configuration import OptionalClientConfiguration -from .._model_base import SdkJSONEncoder, _deserialize -from .._serialization import Deserializer, Serializer +from .._utils.model_base import SdkJSONEncoder, _deserialize +from .._utils.serialization import Deserializer, Serializer JSON = MutableMapping[str, Any] T = TypeVar("T") diff --git a/packages/typespec-python/test/unbranded/generated/typetest-property-valuetypes/typetest/property/valuetypes/_client.py b/packages/typespec-python/test/unbranded/generated/typetest-property-valuetypes/typetest/property/valuetypes/_client.py index 542c0f33870..920e91040cd 100644 --- a/packages/typespec-python/test/unbranded/generated/typetest-property-valuetypes/typetest/property/valuetypes/_client.py +++ b/packages/typespec-python/test/unbranded/generated/typetest-property-valuetypes/typetest/property/valuetypes/_client.py @@ -8,7 +8,7 @@ from corehttp.runtime import PipelineClient, policies from ._configuration import ValueTypesClientConfiguration -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer from .operations import ( BooleanLiteralOperations, BooleanOperations, diff --git a/packages/typespec-python/test/unbranded/generated/typetest-property-valuetypes/typetest/property/valuetypes/_utils/__init__.py b/packages/typespec-python/test/unbranded/generated/typetest-property-valuetypes/typetest/property/valuetypes/_utils/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/packages/typespec-python/test/unbranded/generated/typetest-property-valuetypes/typetest/property/valuetypes/_model_base.py b/packages/typespec-python/test/unbranded/generated/typetest-property-valuetypes/typetest/property/valuetypes/_utils/model_base.py similarity index 100% rename from packages/typespec-python/test/unbranded/generated/typetest-property-valuetypes/typetest/property/valuetypes/_model_base.py rename to packages/typespec-python/test/unbranded/generated/typetest-property-valuetypes/typetest/property/valuetypes/_utils/model_base.py diff --git a/packages/typespec-python/test/unbranded/generated/typetest-property-valuetypes/typetest/property/valuetypes/_serialization.py b/packages/typespec-python/test/unbranded/generated/typetest-property-valuetypes/typetest/property/valuetypes/_utils/serialization.py similarity index 100% rename from packages/typespec-python/test/unbranded/generated/typetest-property-valuetypes/typetest/property/valuetypes/_serialization.py rename to packages/typespec-python/test/unbranded/generated/typetest-property-valuetypes/typetest/property/valuetypes/_utils/serialization.py diff --git a/packages/typespec-python/test/unbranded/generated/typetest-property-valuetypes/typetest/property/valuetypes/aio/_client.py b/packages/typespec-python/test/unbranded/generated/typetest-property-valuetypes/typetest/property/valuetypes/aio/_client.py index b473461be64..529c61c49ac 100644 --- a/packages/typespec-python/test/unbranded/generated/typetest-property-valuetypes/typetest/property/valuetypes/aio/_client.py +++ b/packages/typespec-python/test/unbranded/generated/typetest-property-valuetypes/typetest/property/valuetypes/aio/_client.py @@ -7,7 +7,7 @@ from corehttp.rest import AsyncHttpResponse, HttpRequest from corehttp.runtime import AsyncPipelineClient, policies -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import ValueTypesClientConfiguration from .operations import ( BooleanLiteralOperations, diff --git a/packages/typespec-python/test/unbranded/generated/typetest-property-valuetypes/typetest/property/valuetypes/aio/operations/_operations.py b/packages/typespec-python/test/unbranded/generated/typetest-property-valuetypes/typetest/property/valuetypes/aio/operations/_operations.py index e2903533cda..361fc30ee1b 100644 --- a/packages/typespec-python/test/unbranded/generated/typetest-property-valuetypes/typetest/property/valuetypes/aio/operations/_operations.py +++ b/packages/typespec-python/test/unbranded/generated/typetest-property-valuetypes/typetest/property/valuetypes/aio/operations/_operations.py @@ -21,8 +21,8 @@ from corehttp.utils import case_insensitive_dict from ... import models as _models -from ..._model_base import SdkJSONEncoder, _deserialize -from ..._serialization import Deserializer, Serializer +from ..._utils.model_base import SdkJSONEncoder, _deserialize +from ..._utils.serialization import Deserializer, Serializer from ...operations._operations import ( build_boolean_get_request, build_boolean_literal_get_request, diff --git a/packages/typespec-python/test/unbranded/generated/typetest-property-valuetypes/typetest/property/valuetypes/models/_models.py b/packages/typespec-python/test/unbranded/generated/typetest-property-valuetypes/typetest/property/valuetypes/models/_models.py index 3d7cfc2bfba..b635c35cdac 100644 --- a/packages/typespec-python/test/unbranded/generated/typetest-property-valuetypes/typetest/property/valuetypes/models/_models.py +++ b/packages/typespec-python/test/unbranded/generated/typetest-property-valuetypes/typetest/property/valuetypes/models/_models.py @@ -5,15 +5,14 @@ import decimal from typing import Any, Dict, List, Literal, Mapping, TYPE_CHECKING, Union, overload -from .. import _model_base -from .._model_base import rest_field +from .._utils.model_base import Model as _Model, rest_field from ._enums import ExtendedEnum if TYPE_CHECKING: from .. import models as _models -class BooleanLiteralProperty(_model_base.Model): +class BooleanLiteralProperty(_Model): """Model with a boolean literal property. :ivar property: Property. Required. Default value is True. @@ -28,7 +27,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: self.property: Literal[True] = True -class BooleanProperty(_model_base.Model): +class BooleanProperty(_Model): """Model with a boolean property. :ivar property: Property. Required. @@ -56,7 +55,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class BytesProperty(_model_base.Model): +class BytesProperty(_Model): """Model with a bytes property. :ivar property: Property. Required. @@ -84,7 +83,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class CollectionsIntProperty(_model_base.Model): +class CollectionsIntProperty(_Model): """Model with collection int properties. :ivar property: Property. Required. @@ -112,7 +111,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class CollectionsModelProperty(_model_base.Model): +class CollectionsModelProperty(_Model): """Model with collection model properties. :ivar property: Property. Required. @@ -140,7 +139,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class CollectionsStringProperty(_model_base.Model): +class CollectionsStringProperty(_Model): """Model with collection string properties. :ivar property: Property. Required. @@ -168,7 +167,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class DatetimeProperty(_model_base.Model): +class DatetimeProperty(_Model): """Model with a datetime property. :ivar property: Property. Required. @@ -198,7 +197,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class Decimal128Property(_model_base.Model): +class Decimal128Property(_Model): """Model with a decimal128 property. :ivar property: Property. Required. @@ -226,7 +225,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class DecimalProperty(_model_base.Model): +class DecimalProperty(_Model): """Model with a decimal property. :ivar property: Property. Required. @@ -254,7 +253,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class DictionaryStringProperty(_model_base.Model): +class DictionaryStringProperty(_Model): """Model with dictionary string properties. :ivar property: Property. Required. @@ -282,7 +281,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class DurationProperty(_model_base.Model): +class DurationProperty(_Model): """Model with a duration property. :ivar property: Property. Required. @@ -310,7 +309,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class EnumProperty(_model_base.Model): +class EnumProperty(_Model): """Model with enum properties. :ivar property: Property. Required. Known values are: "ValueOne" and "ValueTwo". @@ -340,7 +339,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class ExtensibleEnumProperty(_model_base.Model): +class ExtensibleEnumProperty(_Model): """Model with extensible enum properties. :ivar property: Property. Required. Known values are: "ValueOne" and "ValueTwo". @@ -368,7 +367,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class FloatLiteralProperty(_model_base.Model): +class FloatLiteralProperty(_Model): """Model with a float literal property. :ivar property: Property. Required. Default value is 43.125. @@ -383,7 +382,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: self.property: float = 43.125 -class FloatProperty(_model_base.Model): +class FloatProperty(_Model): """Model with a float property. :ivar property: Property. Required. @@ -411,7 +410,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class InnerModel(_model_base.Model): +class InnerModel(_Model): """Inner model. Will be a property type for ModelWithModelProperties. :ivar property: Required string property. Required. @@ -439,7 +438,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class IntLiteralProperty(_model_base.Model): +class IntLiteralProperty(_Model): """Model with a int literal property. :ivar property: Property. Required. Default value is 42. @@ -454,7 +453,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: self.property: Literal[42] = 42 -class IntProperty(_model_base.Model): +class IntProperty(_Model): """Model with a int property. :ivar property: Property. Required. @@ -482,7 +481,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class ModelProperty(_model_base.Model): +class ModelProperty(_Model): """Model with model properties. :ivar property: Property. Required. @@ -510,11 +509,11 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class NeverProperty(_model_base.Model): +class NeverProperty(_Model): """Model with a property never. (This property should not be included).""" -class StringLiteralProperty(_model_base.Model): +class StringLiteralProperty(_Model): """Model with a string literal property. :ivar property: Property. Required. Default value is "hello". @@ -529,7 +528,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: self.property: Literal["hello"] = "hello" -class StringProperty(_model_base.Model): +class StringProperty(_Model): """Model with a string property. :ivar property: Property. Required. @@ -557,7 +556,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class UnionEnumValueProperty(_model_base.Model): +class UnionEnumValueProperty(_Model): """Template type for testing models with specific properties. Pass in the type of the property you are looking for. @@ -586,7 +585,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class UnionFloatLiteralProperty(_model_base.Model): +class UnionFloatLiteralProperty(_Model): """Model with a union of float literal as property. :ivar property: Property. Required. Is one of the following types: float @@ -614,7 +613,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class UnionIntLiteralProperty(_model_base.Model): +class UnionIntLiteralProperty(_Model): """Model with a union of int literal as property. :ivar property: Property. Required. Is either a Literal[42] type or a Literal[43] type. @@ -642,7 +641,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class UnionStringLiteralProperty(_model_base.Model): +class UnionStringLiteralProperty(_Model): """Model with a union of string literal as property. :ivar property: Property. Required. Is either a Literal["hello"] type or a Literal["world"] @@ -671,7 +670,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class UnknownArrayProperty(_model_base.Model): +class UnknownArrayProperty(_Model): """Model with a property unknown, and the data is an array. :ivar property: Property. Required. @@ -699,7 +698,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class UnknownDictProperty(_model_base.Model): +class UnknownDictProperty(_Model): """Model with a property unknown, and the data is a dictionnary. :ivar property: Property. Required. @@ -727,7 +726,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class UnknownIntProperty(_model_base.Model): +class UnknownIntProperty(_Model): """Model with a property unknown, and the data is a int32. :ivar property: Property. Required. @@ -755,7 +754,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class UnknownStringProperty(_model_base.Model): +class UnknownStringProperty(_Model): """Model with a property unknown, and the data is a string. :ivar property: Property. Required. diff --git a/packages/typespec-python/test/unbranded/generated/typetest-property-valuetypes/typetest/property/valuetypes/operations/_operations.py b/packages/typespec-python/test/unbranded/generated/typetest-property-valuetypes/typetest/property/valuetypes/operations/_operations.py index 3bed40d58cd..5774dd4b908 100644 --- a/packages/typespec-python/test/unbranded/generated/typetest-property-valuetypes/typetest/property/valuetypes/operations/_operations.py +++ b/packages/typespec-python/test/unbranded/generated/typetest-property-valuetypes/typetest/property/valuetypes/operations/_operations.py @@ -22,8 +22,8 @@ from .. import models as _models from .._configuration import ValueTypesClientConfiguration -from .._model_base import SdkJSONEncoder, _deserialize -from .._serialization import Deserializer, Serializer +from .._utils.model_base import SdkJSONEncoder, _deserialize +from .._utils.serialization import Deserializer, Serializer JSON = MutableMapping[str, Any] T = TypeVar("T") diff --git a/packages/typespec-python/test/unbranded/generated/typetest-scalar/typetest/scalar/_client.py b/packages/typespec-python/test/unbranded/generated/typetest-scalar/typetest/scalar/_client.py index 04d3ad1a346..5fb6ec4709d 100644 --- a/packages/typespec-python/test/unbranded/generated/typetest-scalar/typetest/scalar/_client.py +++ b/packages/typespec-python/test/unbranded/generated/typetest-scalar/typetest/scalar/_client.py @@ -8,7 +8,7 @@ from corehttp.runtime import PipelineClient, policies from ._configuration import ScalarClientConfiguration -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer from .operations import ( BooleanOperations, Decimal128TypeOperations, diff --git a/packages/typespec-python/test/unbranded/generated/typetest-scalar/typetest/scalar/_utils/__init__.py b/packages/typespec-python/test/unbranded/generated/typetest-scalar/typetest/scalar/_utils/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/packages/typespec-python/test/unbranded/generated/typetest-scalar/typetest/scalar/_model_base.py b/packages/typespec-python/test/unbranded/generated/typetest-scalar/typetest/scalar/_utils/model_base.py similarity index 100% rename from packages/typespec-python/test/unbranded/generated/typetest-scalar/typetest/scalar/_model_base.py rename to packages/typespec-python/test/unbranded/generated/typetest-scalar/typetest/scalar/_utils/model_base.py diff --git a/packages/typespec-python/test/unbranded/generated/typetest-scalar/typetest/scalar/_serialization.py b/packages/typespec-python/test/unbranded/generated/typetest-scalar/typetest/scalar/_utils/serialization.py similarity index 100% rename from packages/typespec-python/test/unbranded/generated/typetest-scalar/typetest/scalar/_serialization.py rename to packages/typespec-python/test/unbranded/generated/typetest-scalar/typetest/scalar/_utils/serialization.py diff --git a/packages/typespec-python/test/unbranded/generated/typetest-scalar/typetest/scalar/aio/_client.py b/packages/typespec-python/test/unbranded/generated/typetest-scalar/typetest/scalar/aio/_client.py index 91fce39fe6c..1d795579c18 100644 --- a/packages/typespec-python/test/unbranded/generated/typetest-scalar/typetest/scalar/aio/_client.py +++ b/packages/typespec-python/test/unbranded/generated/typetest-scalar/typetest/scalar/aio/_client.py @@ -7,7 +7,7 @@ from corehttp.rest import AsyncHttpResponse, HttpRequest from corehttp.runtime import AsyncPipelineClient, policies -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import ScalarClientConfiguration from .operations import ( BooleanOperations, diff --git a/packages/typespec-python/test/unbranded/generated/typetest-scalar/typetest/scalar/aio/operations/_operations.py b/packages/typespec-python/test/unbranded/generated/typetest-scalar/typetest/scalar/aio/operations/_operations.py index e585d00dfb2..676c50e638b 100644 --- a/packages/typespec-python/test/unbranded/generated/typetest-scalar/typetest/scalar/aio/operations/_operations.py +++ b/packages/typespec-python/test/unbranded/generated/typetest-scalar/typetest/scalar/aio/operations/_operations.py @@ -19,8 +19,8 @@ from corehttp.runtime.pipeline import PipelineResponse from corehttp.utils import case_insensitive_dict -from ..._model_base import SdkJSONEncoder, _deserialize -from ..._serialization import Deserializer, Serializer +from ..._utils.model_base import SdkJSONEncoder, _deserialize +from ..._utils.serialization import Deserializer, Serializer from ...operations._operations import ( build_boolean_get_request, build_boolean_put_request, diff --git a/packages/typespec-python/test/unbranded/generated/typetest-scalar/typetest/scalar/operations/_operations.py b/packages/typespec-python/test/unbranded/generated/typetest-scalar/typetest/scalar/operations/_operations.py index f44dba1d77c..e92b5138028 100644 --- a/packages/typespec-python/test/unbranded/generated/typetest-scalar/typetest/scalar/operations/_operations.py +++ b/packages/typespec-python/test/unbranded/generated/typetest-scalar/typetest/scalar/operations/_operations.py @@ -21,8 +21,8 @@ from corehttp.utils import case_insensitive_dict from .._configuration import ScalarClientConfiguration -from .._model_base import SdkJSONEncoder, _deserialize -from .._serialization import Deserializer, Serializer +from .._utils.model_base import SdkJSONEncoder, _deserialize +from .._utils.serialization import Deserializer, Serializer T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] diff --git a/packages/typespec-python/test/unbranded/generated/typetest-union/typetest/union/_client.py b/packages/typespec-python/test/unbranded/generated/typetest-union/typetest/union/_client.py index 72e37871413..433896cf638 100644 --- a/packages/typespec-python/test/unbranded/generated/typetest-union/typetest/union/_client.py +++ b/packages/typespec-python/test/unbranded/generated/typetest-union/typetest/union/_client.py @@ -8,7 +8,7 @@ from corehttp.runtime import PipelineClient, policies from ._configuration import UnionClientConfiguration -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer from .operations import ( EnumsOnlyOperations, FloatsOnlyOperations, diff --git a/packages/typespec-python/test/unbranded/generated/typetest-union/typetest/union/_utils/__init__.py b/packages/typespec-python/test/unbranded/generated/typetest-union/typetest/union/_utils/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/packages/typespec-python/test/unbranded/generated/typetest-union/typetest/union/_model_base.py b/packages/typespec-python/test/unbranded/generated/typetest-union/typetest/union/_utils/model_base.py similarity index 100% rename from packages/typespec-python/test/unbranded/generated/typetest-union/typetest/union/_model_base.py rename to packages/typespec-python/test/unbranded/generated/typetest-union/typetest/union/_utils/model_base.py diff --git a/packages/typespec-python/test/unbranded/generated/typetest-union/typetest/union/_serialization.py b/packages/typespec-python/test/unbranded/generated/typetest-union/typetest/union/_utils/serialization.py similarity index 100% rename from packages/typespec-python/test/unbranded/generated/typetest-union/typetest/union/_serialization.py rename to packages/typespec-python/test/unbranded/generated/typetest-union/typetest/union/_utils/serialization.py diff --git a/packages/typespec-python/test/unbranded/generated/typetest-union/typetest/union/aio/_client.py b/packages/typespec-python/test/unbranded/generated/typetest-union/typetest/union/aio/_client.py index dc9c41d3d5d..c99bcdd1490 100644 --- a/packages/typespec-python/test/unbranded/generated/typetest-union/typetest/union/aio/_client.py +++ b/packages/typespec-python/test/unbranded/generated/typetest-union/typetest/union/aio/_client.py @@ -7,7 +7,7 @@ from corehttp.rest import AsyncHttpResponse, HttpRequest from corehttp.runtime import AsyncPipelineClient, policies -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import UnionClientConfiguration from .operations import ( EnumsOnlyOperations, diff --git a/packages/typespec-python/test/unbranded/generated/typetest-union/typetest/union/aio/operations/_operations.py b/packages/typespec-python/test/unbranded/generated/typetest-union/typetest/union/aio/operations/_operations.py index 4befd3a1ed6..12e6ed402f2 100644 --- a/packages/typespec-python/test/unbranded/generated/typetest-union/typetest/union/aio/operations/_operations.py +++ b/packages/typespec-python/test/unbranded/generated/typetest-union/typetest/union/aio/operations/_operations.py @@ -21,8 +21,8 @@ from corehttp.utils import case_insensitive_dict from ... import models as _models -from ..._model_base import SdkJSONEncoder, _deserialize -from ..._serialization import Deserializer, Serializer +from ..._utils.model_base import SdkJSONEncoder, _deserialize +from ..._utils.serialization import Deserializer, Serializer from ...operations._operations import ( build_enums_only_get_request, build_enums_only_send_request, diff --git a/packages/typespec-python/test/unbranded/generated/typetest-union/typetest/union/models/_models.py b/packages/typespec-python/test/unbranded/generated/typetest-union/typetest/union/models/_models.py index 8a5b2e4ac34..7cd83218e08 100644 --- a/packages/typespec-python/test/unbranded/generated/typetest-union/typetest/union/models/_models.py +++ b/packages/typespec-python/test/unbranded/generated/typetest-union/typetest/union/models/_models.py @@ -3,14 +3,13 @@ from typing import Any, List, Literal, Mapping, TYPE_CHECKING, Union, overload -from .. import _model_base -from .._model_base import rest_field +from .._utils.model_base import Model as _Model, rest_field if TYPE_CHECKING: from .. import models as _models -class Cat(_model_base.Model): +class Cat(_Model): """Cat. :ivar name: Required. @@ -38,7 +37,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class Dog(_model_base.Model): +class Dog(_Model): """Dog. :ivar bark: Required. @@ -66,7 +65,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class EnumsOnlyCases(_model_base.Model): +class EnumsOnlyCases(_Model): """EnumsOnlyCases. :ivar lr: This should be receive/send the left variant. Required. Is one of the following @@ -103,7 +102,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class GetResponse(_model_base.Model): +class GetResponse(_Model): """GetResponse. :ivar prop: Required. Is one of the following types: Literal["a"], Literal["b"], Literal["c"] @@ -131,7 +130,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class GetResponse1(_model_base.Model): +class GetResponse1(_Model): """GetResponse1. :ivar prop: Required. Is one of the following types: Literal["b"], Literal["c"], str @@ -161,7 +160,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class GetResponse2(_model_base.Model): +class GetResponse2(_Model): """GetResponse2. :ivar prop: Required. Known values are: "b" and "c". @@ -191,7 +190,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class GetResponse3(_model_base.Model): +class GetResponse3(_Model): """GetResponse3. :ivar prop: Required. Is one of the following types: Literal[1], Literal[2], Literal[3] @@ -219,7 +218,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class GetResponse4(_model_base.Model): +class GetResponse4(_Model): """GetResponse4. :ivar prop: Required. Is one of the following types: float @@ -247,7 +246,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class GetResponse5(_model_base.Model): +class GetResponse5(_Model): """GetResponse5. :ivar prop: Required. Is either a Cat type or a Dog type. @@ -275,7 +274,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class GetResponse6(_model_base.Model): +class GetResponse6(_Model): """GetResponse6. :ivar prop: Required. @@ -303,7 +302,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class GetResponse7(_model_base.Model): +class GetResponse7(_Model): """GetResponse7. :ivar prop: Required. @@ -331,7 +330,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class GetResponse8(_model_base.Model): +class GetResponse8(_Model): """GetResponse8. :ivar prop: Required. @@ -359,7 +358,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class GetResponse9(_model_base.Model): +class GetResponse9(_Model): """GetResponse9. :ivar prop: Required. @@ -387,7 +386,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class MixedLiteralsCases(_model_base.Model): +class MixedLiteralsCases(_Model): """MixedLiteralsCases. :ivar string_literal: This should be receive/send the "a" variant. Required. Is one of the @@ -446,7 +445,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class MixedTypesCases(_model_base.Model): +class MixedTypesCases(_Model): """MixedTypesCases. :ivar model: This should be receive/send the Cat variant. Required. Is one of the following @@ -512,7 +511,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class StringAndArrayCases(_model_base.Model): +class StringAndArrayCases(_Model): """StringAndArrayCases. :ivar string: This should be receive/send the string variant. Required. Is either a str type or diff --git a/packages/typespec-python/test/unbranded/generated/typetest-union/typetest/union/operations/_operations.py b/packages/typespec-python/test/unbranded/generated/typetest-union/typetest/union/operations/_operations.py index e2a137d4a10..4ce3ef07114 100644 --- a/packages/typespec-python/test/unbranded/generated/typetest-union/typetest/union/operations/_operations.py +++ b/packages/typespec-python/test/unbranded/generated/typetest-union/typetest/union/operations/_operations.py @@ -22,8 +22,8 @@ from .. import models as _models from .._configuration import UnionClientConfiguration -from .._model_base import SdkJSONEncoder, _deserialize -from .._serialization import Deserializer, Serializer +from .._utils.model_base import SdkJSONEncoder, _deserialize +from .._utils.serialization import Deserializer, Serializer JSON = MutableMapping[str, Any] _Unset: Any = object() diff --git a/packages/typespec-python/test/unbranded/generated/versioning-added/versioning/added/_client.py b/packages/typespec-python/test/unbranded/generated/versioning-added/versioning/added/_client.py index 3835fe69c72..6c96ecd6985 100644 --- a/packages/typespec-python/test/unbranded/generated/versioning-added/versioning/added/_client.py +++ b/packages/typespec-python/test/unbranded/generated/versioning-added/versioning/added/_client.py @@ -9,7 +9,7 @@ from . import models as _models from ._configuration import AddedClientConfiguration -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer from .operations import AddedClientOperationsMixin, InterfaceV2Operations diff --git a/packages/typespec-python/test/unbranded/generated/versioning-added/versioning/added/_utils/__init__.py b/packages/typespec-python/test/unbranded/generated/versioning-added/versioning/added/_utils/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/packages/typespec-python/test/unbranded/generated/versioning-added/versioning/added/_model_base.py b/packages/typespec-python/test/unbranded/generated/versioning-added/versioning/added/_utils/model_base.py similarity index 100% rename from packages/typespec-python/test/unbranded/generated/versioning-added/versioning/added/_model_base.py rename to packages/typespec-python/test/unbranded/generated/versioning-added/versioning/added/_utils/model_base.py diff --git a/packages/typespec-python/test/unbranded/generated/versioning-added/versioning/added/_serialization.py b/packages/typespec-python/test/unbranded/generated/versioning-added/versioning/added/_utils/serialization.py similarity index 100% rename from packages/typespec-python/test/unbranded/generated/versioning-added/versioning/added/_serialization.py rename to packages/typespec-python/test/unbranded/generated/versioning-added/versioning/added/_utils/serialization.py diff --git a/packages/typespec-python/test/unbranded/generated/versioning-added/versioning/added/_utils/utils.py b/packages/typespec-python/test/unbranded/generated/versioning-added/versioning/added/_utils/utils.py new file mode 100644 index 00000000000..02aa2f816ea --- /dev/null +++ b/packages/typespec-python/test/unbranded/generated/versioning-added/versioning/added/_utils/utils.py @@ -0,0 +1,18 @@ +from abc import ABC +from typing import Generic, TYPE_CHECKING, TypeVar + +if TYPE_CHECKING: + from .serialization import Deserializer, Serializer + + +TClient = TypeVar("TClient") +TConfig = TypeVar("TConfig") + + +class ClientMixinABC(ABC, Generic[TClient, TConfig]): + """DO NOT use this class. It is for internal typing use only.""" + + _client: TClient + _config: TConfig + _serialize: "Serializer" + _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/unbranded/generated/versioning-added/versioning/added/_vendor.py b/packages/typespec-python/test/unbranded/generated/versioning-added/versioning/added/_vendor.py deleted file mode 100644 index 7c134045620..00000000000 --- a/packages/typespec-python/test/unbranded/generated/versioning-added/versioning/added/_vendor.py +++ /dev/null @@ -1,18 +0,0 @@ -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import AddedClientConfiguration - -if TYPE_CHECKING: - from corehttp.runtime import PipelineClient - - from ._serialization import Deserializer, Serializer - - -class AddedClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "PipelineClient" - _config: AddedClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/unbranded/generated/versioning-added/versioning/added/aio/_client.py b/packages/typespec-python/test/unbranded/generated/versioning-added/versioning/added/aio/_client.py index 9111e0a1514..09ec4e799b2 100644 --- a/packages/typespec-python/test/unbranded/generated/versioning-added/versioning/added/aio/_client.py +++ b/packages/typespec-python/test/unbranded/generated/versioning-added/versioning/added/aio/_client.py @@ -8,7 +8,7 @@ from corehttp.runtime import AsyncPipelineClient, policies from .. import models as _models -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import AddedClientConfiguration from .operations import AddedClientOperationsMixin, InterfaceV2Operations diff --git a/packages/typespec-python/test/unbranded/generated/versioning-added/versioning/added/aio/_vendor.py b/packages/typespec-python/test/unbranded/generated/versioning-added/versioning/added/aio/_vendor.py deleted file mode 100644 index 78ebce906df..00000000000 --- a/packages/typespec-python/test/unbranded/generated/versioning-added/versioning/added/aio/_vendor.py +++ /dev/null @@ -1,18 +0,0 @@ -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import AddedClientConfiguration - -if TYPE_CHECKING: - from corehttp.runtime import AsyncPipelineClient - - from .._serialization import Deserializer, Serializer - - -class AddedClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "AsyncPipelineClient" - _config: AddedClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/unbranded/generated/versioning-added/versioning/added/aio/operations/_operations.py b/packages/typespec-python/test/unbranded/generated/versioning-added/versioning/added/aio/operations/_operations.py index c3f49b25f72..44a7e2267eb 100644 --- a/packages/typespec-python/test/unbranded/generated/versioning-added/versioning/added/aio/operations/_operations.py +++ b/packages/typespec-python/test/unbranded/generated/versioning-added/versioning/added/aio/operations/_operations.py @@ -20,8 +20,9 @@ from corehttp.utils import case_insensitive_dict from ... import models as _models -from ..._model_base import SdkJSONEncoder, _deserialize -from ..._serialization import Deserializer, Serializer +from ..._utils.model_base import SdkJSONEncoder, _deserialize +from ..._utils.serialization import Deserializer, Serializer +from ..._utils.utils import ClientMixinABC from ..._validation import api_version_validation from ...operations._operations import ( build_added_v1_request, @@ -29,7 +30,6 @@ build_interface_v2_v2_in_interface_request, ) from .._configuration import AddedClientConfiguration -from .._vendor import AddedClientMixinABC JSON = MutableMapping[str, Any] T = TypeVar("T") @@ -172,7 +172,7 @@ async def v2_in_interface(self, body: Union[_models.ModelV2, JSON, IO[bytes]], * return deserialized # type: ignore -class AddedClientOperationsMixin(AddedClientMixinABC): +class AddedClientOperationsMixin(ClientMixinABC[AsyncPipelineClient, AddedClientConfiguration]): @overload async def v1( diff --git a/packages/typespec-python/test/unbranded/generated/versioning-added/versioning/added/models/_models.py b/packages/typespec-python/test/unbranded/generated/versioning-added/versioning/added/models/_models.py index 8d4372b3d3f..afae609dd25 100644 --- a/packages/typespec-python/test/unbranded/generated/versioning-added/versioning/added/models/_models.py +++ b/packages/typespec-python/test/unbranded/generated/versioning-added/versioning/added/models/_models.py @@ -3,14 +3,13 @@ from typing import Any, Mapping, TYPE_CHECKING, Union, overload -from .. import _model_base -from .._model_base import rest_field +from .._utils.model_base import Model as _Model, rest_field if TYPE_CHECKING: from .. import _types, models as _models -class ModelV1(_model_base.Model): +class ModelV1(_Model): """ModelV1. :ivar prop: Required. @@ -52,7 +51,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class ModelV2(_model_base.Model): +class ModelV2(_Model): """ModelV2. :ivar prop: Required. diff --git a/packages/typespec-python/test/unbranded/generated/versioning-added/versioning/added/operations/_operations.py b/packages/typespec-python/test/unbranded/generated/versioning-added/versioning/added/operations/_operations.py index 0ab753b693a..f8b44074edc 100644 --- a/packages/typespec-python/test/unbranded/generated/versioning-added/versioning/added/operations/_operations.py +++ b/packages/typespec-python/test/unbranded/generated/versioning-added/versioning/added/operations/_operations.py @@ -21,10 +21,10 @@ from .. import models as _models from .._configuration import AddedClientConfiguration -from .._model_base import SdkJSONEncoder, _deserialize -from .._serialization import Deserializer, Serializer +from .._utils.model_base import SdkJSONEncoder, _deserialize +from .._utils.serialization import Deserializer, Serializer +from .._utils.utils import ClientMixinABC from .._validation import api_version_validation -from .._vendor import AddedClientMixinABC JSON = MutableMapping[str, Any] T = TypeVar("T") @@ -220,7 +220,7 @@ def v2_in_interface(self, body: Union[_models.ModelV2, JSON, IO[bytes]], **kwarg return deserialized # type: ignore -class AddedClientOperationsMixin(AddedClientMixinABC): +class AddedClientOperationsMixin(ClientMixinABC[PipelineClient, AddedClientConfiguration]): @overload def v1( diff --git a/packages/typespec-python/test/unbranded/generated/versioning-madeoptional/versioning/madeoptional/_client.py b/packages/typespec-python/test/unbranded/generated/versioning-madeoptional/versioning/madeoptional/_client.py index 79a3f8bc7f6..feea5500212 100644 --- a/packages/typespec-python/test/unbranded/generated/versioning-madeoptional/versioning/madeoptional/_client.py +++ b/packages/typespec-python/test/unbranded/generated/versioning-madeoptional/versioning/madeoptional/_client.py @@ -10,7 +10,7 @@ from . import models as _models from ._configuration import MadeOptionalClientConfiguration from ._operations import MadeOptionalClientOperationsMixin -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer class MadeOptionalClient(MadeOptionalClientOperationsMixin): # pylint: disable=client-accepts-api-version-keyword diff --git a/packages/typespec-python/test/unbranded/generated/versioning-madeoptional/versioning/madeoptional/_operations/_operations.py b/packages/typespec-python/test/unbranded/generated/versioning-madeoptional/versioning/madeoptional/_operations/_operations.py index 7da48018442..e51983584d5 100644 --- a/packages/typespec-python/test/unbranded/generated/versioning-madeoptional/versioning/madeoptional/_operations/_operations.py +++ b/packages/typespec-python/test/unbranded/generated/versioning-madeoptional/versioning/madeoptional/_operations/_operations.py @@ -15,13 +15,15 @@ map_error, ) from corehttp.rest import HttpRequest, HttpResponse +from corehttp.runtime import PipelineClient from corehttp.runtime.pipeline import PipelineResponse from corehttp.utils import case_insensitive_dict from .. import models as _models -from .._model_base import SdkJSONEncoder, _deserialize -from .._serialization import Serializer -from .._vendor import MadeOptionalClientMixinABC +from .._configuration import MadeOptionalClientConfiguration +from .._utils.model_base import SdkJSONEncoder, _deserialize +from .._utils.serialization import Serializer +from .._utils.utils import ClientMixinABC JSON = MutableMapping[str, Any] T = TypeVar("T") @@ -53,7 +55,7 @@ def build_made_optional_test_request(*, param: Optional[str] = None, **kwargs: A return HttpRequest(method="POST", url=_url, params=_params, headers=_headers, **kwargs) -class MadeOptionalClientOperationsMixin(MadeOptionalClientMixinABC): +class MadeOptionalClientOperationsMixin(ClientMixinABC[PipelineClient, MadeOptionalClientConfiguration]): @overload def test( diff --git a/packages/typespec-python/test/unbranded/generated/versioning-madeoptional/versioning/madeoptional/_utils/__init__.py b/packages/typespec-python/test/unbranded/generated/versioning-madeoptional/versioning/madeoptional/_utils/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/packages/typespec-python/test/unbranded/generated/versioning-madeoptional/versioning/madeoptional/_model_base.py b/packages/typespec-python/test/unbranded/generated/versioning-madeoptional/versioning/madeoptional/_utils/model_base.py similarity index 100% rename from packages/typespec-python/test/unbranded/generated/versioning-madeoptional/versioning/madeoptional/_model_base.py rename to packages/typespec-python/test/unbranded/generated/versioning-madeoptional/versioning/madeoptional/_utils/model_base.py diff --git a/packages/typespec-python/test/unbranded/generated/versioning-madeoptional/versioning/madeoptional/_serialization.py b/packages/typespec-python/test/unbranded/generated/versioning-madeoptional/versioning/madeoptional/_utils/serialization.py similarity index 100% rename from packages/typespec-python/test/unbranded/generated/versioning-madeoptional/versioning/madeoptional/_serialization.py rename to packages/typespec-python/test/unbranded/generated/versioning-madeoptional/versioning/madeoptional/_utils/serialization.py diff --git a/packages/typespec-python/test/unbranded/generated/versioning-madeoptional/versioning/madeoptional/_utils/utils.py b/packages/typespec-python/test/unbranded/generated/versioning-madeoptional/versioning/madeoptional/_utils/utils.py new file mode 100644 index 00000000000..02aa2f816ea --- /dev/null +++ b/packages/typespec-python/test/unbranded/generated/versioning-madeoptional/versioning/madeoptional/_utils/utils.py @@ -0,0 +1,18 @@ +from abc import ABC +from typing import Generic, TYPE_CHECKING, TypeVar + +if TYPE_CHECKING: + from .serialization import Deserializer, Serializer + + +TClient = TypeVar("TClient") +TConfig = TypeVar("TConfig") + + +class ClientMixinABC(ABC, Generic[TClient, TConfig]): + """DO NOT use this class. It is for internal typing use only.""" + + _client: TClient + _config: TConfig + _serialize: "Serializer" + _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/unbranded/generated/versioning-madeoptional/versioning/madeoptional/_vendor.py b/packages/typespec-python/test/unbranded/generated/versioning-madeoptional/versioning/madeoptional/_vendor.py deleted file mode 100644 index 520be0cd19e..00000000000 --- a/packages/typespec-python/test/unbranded/generated/versioning-madeoptional/versioning/madeoptional/_vendor.py +++ /dev/null @@ -1,18 +0,0 @@ -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import MadeOptionalClientConfiguration - -if TYPE_CHECKING: - from corehttp.runtime import PipelineClient - - from ._serialization import Deserializer, Serializer - - -class MadeOptionalClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "PipelineClient" - _config: MadeOptionalClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/unbranded/generated/versioning-madeoptional/versioning/madeoptional/aio/_client.py b/packages/typespec-python/test/unbranded/generated/versioning-madeoptional/versioning/madeoptional/aio/_client.py index 4f9ab6da4e4..cea5d963f6b 100644 --- a/packages/typespec-python/test/unbranded/generated/versioning-madeoptional/versioning/madeoptional/aio/_client.py +++ b/packages/typespec-python/test/unbranded/generated/versioning-madeoptional/versioning/madeoptional/aio/_client.py @@ -8,7 +8,7 @@ from corehttp.runtime import AsyncPipelineClient, policies from .. import models as _models -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import MadeOptionalClientConfiguration from ._operations import MadeOptionalClientOperationsMixin diff --git a/packages/typespec-python/test/unbranded/generated/versioning-madeoptional/versioning/madeoptional/aio/_operations/_operations.py b/packages/typespec-python/test/unbranded/generated/versioning-madeoptional/versioning/madeoptional/aio/_operations/_operations.py index 85191954502..db92005a5c9 100644 --- a/packages/typespec-python/test/unbranded/generated/versioning-madeoptional/versioning/madeoptional/aio/_operations/_operations.py +++ b/packages/typespec-python/test/unbranded/generated/versioning-madeoptional/versioning/madeoptional/aio/_operations/_operations.py @@ -15,20 +15,22 @@ map_error, ) from corehttp.rest import AsyncHttpResponse, HttpRequest +from corehttp.runtime import AsyncPipelineClient from corehttp.runtime.pipeline import PipelineResponse from corehttp.utils import case_insensitive_dict from ... import models as _models -from ..._model_base import SdkJSONEncoder, _deserialize from ..._operations._operations import build_made_optional_test_request -from .._vendor import MadeOptionalClientMixinABC +from ..._utils.model_base import SdkJSONEncoder, _deserialize +from ..._utils.utils import ClientMixinABC +from .._configuration import MadeOptionalClientConfiguration JSON = MutableMapping[str, Any] T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, AsyncHttpResponse], T, Dict[str, Any]], Any]] -class MadeOptionalClientOperationsMixin(MadeOptionalClientMixinABC): +class MadeOptionalClientOperationsMixin(ClientMixinABC[AsyncPipelineClient, MadeOptionalClientConfiguration]): @overload async def test( diff --git a/packages/typespec-python/test/unbranded/generated/versioning-madeoptional/versioning/madeoptional/aio/_vendor.py b/packages/typespec-python/test/unbranded/generated/versioning-madeoptional/versioning/madeoptional/aio/_vendor.py deleted file mode 100644 index 5cd6551a8a5..00000000000 --- a/packages/typespec-python/test/unbranded/generated/versioning-madeoptional/versioning/madeoptional/aio/_vendor.py +++ /dev/null @@ -1,18 +0,0 @@ -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import MadeOptionalClientConfiguration - -if TYPE_CHECKING: - from corehttp.runtime import AsyncPipelineClient - - from .._serialization import Deserializer, Serializer - - -class MadeOptionalClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "AsyncPipelineClient" - _config: MadeOptionalClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/unbranded/generated/versioning-madeoptional/versioning/madeoptional/models/_models.py b/packages/typespec-python/test/unbranded/generated/versioning-madeoptional/versioning/madeoptional/models/_models.py index 172a88161d5..41941a5206c 100644 --- a/packages/typespec-python/test/unbranded/generated/versioning-madeoptional/versioning/madeoptional/models/_models.py +++ b/packages/typespec-python/test/unbranded/generated/versioning-madeoptional/versioning/madeoptional/models/_models.py @@ -3,11 +3,10 @@ from typing import Any, Mapping, Optional, overload -from .. import _model_base -from .._model_base import rest_field +from .._utils.model_base import Model as _Model, rest_field -class TestModel(_model_base.Model): +class TestModel(_Model): """TestModel. :ivar prop: Required. diff --git a/packages/typespec-python/test/unbranded/generated/versioning-removed/versioning/removed/_client.py b/packages/typespec-python/test/unbranded/generated/versioning-removed/versioning/removed/_client.py index 711c13ececc..e71418875f6 100644 --- a/packages/typespec-python/test/unbranded/generated/versioning-removed/versioning/removed/_client.py +++ b/packages/typespec-python/test/unbranded/generated/versioning-removed/versioning/removed/_client.py @@ -10,7 +10,7 @@ from . import models as _models from ._configuration import RemovedClientConfiguration from ._operations import RemovedClientOperationsMixin -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer class RemovedClient(RemovedClientOperationsMixin): # pylint: disable=client-accepts-api-version-keyword diff --git a/packages/typespec-python/test/unbranded/generated/versioning-removed/versioning/removed/_operations/_operations.py b/packages/typespec-python/test/unbranded/generated/versioning-removed/versioning/removed/_operations/_operations.py index 1ec526648f9..349569d198e 100644 --- a/packages/typespec-python/test/unbranded/generated/versioning-removed/versioning/removed/_operations/_operations.py +++ b/packages/typespec-python/test/unbranded/generated/versioning-removed/versioning/removed/_operations/_operations.py @@ -15,13 +15,15 @@ map_error, ) from corehttp.rest import HttpRequest, HttpResponse +from corehttp.runtime import PipelineClient from corehttp.runtime.pipeline import PipelineResponse from corehttp.utils import case_insensitive_dict from .. import models as _models -from .._model_base import SdkJSONEncoder, _deserialize -from .._serialization import Serializer -from .._vendor import RemovedClientMixinABC +from .._configuration import RemovedClientConfiguration +from .._utils.model_base import SdkJSONEncoder, _deserialize +from .._utils.serialization import Serializer +from .._utils.utils import ClientMixinABC JSON = MutableMapping[str, Any] T = TypeVar("T") @@ -65,7 +67,7 @@ def build_removed_model_v3_request(**kwargs: Any) -> HttpRequest: return HttpRequest(method="POST", url=_url, headers=_headers, **kwargs) -class RemovedClientOperationsMixin(RemovedClientMixinABC): +class RemovedClientOperationsMixin(ClientMixinABC[PipelineClient, RemovedClientConfiguration]): @overload def v2(self, body: _models.ModelV2, *, content_type: str = "application/json", **kwargs: Any) -> _models.ModelV2: diff --git a/packages/typespec-python/test/unbranded/generated/versioning-removed/versioning/removed/_utils/__init__.py b/packages/typespec-python/test/unbranded/generated/versioning-removed/versioning/removed/_utils/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/packages/typespec-python/test/unbranded/generated/versioning-removed/versioning/removed/_model_base.py b/packages/typespec-python/test/unbranded/generated/versioning-removed/versioning/removed/_utils/model_base.py similarity index 100% rename from packages/typespec-python/test/unbranded/generated/versioning-removed/versioning/removed/_model_base.py rename to packages/typespec-python/test/unbranded/generated/versioning-removed/versioning/removed/_utils/model_base.py diff --git a/packages/typespec-python/test/unbranded/generated/versioning-removed/versioning/removed/_serialization.py b/packages/typespec-python/test/unbranded/generated/versioning-removed/versioning/removed/_utils/serialization.py similarity index 100% rename from packages/typespec-python/test/unbranded/generated/versioning-removed/versioning/removed/_serialization.py rename to packages/typespec-python/test/unbranded/generated/versioning-removed/versioning/removed/_utils/serialization.py diff --git a/packages/typespec-python/test/unbranded/generated/versioning-removed/versioning/removed/_utils/utils.py b/packages/typespec-python/test/unbranded/generated/versioning-removed/versioning/removed/_utils/utils.py new file mode 100644 index 00000000000..02aa2f816ea --- /dev/null +++ b/packages/typespec-python/test/unbranded/generated/versioning-removed/versioning/removed/_utils/utils.py @@ -0,0 +1,18 @@ +from abc import ABC +from typing import Generic, TYPE_CHECKING, TypeVar + +if TYPE_CHECKING: + from .serialization import Deserializer, Serializer + + +TClient = TypeVar("TClient") +TConfig = TypeVar("TConfig") + + +class ClientMixinABC(ABC, Generic[TClient, TConfig]): + """DO NOT use this class. It is for internal typing use only.""" + + _client: TClient + _config: TConfig + _serialize: "Serializer" + _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/unbranded/generated/versioning-removed/versioning/removed/_vendor.py b/packages/typespec-python/test/unbranded/generated/versioning-removed/versioning/removed/_vendor.py deleted file mode 100644 index 476a4e99c22..00000000000 --- a/packages/typespec-python/test/unbranded/generated/versioning-removed/versioning/removed/_vendor.py +++ /dev/null @@ -1,18 +0,0 @@ -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import RemovedClientConfiguration - -if TYPE_CHECKING: - from corehttp.runtime import PipelineClient - - from ._serialization import Deserializer, Serializer - - -class RemovedClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "PipelineClient" - _config: RemovedClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/unbranded/generated/versioning-removed/versioning/removed/aio/_client.py b/packages/typespec-python/test/unbranded/generated/versioning-removed/versioning/removed/aio/_client.py index ee748741a6a..d41181be373 100644 --- a/packages/typespec-python/test/unbranded/generated/versioning-removed/versioning/removed/aio/_client.py +++ b/packages/typespec-python/test/unbranded/generated/versioning-removed/versioning/removed/aio/_client.py @@ -8,7 +8,7 @@ from corehttp.runtime import AsyncPipelineClient, policies from .. import models as _models -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import RemovedClientConfiguration from ._operations import RemovedClientOperationsMixin diff --git a/packages/typespec-python/test/unbranded/generated/versioning-removed/versioning/removed/aio/_operations/_operations.py b/packages/typespec-python/test/unbranded/generated/versioning-removed/versioning/removed/aio/_operations/_operations.py index d5cc0bd8fa9..b02e894b455 100644 --- a/packages/typespec-python/test/unbranded/generated/versioning-removed/versioning/removed/aio/_operations/_operations.py +++ b/packages/typespec-python/test/unbranded/generated/versioning-removed/versioning/removed/aio/_operations/_operations.py @@ -15,20 +15,22 @@ map_error, ) from corehttp.rest import AsyncHttpResponse, HttpRequest +from corehttp.runtime import AsyncPipelineClient from corehttp.runtime.pipeline import PipelineResponse from corehttp.utils import case_insensitive_dict from ... import models as _models -from ..._model_base import SdkJSONEncoder, _deserialize from ..._operations._operations import build_removed_model_v3_request, build_removed_v2_request -from .._vendor import RemovedClientMixinABC +from ..._utils.model_base import SdkJSONEncoder, _deserialize +from ..._utils.utils import ClientMixinABC +from .._configuration import RemovedClientConfiguration JSON = MutableMapping[str, Any] T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, AsyncHttpResponse], T, Dict[str, Any]], Any]] -class RemovedClientOperationsMixin(RemovedClientMixinABC): +class RemovedClientOperationsMixin(ClientMixinABC[AsyncPipelineClient, RemovedClientConfiguration]): @overload async def v2( diff --git a/packages/typespec-python/test/unbranded/generated/versioning-removed/versioning/removed/aio/_vendor.py b/packages/typespec-python/test/unbranded/generated/versioning-removed/versioning/removed/aio/_vendor.py deleted file mode 100644 index fcc59ef1e39..00000000000 --- a/packages/typespec-python/test/unbranded/generated/versioning-removed/versioning/removed/aio/_vendor.py +++ /dev/null @@ -1,18 +0,0 @@ -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import RemovedClientConfiguration - -if TYPE_CHECKING: - from corehttp.runtime import AsyncPipelineClient - - from .._serialization import Deserializer, Serializer - - -class RemovedClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "AsyncPipelineClient" - _config: RemovedClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/unbranded/generated/versioning-removed/versioning/removed/models/_models.py b/packages/typespec-python/test/unbranded/generated/versioning-removed/versioning/removed/models/_models.py index b5b1ee579b8..083abc9deb1 100644 --- a/packages/typespec-python/test/unbranded/generated/versioning-removed/versioning/removed/models/_models.py +++ b/packages/typespec-python/test/unbranded/generated/versioning-removed/versioning/removed/models/_models.py @@ -3,14 +3,13 @@ from typing import Any, Mapping, TYPE_CHECKING, Union, overload -from .. import _model_base -from .._model_base import rest_field +from .._utils.model_base import Model as _Model, rest_field if TYPE_CHECKING: from .. import _types, models as _models -class ModelV2(_model_base.Model): +class ModelV2(_Model): """ModelV2. :ivar prop: Required. @@ -52,7 +51,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) -class ModelV3(_model_base.Model): +class ModelV3(_Model): """ModelV3. :ivar id: Required. diff --git a/packages/typespec-python/test/unbranded/generated/versioning-renamedfrom/versioning/renamedfrom/_client.py b/packages/typespec-python/test/unbranded/generated/versioning-renamedfrom/versioning/renamedfrom/_client.py index e61d0224126..8b34bb32f69 100644 --- a/packages/typespec-python/test/unbranded/generated/versioning-renamedfrom/versioning/renamedfrom/_client.py +++ b/packages/typespec-python/test/unbranded/generated/versioning-renamedfrom/versioning/renamedfrom/_client.py @@ -9,7 +9,7 @@ from . import models as _models from ._configuration import RenamedFromClientConfiguration -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer from .operations import NewInterfaceOperations, RenamedFromClientOperationsMixin diff --git a/packages/typespec-python/test/unbranded/generated/versioning-renamedfrom/versioning/renamedfrom/_utils/__init__.py b/packages/typespec-python/test/unbranded/generated/versioning-renamedfrom/versioning/renamedfrom/_utils/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/packages/typespec-python/test/unbranded/generated/versioning-renamedfrom/versioning/renamedfrom/_model_base.py b/packages/typespec-python/test/unbranded/generated/versioning-renamedfrom/versioning/renamedfrom/_utils/model_base.py similarity index 100% rename from packages/typespec-python/test/unbranded/generated/versioning-renamedfrom/versioning/renamedfrom/_model_base.py rename to packages/typespec-python/test/unbranded/generated/versioning-renamedfrom/versioning/renamedfrom/_utils/model_base.py diff --git a/packages/typespec-python/test/unbranded/generated/versioning-renamedfrom/versioning/renamedfrom/_serialization.py b/packages/typespec-python/test/unbranded/generated/versioning-renamedfrom/versioning/renamedfrom/_utils/serialization.py similarity index 100% rename from packages/typespec-python/test/unbranded/generated/versioning-renamedfrom/versioning/renamedfrom/_serialization.py rename to packages/typespec-python/test/unbranded/generated/versioning-renamedfrom/versioning/renamedfrom/_utils/serialization.py diff --git a/packages/typespec-python/test/unbranded/generated/versioning-renamedfrom/versioning/renamedfrom/_utils/utils.py b/packages/typespec-python/test/unbranded/generated/versioning-renamedfrom/versioning/renamedfrom/_utils/utils.py new file mode 100644 index 00000000000..02aa2f816ea --- /dev/null +++ b/packages/typespec-python/test/unbranded/generated/versioning-renamedfrom/versioning/renamedfrom/_utils/utils.py @@ -0,0 +1,18 @@ +from abc import ABC +from typing import Generic, TYPE_CHECKING, TypeVar + +if TYPE_CHECKING: + from .serialization import Deserializer, Serializer + + +TClient = TypeVar("TClient") +TConfig = TypeVar("TConfig") + + +class ClientMixinABC(ABC, Generic[TClient, TConfig]): + """DO NOT use this class. It is for internal typing use only.""" + + _client: TClient + _config: TConfig + _serialize: "Serializer" + _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/unbranded/generated/versioning-renamedfrom/versioning/renamedfrom/_vendor.py b/packages/typespec-python/test/unbranded/generated/versioning-renamedfrom/versioning/renamedfrom/_vendor.py deleted file mode 100644 index 98b28d6b172..00000000000 --- a/packages/typespec-python/test/unbranded/generated/versioning-renamedfrom/versioning/renamedfrom/_vendor.py +++ /dev/null @@ -1,18 +0,0 @@ -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import RenamedFromClientConfiguration - -if TYPE_CHECKING: - from corehttp.runtime import PipelineClient - - from ._serialization import Deserializer, Serializer - - -class RenamedFromClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "PipelineClient" - _config: RenamedFromClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/unbranded/generated/versioning-renamedfrom/versioning/renamedfrom/aio/_client.py b/packages/typespec-python/test/unbranded/generated/versioning-renamedfrom/versioning/renamedfrom/aio/_client.py index 749b0cb9019..e40e1dd52d7 100644 --- a/packages/typespec-python/test/unbranded/generated/versioning-renamedfrom/versioning/renamedfrom/aio/_client.py +++ b/packages/typespec-python/test/unbranded/generated/versioning-renamedfrom/versioning/renamedfrom/aio/_client.py @@ -8,7 +8,7 @@ from corehttp.runtime import AsyncPipelineClient, policies from .. import models as _models -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import RenamedFromClientConfiguration from .operations import NewInterfaceOperations, RenamedFromClientOperationsMixin diff --git a/packages/typespec-python/test/unbranded/generated/versioning-renamedfrom/versioning/renamedfrom/aio/_vendor.py b/packages/typespec-python/test/unbranded/generated/versioning-renamedfrom/versioning/renamedfrom/aio/_vendor.py deleted file mode 100644 index 96051fd3cda..00000000000 --- a/packages/typespec-python/test/unbranded/generated/versioning-renamedfrom/versioning/renamedfrom/aio/_vendor.py +++ /dev/null @@ -1,18 +0,0 @@ -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import RenamedFromClientConfiguration - -if TYPE_CHECKING: - from corehttp.runtime import AsyncPipelineClient - - from .._serialization import Deserializer, Serializer - - -class RenamedFromClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "AsyncPipelineClient" - _config: RenamedFromClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/unbranded/generated/versioning-renamedfrom/versioning/renamedfrom/aio/operations/_operations.py b/packages/typespec-python/test/unbranded/generated/versioning-renamedfrom/versioning/renamedfrom/aio/operations/_operations.py index e5f80334f8c..7416a6fd2fe 100644 --- a/packages/typespec-python/test/unbranded/generated/versioning-renamedfrom/versioning/renamedfrom/aio/operations/_operations.py +++ b/packages/typespec-python/test/unbranded/generated/versioning-renamedfrom/versioning/renamedfrom/aio/operations/_operations.py @@ -20,14 +20,14 @@ from corehttp.utils import case_insensitive_dict from ... import models as _models -from ..._model_base import SdkJSONEncoder, _deserialize -from ..._serialization import Deserializer, Serializer +from ..._utils.model_base import SdkJSONEncoder, _deserialize +from ..._utils.serialization import Deserializer, Serializer +from ..._utils.utils import ClientMixinABC from ...operations._operations import ( build_new_interface_new_op_in_new_interface_request, build_renamed_from_new_op_request, ) from .._configuration import RenamedFromClientConfiguration -from .._vendor import RenamedFromClientMixinABC JSON = MutableMapping[str, Any] T = TypeVar("T") @@ -168,7 +168,7 @@ async def new_op_in_new_interface( return deserialized # type: ignore -class RenamedFromClientOperationsMixin(RenamedFromClientMixinABC): +class RenamedFromClientOperationsMixin(ClientMixinABC[AsyncPipelineClient, RenamedFromClientConfiguration]): @overload async def new_op( diff --git a/packages/typespec-python/test/unbranded/generated/versioning-renamedfrom/versioning/renamedfrom/models/_models.py b/packages/typespec-python/test/unbranded/generated/versioning-renamedfrom/versioning/renamedfrom/models/_models.py index 4c6346de4d1..855e563da3d 100644 --- a/packages/typespec-python/test/unbranded/generated/versioning-renamedfrom/versioning/renamedfrom/models/_models.py +++ b/packages/typespec-python/test/unbranded/generated/versioning-renamedfrom/versioning/renamedfrom/models/_models.py @@ -3,14 +3,13 @@ from typing import Any, Mapping, TYPE_CHECKING, Union, overload -from .. import _model_base -from .._model_base import rest_field +from .._utils.model_base import Model as _Model, rest_field if TYPE_CHECKING: from .. import _types, models as _models -class NewModel(_model_base.Model): +class NewModel(_Model): """NewModel. :ivar new_prop: Required. diff --git a/packages/typespec-python/test/unbranded/generated/versioning-renamedfrom/versioning/renamedfrom/operations/_operations.py b/packages/typespec-python/test/unbranded/generated/versioning-renamedfrom/versioning/renamedfrom/operations/_operations.py index dc69ea066f2..210facfbb8a 100644 --- a/packages/typespec-python/test/unbranded/generated/versioning-renamedfrom/versioning/renamedfrom/operations/_operations.py +++ b/packages/typespec-python/test/unbranded/generated/versioning-renamedfrom/versioning/renamedfrom/operations/_operations.py @@ -21,9 +21,9 @@ from .. import models as _models from .._configuration import RenamedFromClientConfiguration -from .._model_base import SdkJSONEncoder, _deserialize -from .._serialization import Deserializer, Serializer -from .._vendor import RenamedFromClientMixinABC +from .._utils.model_base import SdkJSONEncoder, _deserialize +from .._utils.serialization import Deserializer, Serializer +from .._utils.utils import ClientMixinABC JSON = MutableMapping[str, Any] T = TypeVar("T") @@ -205,7 +205,7 @@ def new_op_in_new_interface( return deserialized # type: ignore -class RenamedFromClientOperationsMixin(RenamedFromClientMixinABC): +class RenamedFromClientOperationsMixin(ClientMixinABC[PipelineClient, RenamedFromClientConfiguration]): @overload def new_op( diff --git a/packages/typespec-python/test/unbranded/generated/versioning-returntypechangedfrom/versioning/returntypechangedfrom/_client.py b/packages/typespec-python/test/unbranded/generated/versioning-returntypechangedfrom/versioning/returntypechangedfrom/_client.py index 3c8160365b7..773426b0362 100644 --- a/packages/typespec-python/test/unbranded/generated/versioning-returntypechangedfrom/versioning/returntypechangedfrom/_client.py +++ b/packages/typespec-python/test/unbranded/generated/versioning-returntypechangedfrom/versioning/returntypechangedfrom/_client.py @@ -10,7 +10,7 @@ from . import models as _models from ._configuration import ReturnTypeChangedFromClientConfiguration from ._operations import ReturnTypeChangedFromClientOperationsMixin -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer class ReturnTypeChangedFromClient( diff --git a/packages/typespec-python/test/unbranded/generated/versioning-returntypechangedfrom/versioning/returntypechangedfrom/_operations/_operations.py b/packages/typespec-python/test/unbranded/generated/versioning-returntypechangedfrom/versioning/returntypechangedfrom/_operations/_operations.py index a9e83339e6f..c7ccba4a987 100644 --- a/packages/typespec-python/test/unbranded/generated/versioning-returntypechangedfrom/versioning/returntypechangedfrom/_operations/_operations.py +++ b/packages/typespec-python/test/unbranded/generated/versioning-returntypechangedfrom/versioning/returntypechangedfrom/_operations/_operations.py @@ -14,12 +14,14 @@ map_error, ) from corehttp.rest import HttpRequest, HttpResponse +from corehttp.runtime import PipelineClient from corehttp.runtime.pipeline import PipelineResponse from corehttp.utils import case_insensitive_dict -from .._model_base import SdkJSONEncoder, _deserialize -from .._serialization import Serializer -from .._vendor import ReturnTypeChangedFromClientMixinABC +from .._configuration import ReturnTypeChangedFromClientConfiguration +from .._utils.model_base import SdkJSONEncoder, _deserialize +from .._utils.serialization import Serializer +from .._utils.utils import ClientMixinABC T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] @@ -44,7 +46,9 @@ def build_return_type_changed_from_test_request(**kwargs: Any) -> HttpRequest: return HttpRequest(method="POST", url=_url, headers=_headers, **kwargs) -class ReturnTypeChangedFromClientOperationsMixin(ReturnTypeChangedFromClientMixinABC): # pylint: disable=name-too-long +class ReturnTypeChangedFromClientOperationsMixin( # pylint: disable=name-too-long + ClientMixinABC[PipelineClient, ReturnTypeChangedFromClientConfiguration] +): def test(self, body: str, **kwargs: Any) -> str: """test. diff --git a/packages/typespec-python/test/unbranded/generated/versioning-returntypechangedfrom/versioning/returntypechangedfrom/_utils/__init__.py b/packages/typespec-python/test/unbranded/generated/versioning-returntypechangedfrom/versioning/returntypechangedfrom/_utils/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/packages/typespec-python/test/unbranded/generated/versioning-returntypechangedfrom/versioning/returntypechangedfrom/_model_base.py b/packages/typespec-python/test/unbranded/generated/versioning-returntypechangedfrom/versioning/returntypechangedfrom/_utils/model_base.py similarity index 100% rename from packages/typespec-python/test/unbranded/generated/versioning-returntypechangedfrom/versioning/returntypechangedfrom/_model_base.py rename to packages/typespec-python/test/unbranded/generated/versioning-returntypechangedfrom/versioning/returntypechangedfrom/_utils/model_base.py diff --git a/packages/typespec-python/test/unbranded/generated/versioning-returntypechangedfrom/versioning/returntypechangedfrom/_serialization.py b/packages/typespec-python/test/unbranded/generated/versioning-returntypechangedfrom/versioning/returntypechangedfrom/_utils/serialization.py similarity index 100% rename from packages/typespec-python/test/unbranded/generated/versioning-returntypechangedfrom/versioning/returntypechangedfrom/_serialization.py rename to packages/typespec-python/test/unbranded/generated/versioning-returntypechangedfrom/versioning/returntypechangedfrom/_utils/serialization.py diff --git a/packages/typespec-python/test/unbranded/generated/versioning-returntypechangedfrom/versioning/returntypechangedfrom/_utils/utils.py b/packages/typespec-python/test/unbranded/generated/versioning-returntypechangedfrom/versioning/returntypechangedfrom/_utils/utils.py new file mode 100644 index 00000000000..02aa2f816ea --- /dev/null +++ b/packages/typespec-python/test/unbranded/generated/versioning-returntypechangedfrom/versioning/returntypechangedfrom/_utils/utils.py @@ -0,0 +1,18 @@ +from abc import ABC +from typing import Generic, TYPE_CHECKING, TypeVar + +if TYPE_CHECKING: + from .serialization import Deserializer, Serializer + + +TClient = TypeVar("TClient") +TConfig = TypeVar("TConfig") + + +class ClientMixinABC(ABC, Generic[TClient, TConfig]): + """DO NOT use this class. It is for internal typing use only.""" + + _client: TClient + _config: TConfig + _serialize: "Serializer" + _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/unbranded/generated/versioning-returntypechangedfrom/versioning/returntypechangedfrom/_vendor.py b/packages/typespec-python/test/unbranded/generated/versioning-returntypechangedfrom/versioning/returntypechangedfrom/_vendor.py deleted file mode 100644 index a3d431c0cae..00000000000 --- a/packages/typespec-python/test/unbranded/generated/versioning-returntypechangedfrom/versioning/returntypechangedfrom/_vendor.py +++ /dev/null @@ -1,18 +0,0 @@ -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import ReturnTypeChangedFromClientConfiguration - -if TYPE_CHECKING: - from corehttp.runtime import PipelineClient - - from ._serialization import Deserializer, Serializer - - -class ReturnTypeChangedFromClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "PipelineClient" - _config: ReturnTypeChangedFromClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/unbranded/generated/versioning-returntypechangedfrom/versioning/returntypechangedfrom/aio/_client.py b/packages/typespec-python/test/unbranded/generated/versioning-returntypechangedfrom/versioning/returntypechangedfrom/aio/_client.py index 46ab27cf564..ca784d7b832 100644 --- a/packages/typespec-python/test/unbranded/generated/versioning-returntypechangedfrom/versioning/returntypechangedfrom/aio/_client.py +++ b/packages/typespec-python/test/unbranded/generated/versioning-returntypechangedfrom/versioning/returntypechangedfrom/aio/_client.py @@ -8,7 +8,7 @@ from corehttp.runtime import AsyncPipelineClient, policies from .. import models as _models -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import ReturnTypeChangedFromClientConfiguration from ._operations import ReturnTypeChangedFromClientOperationsMixin diff --git a/packages/typespec-python/test/unbranded/generated/versioning-returntypechangedfrom/versioning/returntypechangedfrom/aio/_operations/_operations.py b/packages/typespec-python/test/unbranded/generated/versioning-returntypechangedfrom/versioning/returntypechangedfrom/aio/_operations/_operations.py index bf9ebc6e1bd..2112265a4ee 100644 --- a/packages/typespec-python/test/unbranded/generated/versioning-returntypechangedfrom/versioning/returntypechangedfrom/aio/_operations/_operations.py +++ b/packages/typespec-python/test/unbranded/generated/versioning-returntypechangedfrom/versioning/returntypechangedfrom/aio/_operations/_operations.py @@ -14,18 +14,22 @@ map_error, ) from corehttp.rest import AsyncHttpResponse, HttpRequest +from corehttp.runtime import AsyncPipelineClient from corehttp.runtime.pipeline import PipelineResponse from corehttp.utils import case_insensitive_dict -from ..._model_base import SdkJSONEncoder, _deserialize from ..._operations._operations import build_return_type_changed_from_test_request -from .._vendor import ReturnTypeChangedFromClientMixinABC +from ..._utils.model_base import SdkJSONEncoder, _deserialize +from ..._utils.utils import ClientMixinABC +from .._configuration import ReturnTypeChangedFromClientConfiguration T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, AsyncHttpResponse], T, Dict[str, Any]], Any]] -class ReturnTypeChangedFromClientOperationsMixin(ReturnTypeChangedFromClientMixinABC): # pylint: disable=name-too-long +class ReturnTypeChangedFromClientOperationsMixin( # pylint: disable=name-too-long + ClientMixinABC[AsyncPipelineClient, ReturnTypeChangedFromClientConfiguration] +): async def test(self, body: str, **kwargs: Any) -> str: """test. diff --git a/packages/typespec-python/test/unbranded/generated/versioning-returntypechangedfrom/versioning/returntypechangedfrom/aio/_vendor.py b/packages/typespec-python/test/unbranded/generated/versioning-returntypechangedfrom/versioning/returntypechangedfrom/aio/_vendor.py deleted file mode 100644 index afb2e0ea986..00000000000 --- a/packages/typespec-python/test/unbranded/generated/versioning-returntypechangedfrom/versioning/returntypechangedfrom/aio/_vendor.py +++ /dev/null @@ -1,18 +0,0 @@ -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import ReturnTypeChangedFromClientConfiguration - -if TYPE_CHECKING: - from corehttp.runtime import AsyncPipelineClient - - from .._serialization import Deserializer, Serializer - - -class ReturnTypeChangedFromClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "AsyncPipelineClient" - _config: ReturnTypeChangedFromClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/unbranded/generated/versioning-typechangedfrom/versioning/typechangedfrom/_client.py b/packages/typespec-python/test/unbranded/generated/versioning-typechangedfrom/versioning/typechangedfrom/_client.py index bf27de33f16..801fa9100e9 100644 --- a/packages/typespec-python/test/unbranded/generated/versioning-typechangedfrom/versioning/typechangedfrom/_client.py +++ b/packages/typespec-python/test/unbranded/generated/versioning-typechangedfrom/versioning/typechangedfrom/_client.py @@ -10,7 +10,7 @@ from . import models as _models from ._configuration import TypeChangedFromClientConfiguration from ._operations import TypeChangedFromClientOperationsMixin -from ._serialization import Deserializer, Serializer +from ._utils.serialization import Deserializer, Serializer class TypeChangedFromClient(TypeChangedFromClientOperationsMixin): # pylint: disable=client-accepts-api-version-keyword diff --git a/packages/typespec-python/test/unbranded/generated/versioning-typechangedfrom/versioning/typechangedfrom/_operations/_operations.py b/packages/typespec-python/test/unbranded/generated/versioning-typechangedfrom/versioning/typechangedfrom/_operations/_operations.py index de176c30e6e..8dcc0a8d867 100644 --- a/packages/typespec-python/test/unbranded/generated/versioning-typechangedfrom/versioning/typechangedfrom/_operations/_operations.py +++ b/packages/typespec-python/test/unbranded/generated/versioning-typechangedfrom/versioning/typechangedfrom/_operations/_operations.py @@ -15,13 +15,15 @@ map_error, ) from corehttp.rest import HttpRequest, HttpResponse +from corehttp.runtime import PipelineClient from corehttp.runtime.pipeline import PipelineResponse from corehttp.utils import case_insensitive_dict from .. import models as _models -from .._model_base import SdkJSONEncoder, _deserialize -from .._serialization import Serializer -from .._vendor import TypeChangedFromClientMixinABC +from .._configuration import TypeChangedFromClientConfiguration +from .._utils.model_base import SdkJSONEncoder, _deserialize +from .._utils.serialization import Serializer +from .._utils.utils import ClientMixinABC JSON = MutableMapping[str, Any] T = TypeVar("T") @@ -52,7 +54,7 @@ def build_type_changed_from_test_request(*, param: str, **kwargs: Any) -> HttpRe return HttpRequest(method="POST", url=_url, params=_params, headers=_headers, **kwargs) -class TypeChangedFromClientOperationsMixin(TypeChangedFromClientMixinABC): +class TypeChangedFromClientOperationsMixin(ClientMixinABC[PipelineClient, TypeChangedFromClientConfiguration]): @overload def test( diff --git a/packages/typespec-python/test/unbranded/generated/versioning-typechangedfrom/versioning/typechangedfrom/_utils/__init__.py b/packages/typespec-python/test/unbranded/generated/versioning-typechangedfrom/versioning/typechangedfrom/_utils/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/packages/typespec-python/test/unbranded/generated/versioning-typechangedfrom/versioning/typechangedfrom/_model_base.py b/packages/typespec-python/test/unbranded/generated/versioning-typechangedfrom/versioning/typechangedfrom/_utils/model_base.py similarity index 100% rename from packages/typespec-python/test/unbranded/generated/versioning-typechangedfrom/versioning/typechangedfrom/_model_base.py rename to packages/typespec-python/test/unbranded/generated/versioning-typechangedfrom/versioning/typechangedfrom/_utils/model_base.py diff --git a/packages/typespec-python/test/unbranded/generated/versioning-typechangedfrom/versioning/typechangedfrom/_serialization.py b/packages/typespec-python/test/unbranded/generated/versioning-typechangedfrom/versioning/typechangedfrom/_utils/serialization.py similarity index 100% rename from packages/typespec-python/test/unbranded/generated/versioning-typechangedfrom/versioning/typechangedfrom/_serialization.py rename to packages/typespec-python/test/unbranded/generated/versioning-typechangedfrom/versioning/typechangedfrom/_utils/serialization.py diff --git a/packages/typespec-python/test/unbranded/generated/versioning-typechangedfrom/versioning/typechangedfrom/_utils/utils.py b/packages/typespec-python/test/unbranded/generated/versioning-typechangedfrom/versioning/typechangedfrom/_utils/utils.py new file mode 100644 index 00000000000..02aa2f816ea --- /dev/null +++ b/packages/typespec-python/test/unbranded/generated/versioning-typechangedfrom/versioning/typechangedfrom/_utils/utils.py @@ -0,0 +1,18 @@ +from abc import ABC +from typing import Generic, TYPE_CHECKING, TypeVar + +if TYPE_CHECKING: + from .serialization import Deserializer, Serializer + + +TClient = TypeVar("TClient") +TConfig = TypeVar("TConfig") + + +class ClientMixinABC(ABC, Generic[TClient, TConfig]): + """DO NOT use this class. It is for internal typing use only.""" + + _client: TClient + _config: TConfig + _serialize: "Serializer" + _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/unbranded/generated/versioning-typechangedfrom/versioning/typechangedfrom/_vendor.py b/packages/typespec-python/test/unbranded/generated/versioning-typechangedfrom/versioning/typechangedfrom/_vendor.py deleted file mode 100644 index 19319bacd2f..00000000000 --- a/packages/typespec-python/test/unbranded/generated/versioning-typechangedfrom/versioning/typechangedfrom/_vendor.py +++ /dev/null @@ -1,18 +0,0 @@ -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import TypeChangedFromClientConfiguration - -if TYPE_CHECKING: - from corehttp.runtime import PipelineClient - - from ._serialization import Deserializer, Serializer - - -class TypeChangedFromClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "PipelineClient" - _config: TypeChangedFromClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/unbranded/generated/versioning-typechangedfrom/versioning/typechangedfrom/aio/_client.py b/packages/typespec-python/test/unbranded/generated/versioning-typechangedfrom/versioning/typechangedfrom/aio/_client.py index 24339cb3e0d..29a7e3f021d 100644 --- a/packages/typespec-python/test/unbranded/generated/versioning-typechangedfrom/versioning/typechangedfrom/aio/_client.py +++ b/packages/typespec-python/test/unbranded/generated/versioning-typechangedfrom/versioning/typechangedfrom/aio/_client.py @@ -8,7 +8,7 @@ from corehttp.runtime import AsyncPipelineClient, policies from .. import models as _models -from .._serialization import Deserializer, Serializer +from .._utils.serialization import Deserializer, Serializer from ._configuration import TypeChangedFromClientConfiguration from ._operations import TypeChangedFromClientOperationsMixin diff --git a/packages/typespec-python/test/unbranded/generated/versioning-typechangedfrom/versioning/typechangedfrom/aio/_operations/_operations.py b/packages/typespec-python/test/unbranded/generated/versioning-typechangedfrom/versioning/typechangedfrom/aio/_operations/_operations.py index 5a6c4e47e0b..a394dca310f 100644 --- a/packages/typespec-python/test/unbranded/generated/versioning-typechangedfrom/versioning/typechangedfrom/aio/_operations/_operations.py +++ b/packages/typespec-python/test/unbranded/generated/versioning-typechangedfrom/versioning/typechangedfrom/aio/_operations/_operations.py @@ -15,20 +15,22 @@ map_error, ) from corehttp.rest import AsyncHttpResponse, HttpRequest +from corehttp.runtime import AsyncPipelineClient from corehttp.runtime.pipeline import PipelineResponse from corehttp.utils import case_insensitive_dict from ... import models as _models -from ..._model_base import SdkJSONEncoder, _deserialize from ..._operations._operations import build_type_changed_from_test_request -from .._vendor import TypeChangedFromClientMixinABC +from ..._utils.model_base import SdkJSONEncoder, _deserialize +from ..._utils.utils import ClientMixinABC +from .._configuration import TypeChangedFromClientConfiguration JSON = MutableMapping[str, Any] T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, AsyncHttpResponse], T, Dict[str, Any]], Any]] -class TypeChangedFromClientOperationsMixin(TypeChangedFromClientMixinABC): +class TypeChangedFromClientOperationsMixin(ClientMixinABC[AsyncPipelineClient, TypeChangedFromClientConfiguration]): @overload async def test( diff --git a/packages/typespec-python/test/unbranded/generated/versioning-typechangedfrom/versioning/typechangedfrom/aio/_vendor.py b/packages/typespec-python/test/unbranded/generated/versioning-typechangedfrom/versioning/typechangedfrom/aio/_vendor.py deleted file mode 100644 index e9cb86366a8..00000000000 --- a/packages/typespec-python/test/unbranded/generated/versioning-typechangedfrom/versioning/typechangedfrom/aio/_vendor.py +++ /dev/null @@ -1,18 +0,0 @@ -from abc import ABC -from typing import TYPE_CHECKING - -from ._configuration import TypeChangedFromClientConfiguration - -if TYPE_CHECKING: - from corehttp.runtime import AsyncPipelineClient - - from .._serialization import Deserializer, Serializer - - -class TypeChangedFromClientMixinABC(ABC): - """DO NOT use this class. It is for internal typing use only.""" - - _client: "AsyncPipelineClient" - _config: TypeChangedFromClientConfiguration - _serialize: "Serializer" - _deserialize: "Deserializer" diff --git a/packages/typespec-python/test/unbranded/generated/versioning-typechangedfrom/versioning/typechangedfrom/models/_models.py b/packages/typespec-python/test/unbranded/generated/versioning-typechangedfrom/versioning/typechangedfrom/models/_models.py index adfc3374ed7..50d31a1d17d 100644 --- a/packages/typespec-python/test/unbranded/generated/versioning-typechangedfrom/versioning/typechangedfrom/models/_models.py +++ b/packages/typespec-python/test/unbranded/generated/versioning-typechangedfrom/versioning/typechangedfrom/models/_models.py @@ -3,11 +3,10 @@ from typing import Any, Mapping, overload -from .. import _model_base -from .._model_base import rest_field +from .._utils.model_base import Model as _Model, rest_field -class TestModel(_model_base.Model): +class TestModel(_Model): """TestModel. :ivar prop: Required. diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index fa15c02644c..4cf919a62ea 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -57,8 +57,8 @@ importers: specifier: ~1.0.2 version: 1.0.2 '@typespec/http-client-python': - specifier: ~0.11.0 - version: 0.11.0(snncae6gzwxjtoyf2aptgh5sru) + specifier: ~0.11.1 + version: 0.11.1(snncae6gzwxjtoyf2aptgh5sru) fs-extra: specifier: ~11.2.0 version: 11.2.0 @@ -79,8 +79,8 @@ importers: packages/typespec-python: dependencies: '@typespec/http-client-python': - specifier: ~0.11.0 - version: 0.11.0(snncae6gzwxjtoyf2aptgh5sru) + specifier: ~0.11.1 + version: 0.11.1(snncae6gzwxjtoyf2aptgh5sru) fs-extra: specifier: ~11.2.0 version: 11.2.0 @@ -1538,8 +1538,8 @@ packages: peerDependencies: '@typespec/compiler': ^1.0.0-rc.0 - '@typespec/http-client-python@0.11.0': - resolution: {integrity: sha512-slbYCuyMcQrq0ACwk0PKAN1lkbhrRH3oawxadVreYHWxWpletRNCuoAiGD/f4NK1VGQzfNokPmAs2myRsi7D9w==} + '@typespec/http-client-python@0.11.1': + resolution: {integrity: sha512-RVdyHsFu4fzVO3/xtfNo9ZspCKAUZPukmKiV6WUfoabS5jEtl9YpxMGC7Cyb07tAnE0qjEOrQcMyABIq0yBpxA==} engines: {node: '>=20.0.0'} peerDependencies: '@azure-tools/typespec-autorest': '>=0.54.0 <1.0.0' @@ -5893,7 +5893,7 @@ snapshots: dependencies: '@typespec/compiler': 1.0.0-rc.0(@types/node@22.13.17) - '@typespec/http-client-python@0.11.0(snncae6gzwxjtoyf2aptgh5sru)': + '@typespec/http-client-python@0.11.1(snncae6gzwxjtoyf2aptgh5sru)': dependencies: '@azure-tools/typespec-autorest': 0.54.0(psqtwvjmgth7tsukc2x2eth2za) '@azure-tools/typespec-azure-core': 0.54.0(@typespec/compiler@1.0.0-rc.0(@types/node@22.13.17))(@typespec/http@1.0.0-rc.0(@typespec/compiler@1.0.0-rc.0(@types/node@22.13.17))(@typespec/streams@0.68.0(@typespec/compiler@1.0.0-rc.0(@types/node@22.13.17))))(@typespec/rest@0.68.0(@typespec/compiler@1.0.0-rc.0(@types/node@22.13.17))(@typespec/http@1.0.0-rc.0(@typespec/compiler@1.0.0-rc.0(@types/node@22.13.17))(@typespec/streams@0.68.0(@typespec/compiler@1.0.0-rc.0(@types/node@22.13.17)))))