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)))))