@autorest/python 6.1.6 → 6.1.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (29) hide show
  1. package/autorest/_utils.py +22 -3
  2. package/autorest/black/__init__.py +2 -2
  3. package/autorest/cadlflags/__init__.py +4 -2
  4. package/autorest/codegen/__init__.py +8 -4
  5. package/autorest/codegen/models/__init__.py +1 -1
  6. package/autorest/codegen/models/client.py +5 -3
  7. package/autorest/codegen/models/combined_type.py +6 -4
  8. package/autorest/codegen/models/enum_type.py +6 -4
  9. package/autorest/codegen/models/model_type.py +30 -9
  10. package/autorest/codegen/models/operation.py +21 -0
  11. package/autorest/codegen/models/operation_group.py +6 -7
  12. package/autorest/codegen/models/parameter.py +37 -0
  13. package/autorest/codegen/models/property.py +8 -15
  14. package/autorest/codegen/models/request_builder_parameter.py +4 -2
  15. package/autorest/codegen/serializers/__init__.py +12 -2
  16. package/autorest/codegen/serializers/builder_serializer.py +42 -20
  17. package/autorest/codegen/serializers/client_serializer.py +3 -4
  18. package/autorest/codegen/serializers/general_serializer.py +4 -0
  19. package/autorest/codegen/serializers/model_serializer.py +159 -61
  20. package/autorest/codegen/templates/model_base.py.jinja2 +636 -0
  21. package/autorest/codegen/templates/model_container.py.jinja2 +6 -2
  22. package/autorest/codegen/templates/model_dpg.py.jinja2 +62 -0
  23. package/autorest/codegen/templates/model_init.py.jinja2 +0 -5
  24. package/autorest/codegen/templates/{model.py.jinja2 → model_msrest.py.jinja2} +1 -1
  25. package/autorest/codegen/templates/operation_group.py.jinja2 +1 -1
  26. package/autorest/m2r/__init__.py +4 -2
  27. package/autorest/preprocess/__init__.py +2 -2
  28. package/package.json +9 -10
  29. package/ChangeLog.md +0 -1299
@@ -3,7 +3,7 @@
3
3
  # Licensed under the MIT License. See License.txt in the project root for
4
4
  # license information.
5
5
  # --------------------------------------------------------------------------
6
- from typing import Any, Dict
6
+ from typing import Any, Dict, Tuple
7
7
  import re
8
8
  import argparse
9
9
 
@@ -37,7 +37,9 @@ def to_snake_case(name: str) -> str:
37
37
  return re.sub("[A-Z]+", replace_upper_characters, name)
38
38
 
39
39
 
40
- def parse_args(need_cadl_file: bool = True):
40
+ def parse_args(
41
+ need_cadl_file: bool = True,
42
+ ) -> Tuple[argparse.Namespace, Dict[str, Any]]:
41
43
  parser = argparse.ArgumentParser(
42
44
  description="Run mypy against target folder. Add a local custom plugin to the path prior to execution. "
43
45
  )
@@ -60,7 +62,24 @@ def parse_args(need_cadl_file: bool = True):
60
62
  required=False,
61
63
  action="store_true",
62
64
  )
63
- return parser.parse_args()
65
+ args, unknown_args = parser.parse_known_args()
66
+
67
+ def _get_value(value: Any) -> Any:
68
+ if value == "true":
69
+ return True
70
+ if value == "false":
71
+ return False
72
+ try:
73
+ return int(value)
74
+ except ValueError:
75
+ pass
76
+ return value
77
+
78
+ unknown_args_ret = {
79
+ ua.strip("--").split("=")[0]: _get_value(ua.strip("--").split("=")[1])
80
+ for ua in unknown_args
81
+ }
82
+ return args, unknown_args_ret
64
83
 
65
84
 
66
85
  def get_body_type_for_description(body_parameter: Dict[str, Any]) -> str:
@@ -54,5 +54,5 @@ class BlackScriptPluginAutorest(BlackScriptPlugin, PluginAutorest):
54
54
 
55
55
  if __name__ == "__main__":
56
56
  # CADL pipeline will call this
57
- args = parse_args(need_cadl_file=False)
58
- BlackScriptPlugin(output_folder=args.output_folder).process()
57
+ args, unknown_args = parse_args(need_cadl_file=False)
58
+ BlackScriptPlugin(output_folder=args.output_folder, **unknown_args).process()
@@ -124,5 +124,7 @@ class CadlFlags(YamlUpdatePlugin): # pylint: disable=abstract-method
124
124
 
125
125
  if __name__ == "__main__":
126
126
  # CADL pipeline will call this
127
- args = parse_args()
128
- CadlFlags(output_folder=args.output_folder, cadl_file=args.cadl_file).process()
127
+ args, unknown_args = parse_args()
128
+ CadlFlags(
129
+ output_folder=args.output_folder, cadl_file=args.cadl_file, **unknown_args
130
+ ).process()
@@ -44,9 +44,9 @@ def _validate_code_model_options(options: Dict[str, Any]) -> None:
44
44
  "or 'embedded'"
45
45
  )
46
46
 
47
- if options["models_mode"] not in ["msrest", "none"]:
47
+ if options["models_mode"] not in ["msrest", "dpg", "none"]:
48
48
  raise ValueError(
49
- "--models-mode can only be 'msrest' or 'none'. "
49
+ "--models-mode can only be 'msrest', 'dpg' or 'none'. "
50
50
  "Pass in 'msrest' if you want msrest models, or "
51
51
  "'none' if you don't want any."
52
52
  )
@@ -179,6 +179,8 @@ class CodeGenerator(Plugin):
179
179
  models_mode_default = (
180
180
  "none" if low_level_client or version_tolerant else "msrest"
181
181
  )
182
+ if self.options.get("cadl_file") is not None:
183
+ models_mode_default = "dpg"
182
184
 
183
185
  options: Dict[str, Any] = {
184
186
  "azure_arm": azure_arm,
@@ -359,5 +361,7 @@ class CodeGeneratorAutorest(CodeGenerator, PluginAutorest):
359
361
 
360
362
  if __name__ == "__main__":
361
363
  # CADL pipeline will call this
362
- args = parse_args()
363
- CodeGenerator(output_folder=args.output_folder, cadl_file=args.cadl_file).process()
364
+ args, unknown_args = parse_args()
365
+ CodeGenerator(
366
+ output_folder=args.output_folder, cadl_file=args.cadl_file, **unknown_args
367
+ ).process()
@@ -158,7 +158,7 @@ def build_type(yaml_data: Dict[str, Any], code_model: CodeModel) -> BaseType:
158
158
  code_model.types_map[yaml_id] = response
159
159
  response.fill_instance_from_yaml(yaml_data, code_model)
160
160
  else:
161
- object_type = yaml_data.get("type", None)
161
+ object_type = yaml_data.get("type")
162
162
  if object_type is None:
163
163
  _LOGGER.warning(
164
164
  'Unrecognized definition type "%s" is found, falling back it as "string"! ',
@@ -108,7 +108,6 @@ class Client(_ClientConfigBase[ClientGlobalParameterList]):
108
108
  f"{self.code_model.client.name}Configuration",
109
109
  ImportType.LOCAL,
110
110
  )
111
-
112
111
  file_import.add_msrest_import(
113
112
  self.code_model,
114
113
  ".." if async_mode else ".",
@@ -148,7 +147,10 @@ class Client(_ClientConfigBase[ClientGlobalParameterList]):
148
147
  ImportType.LOCAL,
149
148
  )
150
149
 
151
- if self.code_model.model_types and self.code_model.options["models_mode"]:
150
+ if (
151
+ self.code_model.model_types
152
+ and self.code_model.options["models_mode"] == "msrest"
153
+ ):
152
154
  path_to_models = ".." if async_mode else "."
153
155
  if len(self.code_model.model_types) != len(
154
156
  self.code_model.public_model_types
@@ -167,7 +169,7 @@ class Client(_ClientConfigBase[ClientGlobalParameterList]):
167
169
  file_import.add_submodule_import(
168
170
  path_to_models, "models", ImportType.LOCAL
169
171
  )
170
- else:
172
+ elif self.code_model.options["models_mode"] == "msrest":
171
173
  # in this case, we have client_models = {} in the service client, which needs a type annotation
172
174
  # this import will always be commented, so will always add it to the typing section
173
175
  file_import.add_submodule_import(
@@ -4,7 +4,7 @@
4
4
  # license information.
5
5
  # --------------------------------------------------------------------------
6
6
  from typing import Any, Dict, List, Optional, TYPE_CHECKING
7
-
7
+ import re
8
8
  from autorest.codegen.models.imports import FileImport, ImportType
9
9
  from .base_type import BaseType
10
10
 
@@ -67,9 +67,11 @@ class CombinedType(BaseType):
67
67
  Special case for enum, for instance: Union[str, "EnumName"]
68
68
  """
69
69
  kwargs["is_operation_file"] = True
70
- return (
71
- f'Union[{", ".join(type.type_annotation(**kwargs) for type in self.types)}]'
72
- )
70
+ inside_types = [type.type_annotation(**kwargs) for type in self.types]
71
+
72
+ # If the inside types has been a Union, peel first and then re-union
73
+ pattern = re.compile(r"Union\[.*\]")
74
+ return f'Union[{", ".join(map(lambda x: x[6: -1] if pattern.match(x) else x, inside_types))}]'
73
75
 
74
76
  def get_json_template_representation(
75
77
  self,
@@ -107,10 +107,12 @@ class EnumType(BaseType):
107
107
  :rtype: str
108
108
  """
109
109
  if self.code_model.options["models_mode"]:
110
- return (
111
- f"Union[{self.value_type.type_annotation(**kwargs)},"
112
- f' "_models.{self.name}"]'
113
- )
110
+ model_name = f"_models.{self.name}"
111
+ # we don't need quoted annotation in operation files, and need it in model folder files.
112
+ if not kwargs.get("is_operation_file", False):
113
+ model_name = f'"{model_name}"'
114
+
115
+ return f"Union[{self.value_type.type_annotation(**kwargs)}, {model_name}]"
114
116
  return self.value_type.type_annotation(**kwargs)
115
117
 
116
118
  def get_declaration(self, value: Any) -> str:
@@ -8,6 +8,7 @@ from typing import Any, Dict, List, Optional, TYPE_CHECKING, cast
8
8
 
9
9
  from autorest.codegen.models.utils import add_to_pylint_disable
10
10
  from .base_type import BaseType
11
+ from .constant_type import ConstantType
11
12
  from .property import Property
12
13
  from .imports import FileImport, ImportType, TypingSection
13
14
 
@@ -32,7 +33,9 @@ def _get_properties(type: "ModelType", properties: List[Property]) -> List[Prope
32
33
  return properties
33
34
 
34
35
 
35
- class ModelType(BaseType): # pylint: disable=too-many-instance-attributes
36
+ class ModelType(
37
+ BaseType
38
+ ): # pylint: disable=too-many-instance-attributes, too-many-public-methods
36
39
  """Represents a class ready to be serialized in Python.
37
40
 
38
41
  :param str name: The name of the class.
@@ -71,14 +74,16 @@ class ModelType(BaseType): # pylint: disable=too-many-instance-attributes
71
74
 
72
75
  @property
73
76
  def serialization_type(self) -> str:
74
- if self.code_model.options["models_mode"]:
75
- return (
76
- self.name
77
- if self.is_public
78
- else f"{self.code_model.models_filename}.{self.name}"
79
- )
77
+ if self.code_model.options["models_mode"] == "msrest":
78
+ return f"{'' if self.is_public else (self.code_model.models_filename + '.')}{self.name}"
79
+ if self.code_model.options["models_mode"] == "dpg":
80
+ return f"{'' if self.is_public else '_models.'}_models.{self.name}"
80
81
  return "object"
81
82
 
83
+ @property
84
+ def is_polymorphic(self) -> bool:
85
+ return any(p.is_polymorphic for p in self.properties)
86
+
82
87
  def type_annotation(self, **kwargs: Any) -> str:
83
88
  if self.code_model.options["models_mode"]:
84
89
  is_operation_file = kwargs.pop("is_operation_file", False)
@@ -229,10 +234,26 @@ class ModelType(BaseType): # pylint: disable=too-many-instance-attributes
229
234
  except StopIteration:
230
235
  return None
231
236
 
237
+ @property
238
+ def discriminator_property(self) -> Optional[Property]:
239
+ try:
240
+ return next(
241
+ p
242
+ for p in self.properties
243
+ if p.is_discriminator
244
+ and isinstance(p.type, ConstantType)
245
+ and p.type.value == self.discriminator_value
246
+ )
247
+ except StopIteration:
248
+ return None
249
+
232
250
  @property
233
251
  def instance_check_template(self) -> str:
234
- if self.code_model.options["models_mode"]:
252
+ models_mode = self.code_model.options["models_mode"]
253
+ if models_mode == "msrest":
235
254
  return "isinstance({}, msrest.Model)"
255
+ if models_mode == "dpg":
256
+ return "isinstance({}, _model_base.Model)"
236
257
  return "isinstance({}, MutableMapping)"
237
258
 
238
259
  @property
@@ -257,7 +278,7 @@ class ModelType(BaseType): # pylint: disable=too-many-instance-attributes
257
278
  file_import.add_submodule_import(
258
279
  relative_path, "models", ImportType.LOCAL, alias="_models"
259
280
  )
260
- if self.code_model.options["models_mode"]:
281
+ if self.code_model.options["models_mode"] == "msrest":
261
282
  return file_import
262
283
  file_import.add_submodule_import(
263
284
  "typing", "Any", ImportType.STDLIB, TypingSection.CONDITIONAL
@@ -154,6 +154,14 @@ class OperationBase( # pylint: disable=too-many-public-methods
154
154
  retval = self._response_docstring_helper("docstring_text", **kwargs)
155
155
  if not self.code_model.options["version_tolerant"]:
156
156
  retval += " or the result of cls(response)"
157
+ if self.code_model.options["models_mode"] == "dpg" and any(
158
+ isinstance(r.type, ModelType) for r in self.responses
159
+ ):
160
+ r = next(r for r in self.responses if isinstance(r.type, ModelType))
161
+ type_name = getattr(r, "item_type", getattr(r, "type")).docstring_text(
162
+ **kwargs
163
+ )
164
+ retval += f". The {type_name} is compatible with MutableMapping"
157
165
  return retval
158
166
 
159
167
  def response_docstring_type(self, **kwargs) -> str:
@@ -461,6 +469,19 @@ class Operation(OperationBase[Response]):
461
469
  and not self.code_model.options["models_mode"]
462
470
  ):
463
471
  file_import.add_submodule_import("typing", "cast", ImportType.STDLIB)
472
+ if self.code_model.options["models_mode"] == "dpg":
473
+ relative_path = "..." if async_mode else ".."
474
+ if self.parameters.has_body:
475
+ file_import.add_submodule_import(
476
+ f"{relative_path}_model_base", "AzureJSONEncoder", ImportType.LOCAL
477
+ )
478
+ file_import.add_import("json", ImportType.STDLIB)
479
+ if self.default_error_deserialization or any(
480
+ [r.type for r in self.responses]
481
+ ):
482
+ file_import.add_submodule_import(
483
+ f"{relative_path}_model_base", "_deserialize", ImportType.LOCAL
484
+ )
464
485
 
465
486
  return file_import
466
487
 
@@ -80,13 +80,12 @@ class OperationGroup(BaseModel):
80
80
  operation.imports(async_mode, relative_path=relative_path)
81
81
  )
82
82
  # for multiapi
83
- if not self.code_model.options["version_tolerant"]:
84
- if (
85
- self.code_model.model_types or self.code_model.enums
86
- ) and self.code_model.options["models_mode"]:
87
- file_import.add_submodule_import(
88
- relative_path, "models", ImportType.LOCAL, alias="_models"
89
- )
83
+ if (
84
+ self.code_model.model_types or self.code_model.enums
85
+ ) and self.code_model.options["models_mode"] == "msrest":
86
+ file_import.add_submodule_import(
87
+ relative_path, "models", ImportType.LOCAL, alias="_models"
88
+ )
90
89
  if self.code_model.need_mixin_abc:
91
90
  file_import.add_submodule_import(".._vendor", "MixinABC", ImportType.LOCAL)
92
91
  if self.has_abstract_operations:
@@ -5,6 +5,7 @@
5
5
  # --------------------------------------------------------------------------
6
6
  import abc
7
7
  from enum import Enum, auto
8
+ import re
8
9
 
9
10
  from typing import (
10
11
  Dict,
@@ -21,6 +22,8 @@ from .imports import FileImport, ImportType
21
22
  from .base_model import BaseModel
22
23
  from .base_type import BaseType
23
24
  from .constant_type import ConstantType
25
+ from .model_type import ModelType
26
+ from .combined_type import CombinedType
24
27
  from .utils import add_to_description
25
28
 
26
29
  if TYPE_CHECKING:
@@ -235,6 +238,40 @@ class BodyParameter(_BodyParameterBase):
235
238
  type=code_model.lookup_type(id(yaml_data["type"])),
236
239
  )
237
240
 
241
+ def type_annotation(self, **kwargs: Any) -> str:
242
+ annotation = super().type_annotation(**kwargs)
243
+ model_seq = BodyParameter.get_model_seq(self.type)
244
+ if self.code_model.options["models_mode"] == "dpg" and model_seq >= 0:
245
+ pattern = re.compile(r"Union\[.*\]")
246
+ union_content = (
247
+ annotation[6:-1] if pattern.match(annotation) else annotation
248
+ )
249
+ items = union_content.split(", ")
250
+ items.insert(model_seq + 1, "JSON")
251
+ annotation = f'Union[{", ".join(items)}]'
252
+ return annotation
253
+
254
+ def docstring_type(self, **kwargs: Any) -> str:
255
+ docstring = super().docstring_type(**kwargs)
256
+ model_seq = BodyParameter.get_model_seq(self.type)
257
+ if self.code_model.options["models_mode"] == "dpg" and model_seq >= 0:
258
+ items = docstring.split(" or ")
259
+ items.insert(model_seq + 1, "JSON")
260
+ docstring = " or ".join(items)
261
+ return docstring
262
+
263
+ @staticmethod
264
+ def get_model_seq(t: BaseType):
265
+ if isinstance(t, ModelType):
266
+ return 0
267
+ if isinstance(t, CombinedType):
268
+ sub_num = len(t.types)
269
+ for i in range(sub_num):
270
+ sub_seq = BodyParameter.get_model_seq(t.types[i])
271
+ if sub_seq >= 0:
272
+ return i + sub_seq
273
+ return -1
274
+
238
275
 
239
276
  EntryBodyParameterType = TypeVar(
240
277
  "EntryBodyParameterType", bound=Union[BodyParameter, "RequestBuilderBodyParameter"]
@@ -29,6 +29,7 @@ class Property(BaseModel): # pylint: disable=too-many-instance-attributes
29
29
  self.type = type
30
30
  self.optional: bool = self.yaml_data["optional"]
31
31
  self.readonly: bool = self.yaml_data.get("readonly", False)
32
+ self.is_polymorphic: bool = self.yaml_data.get("isPolymorphic", False)
32
33
  self.is_discriminator: bool = yaml_data.get("isDiscriminator", False)
33
34
  self.client_default_value = yaml_data.get("clientDefaultValue", None)
34
35
  if self.client_default_value is None:
@@ -45,7 +46,7 @@ class Property(BaseModel): # pylint: disable=too-many-instance-attributes
45
46
  def description(self, *, is_operation_file: bool) -> str:
46
47
  from .model_type import ModelType
47
48
 
48
- description = self.yaml_data["description"]
49
+ description = self.yaml_data.get("description", "")
49
50
  if not (self.optional or self.client_default_value):
50
51
  description = add_to_description(description, "Required.")
51
52
  # don't want model type documentation as part of property doc
@@ -124,20 +125,6 @@ class Property(BaseModel): # pylint: disable=too-many-instance-attributes
124
125
  retval.update(self.type.validation or {})
125
126
  return retval or None
126
127
 
127
- @property
128
- def attribute_map(self) -> str:
129
- if self.flattened_names:
130
- attribute_key = ".".join(
131
- n.replace(".", "\\\\.") for n in self.flattened_names
132
- )
133
- else:
134
- attribute_key = self.rest_api_name.replace(".", "\\\\.")
135
- if self.type.xml_serialization_ctxt:
136
- xml_metadata = f", 'xml': {{{self.type.xml_serialization_ctxt}}}"
137
- else:
138
- xml_metadata = ""
139
- return f'"{self.client_name}": {{"key": "{attribute_key}", "type": "{self.serialization_type}"{xml_metadata}}},'
140
-
141
128
  def imports(self) -> FileImport:
142
129
  from .model_type import ModelType
143
130
 
@@ -152,6 +139,12 @@ class Property(BaseModel): # pylint: disable=too-many-instance-attributes
152
139
  TypingSection.TYPING,
153
140
  alias="_models",
154
141
  )
142
+ if self.code_model.options["models_mode"] == "dpg":
143
+ file_import.add_submodule_import(
144
+ ".._model_base",
145
+ "rest_discriminator" if self.is_discriminator else "rest_field",
146
+ ImportType.LOCAL,
147
+ )
155
148
  return file_import
156
149
 
157
150
  @classmethod
@@ -24,8 +24,10 @@ class RequestBuilderBodyParameter(BodyParameter):
24
24
 
25
25
  def __init__(self, *args, **kwargs) -> None:
26
26
  super().__init__(*args, **kwargs)
27
- if isinstance(self.type, (BinaryType, StringType)) or any(
28
- "xml" in ct for ct in self.content_types
27
+ if (
28
+ isinstance(self.type, (BinaryType, StringType))
29
+ or any("xml" in ct for ct in self.content_types)
30
+ or self.code_model.options["models_mode"] == "dpg"
29
31
  ):
30
32
  self.client_name = "content"
31
33
  else:
@@ -16,7 +16,7 @@ from ..models import TokenCredentialType
16
16
  from .enum_serializer import EnumSerializer
17
17
  from .general_serializer import GeneralSerializer
18
18
  from .model_init_serializer import ModelInitSerializer
19
- from .model_serializer import ModelSerializer
19
+ from .model_serializer import DpgModelSerializer, MsrestModelSerializer
20
20
  from .operations_init_serializer import OperationsInitSerializer
21
21
  from .operation_groups_serializer import OperationGroupsSerializer
22
22
  from .metadata_serializer import MetadataSerializer
@@ -215,10 +215,15 @@ class JinjaSerializer(ReaderAndWriter): # pylint: disable=abstract-method
215
215
  ) -> None:
216
216
  # Write the models folder
217
217
  models_path = namespace_path / Path("models")
218
+ serializer = (
219
+ DpgModelSerializer
220
+ if self.code_model.options["models_mode"] == "dpg"
221
+ else MsrestModelSerializer
222
+ )
218
223
  if self.code_model.model_types:
219
224
  self.write_file(
220
225
  models_path / Path(f"{self.code_model.models_filename}.py"),
221
- ModelSerializer(code_model=self.code_model, env=env).serialize(),
226
+ serializer(code_model=self.code_model, env=env).serialize(),
222
227
  )
223
228
  if self.code_model.enums:
224
229
  self.write_file(
@@ -427,6 +432,11 @@ class JinjaSerializer(ReaderAndWriter): # pylint: disable=abstract-method
427
432
  namespace_path / Path("_serialization.py"),
428
433
  general_serializer.serialize_serialization_file(),
429
434
  )
435
+ if self.code_model.options["models_mode"] == "dpg":
436
+ self.write_file(
437
+ namespace_path / Path("_model_base.py"),
438
+ general_serializer.serialize_model_base_file(),
439
+ )
430
440
 
431
441
  if any(og for og in self.code_model.operation_groups if og.need_validation):
432
442
  self.write_file(
@@ -674,7 +674,7 @@ class _OperationSerializer(
674
674
  ser_ctxt_name = "serialization_ctxt"
675
675
  if xml_serialization_ctxt and self.code_model.options["models_mode"]:
676
676
  retval.append(f'{ser_ctxt_name} = {{"xml": {{{xml_serialization_ctxt}}}}}')
677
- if self.code_model.options["models_mode"]:
677
+ if self.code_model.options["models_mode"] == "msrest":
678
678
  is_xml_cmd = ", is_xml=True" if send_xml else ""
679
679
  serialization_ctxt_cmd = (
680
680
  f", {ser_ctxt_name}={ser_ctxt_name}" if xml_serialization_ctxt else ""
@@ -683,6 +683,8 @@ class _OperationSerializer(
683
683
  f"_{body_kwarg_name} = self._serialize.body({body_param.client_name}, "
684
684
  f"'{body_param.type.serialization_type}'{is_xml_cmd}{serialization_ctxt_cmd})"
685
685
  )
686
+ elif self.code_model.options["models_mode"] == "dpg":
687
+ create_body_call = f"_{body_kwarg_name} = json.dumps({body_param.client_name}, cls=AzureJSONEncoder)"
686
688
  else:
687
689
  create_body_call = f"_{body_kwarg_name} = {body_param.client_name}"
688
690
  if body_param.optional:
@@ -747,10 +749,12 @@ class _OperationSerializer(
747
749
  0
748
750
  ].parameters.body_parameter.default_content_type
749
751
  retval.append(f'content_type = content_type or "{default_content_type}"')
750
- for overload in builder.overloads:
751
- retval.append(
752
- f"_{overload.request_builder.parameters.body_parameter.client_name} = None"
753
- )
752
+ client_names = [
753
+ overload.request_builder.parameters.body_parameter.client_name
754
+ for overload in builder.overloads
755
+ ]
756
+ for v in sorted(set(client_names), key=client_names.index):
757
+ retval.append(f"_{v} = None")
754
758
  try:
755
759
  # if there is a binary overload, we do a binary check first.
756
760
  binary_overload = cast(
@@ -959,10 +963,16 @@ class _OperationSerializer(
959
963
  )
960
964
  )
961
965
  elif response.type:
962
- if self.code_model.options["models_mode"]:
966
+ if self.code_model.options["models_mode"] == "msrest":
963
967
  retval.append(
964
968
  f"deserialized = self._deserialize('{response.serialization_type}', pipeline_response)"
965
969
  )
970
+ elif self.code_model.options["models_mode"] == "dpg" and isinstance(
971
+ response.type, ModelType
972
+ ):
973
+ retval.append(
974
+ f"deserialized = _deserialize({response.serialization_type}, response.json())"
975
+ )
966
976
  else:
967
977
  deserialized_value = (
968
978
  "ET.fromstring(response.text())"
@@ -987,10 +997,15 @@ class _OperationSerializer(
987
997
  builder.default_error_deserialization
988
998
  and self.code_model.options["models_mode"]
989
999
  ):
990
- retval.append(
991
- f" error = self._deserialize.failsafe_deserialize({builder.default_error_deserialization}, "
992
- "pipeline_response)"
993
- )
1000
+ if self.code_model.options["models_mode"] == "dpg":
1001
+ retval.append(
1002
+ f" error = _deserialize({builder.default_error_deserialization}, response.json())"
1003
+ )
1004
+ else:
1005
+ retval.append(
1006
+ f" error = self._deserialize.failsafe_deserialize({builder.default_error_deserialization}, "
1007
+ "pipeline_response)"
1008
+ )
994
1009
  error_model = ", model=error"
995
1010
  retval.append(
996
1011
  " raise HttpResponseError(response=response{}{})".format(
@@ -1065,11 +1080,14 @@ class _OperationSerializer(
1065
1080
  retval.append(" 304: ResourceNotModifiedError,")
1066
1081
  for excep in builder.non_default_errors:
1067
1082
  error_model_str = ""
1068
- if (
1069
- isinstance(excep.type, ModelType)
1070
- and self.code_model.options["models_mode"]
1071
- ):
1072
- error_model_str = f", model=self._deserialize(_models.{excep.type.serialization_type}, response)"
1083
+ if isinstance(excep.type, ModelType):
1084
+ if self.code_model.options["models_mode"] == "msrest":
1085
+ error_model_str = (
1086
+ f", model=self._deserialize("
1087
+ f"_models.{excep.type.serialization_type}, response)"
1088
+ )
1089
+ elif self.code_model.options["models_mode"] == "dpg":
1090
+ error_model_str = f", model=_deserialize(_models.{excep.type.name}, response.json())"
1073
1091
  error_format_str = (
1074
1092
  ", error_format=ARMErrorFormat"
1075
1093
  if self.code_model.options["azure_arm"]
@@ -1238,11 +1256,15 @@ class _PagingOperationSerializer(
1238
1256
  f"{'async ' if self.async_mode else ''}def extract_data(pipeline_response):"
1239
1257
  ]
1240
1258
  response = builder.responses[0]
1241
- deserialized = (
1242
- f'self._deserialize("{response.serialization_type}", pipeline_response)'
1243
- if self.code_model.options["models_mode"]
1244
- else "pipeline_response.http_response.json()"
1245
- )
1259
+ deserialized = "pipeline_response.http_response.json()"
1260
+ if self.code_model.options["models_mode"] == "msrest":
1261
+ deserialized = (
1262
+ f'self._deserialize("{response.serialization_type}", pipeline_response)'
1263
+ )
1264
+ elif self.code_model.options["models_mode"] == "dpg":
1265
+ deserialized = (
1266
+ f"_deserialize({response.serialization_type}, pipeline_response)"
1267
+ )
1246
1268
  retval.append(f" deserialized = {deserialized}")
1247
1269
  item_name = builder.item_name
1248
1270
  list_of_elem = (
@@ -125,11 +125,10 @@ class ClientSerializer:
125
125
  )
126
126
  else:
127
127
  client_models_value = "{} # type: Dict[str, Any]"
128
- if self.code_model.options["models_mode"]:
128
+ is_msrest_model = self.code_model.options["models_mode"] == "msrest"
129
+ if is_msrest_model:
129
130
  retval.append(f"client_models = {client_models_value}")
130
- client_models_str = (
131
- "client_models" if self.code_model.options["models_mode"] else ""
132
- )
131
+ client_models_str = "client_models" if is_msrest_model else ""
133
132
  retval.append(f"self._serialize = Serializer({client_models_str})")
134
133
  retval.append(f"self._deserialize = Deserializer({client_models_str})")
135
134
  if not self.code_model.options["client_side_validation"]:
@@ -121,6 +121,10 @@ class GeneralSerializer:
121
121
  template = self.env.get_template("serialization.py.jinja2")
122
122
  return template.render(code_model=self.code_model)
123
123
 
124
+ def serialize_model_base_file(self) -> str:
125
+ template = self.env.get_template("model_base.py.jinja2")
126
+ return template.render(code_model=self.code_model)
127
+
124
128
  def serialize_validation_file(self) -> str:
125
129
  template = self.env.get_template("validation.py.jinja2")
126
130
  return template.render(code_model=self.code_model)