@autorest/python 6.28.0 → 6.28.2

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 (44) hide show
  1. package/autorest/codegen.py +2 -2
  2. package/autorest/jsonrpc/__init__.py +2 -2
  3. package/autorest/m4reformatter/__init__.py +13 -13
  4. package/autorest/multiapi/templates/multiapi_service_client.py.jinja2 +1 -1
  5. package/generator/build/lib/pygen/codegen/models/code_model.py +5 -1
  6. package/generator/build/lib/pygen/codegen/models/combined_type.py +4 -3
  7. package/generator/build/lib/pygen/codegen/models/credential_types.py +4 -0
  8. package/generator/build/lib/pygen/codegen/models/operation.py +9 -3
  9. package/generator/build/lib/pygen/codegen/models/operation_group.py +26 -1
  10. package/generator/build/lib/pygen/codegen/models/paging_operation.py +1 -1
  11. package/generator/build/lib/pygen/codegen/models/property.py +2 -2
  12. package/generator/build/lib/pygen/codegen/serializers/__init__.py +22 -7
  13. package/generator/build/lib/pygen/codegen/serializers/builder_serializer.py +14 -3
  14. package/generator/build/lib/pygen/codegen/serializers/model_serializer.py +2 -1
  15. package/generator/build/lib/pygen/codegen/serializers/operation_groups_serializer.py +1 -0
  16. package/generator/build/lib/pygen/codegen/templates/model_base.py.jinja2 +61 -0
  17. package/generator/build/lib/pygen/codegen/templates/operation_group.py.jinja2 +4 -4
  18. package/generator/build/lib/pygen/codegen/templates/operation_groups_container.py.jinja2 +2 -0
  19. package/generator/build/lib/pygen/codegen/templates/serialization.py.jinja2 +39 -107
  20. package/generator/build/lib/pygen/preprocess/__init__.py +1 -1
  21. package/generator/dist/pygen-0.1.0-py3-none-any.whl +0 -0
  22. package/generator/pygen/codegen/models/code_model.py +5 -1
  23. package/generator/pygen/codegen/models/combined_type.py +4 -3
  24. package/generator/pygen/codegen/models/credential_types.py +4 -0
  25. package/generator/pygen/codegen/models/operation.py +9 -3
  26. package/generator/pygen/codegen/models/operation_group.py +26 -1
  27. package/generator/pygen/codegen/models/paging_operation.py +1 -1
  28. package/generator/pygen/codegen/models/property.py +2 -2
  29. package/generator/pygen/codegen/serializers/__init__.py +22 -7
  30. package/generator/pygen/codegen/serializers/builder_serializer.py +14 -3
  31. package/generator/pygen/codegen/serializers/model_serializer.py +2 -1
  32. package/generator/pygen/codegen/serializers/operation_groups_serializer.py +1 -0
  33. package/generator/pygen/codegen/templates/model_base.py.jinja2 +61 -0
  34. package/generator/pygen/codegen/templates/operation_group.py.jinja2 +4 -4
  35. package/generator/pygen/codegen/templates/operation_groups_container.py.jinja2 +2 -0
  36. package/generator/pygen/codegen/templates/serialization.py.jinja2 +39 -107
  37. package/generator/pygen/preprocess/__init__.py +1 -1
  38. package/package.json +2 -2
  39. package/scripts/__pycache__/venvtools.cpython-310.pyc +0 -0
  40. package/scripts/eng/mypy.ini +1 -1
  41. package/scripts/mypy.ini +1 -1
  42. package/scripts/prepare.py +2 -2
  43. package/scripts/start.py +2 -2
  44. package/scripts/venvtools.py +2 -2
@@ -40,7 +40,7 @@ class JinjaSerializerAutorest(JinjaSerializer, ReaderAndWriterAutorest):
40
40
  class CodeGeneratorAutorest(CodeGenerator, PluginAutorest):
41
41
  def get_options(self) -> Dict[str, Any]:
42
42
  if self._autorestapi.get_boolean_value("python3-only") is False:
43
- _LOGGER.warning("You have passed in --python3-only=False. We have force overriden this to True.")
43
+ _LOGGER.warning("You have passed in --python3-only=False. We have force overridden this to True.")
44
44
  if self._autorestapi.get_boolean_value("add-python3-operation-files"):
45
45
  _LOGGER.warning(
46
46
  "You have passed in --add-python3-operation-files. "
@@ -48,7 +48,7 @@ class CodeGeneratorAutorest(CodeGenerator, PluginAutorest):
48
48
  )
49
49
  if self._autorestapi.get_boolean_value("reformat-next-link"):
50
50
  _LOGGER.warning(
51
- "You have passed in --reformat-next-link. We have force overriden "
51
+ "You have passed in --reformat-next-link. We have force overridden "
52
52
  "this to False because we no longer reformat initial query parameters into next "
53
53
  "calls unless explicitly defined in the service definition."
54
54
  )
@@ -12,7 +12,7 @@ from pathlib import Path
12
12
 
13
13
 
14
14
  class Channel(Enum):
15
- # Information is considered the mildest of responses; not necesarily actionable.
15
+ # Information is considered the mildest of responses; not necessarily actionable.
16
16
  Information = "information"
17
17
 
18
18
  # Warnings are considered important for best practices, but not catastrophic in nature.
@@ -27,7 +27,7 @@ class Channel(Enum):
27
27
  # Verbose messages give the user additional clarity on the process.
28
28
  Verbose = "verbose"
29
29
 
30
- # Catastrophic failure, likely abending the process.
30
+ # Catastrophic failure, likely ending the process.
31
31
  Fatal = "fatal"
32
32
 
33
33
 
@@ -492,7 +492,7 @@ class M4Reformatter(YamlUpdatePluginAutorest): # pylint: disable=too-many-publi
492
492
  *,
493
493
  is_overload: bool = False,
494
494
  ) -> Dict[str, Any]:
495
- in_overriden = body_parameter["type"]["type"] == "combined" if body_parameter else False
495
+ in_overridden = body_parameter["type"]["type"] == "combined" if body_parameter else False
496
496
  abstract = False
497
497
  if body_parameter and (body_parameter.get("entries") or len(body_parameter["type"].get("types", [])) > 2):
498
498
  # this means it's formdata or urlencoded, or there are more than 2 types of body
@@ -507,7 +507,7 @@ class M4Reformatter(YamlUpdatePluginAutorest): # pylint: disable=too-many-publi
507
507
  yaml_data,
508
508
  body_parameter,
509
509
  in_overload=is_overload,
510
- in_overriden=in_overriden,
510
+ in_overridden=in_overridden,
511
511
  ),
512
512
  "bodyParameter": body_parameter,
513
513
  "responses": [update_response(r) for r in yaml_data.get("responses", [])],
@@ -723,7 +723,7 @@ class M4Reformatter(YamlUpdatePluginAutorest): # pylint: disable=too-many-publi
723
723
  request_media_types: List[str],
724
724
  *,
725
725
  in_overload: bool = False,
726
- in_overriden: bool = False,
726
+ in_overridden: bool = False,
727
727
  ) -> Dict[str, Any]:
728
728
  # override content type type to string
729
729
  if not body_parameter:
@@ -737,14 +737,14 @@ class M4Reformatter(YamlUpdatePluginAutorest): # pylint: disable=too-many-publi
737
737
  description = param["language"]["default"]["description"]
738
738
  if description and description[-1] != ".":
739
739
  description += "."
740
- if not (in_overriden or in_overload):
740
+ if not (in_overridden or in_overload):
741
741
  param["inDocstring"] = False
742
742
  elif in_overload:
743
743
  description += " Content type parameter for " f"{get_body_type_for_description(body_parameter)} body."
744
744
  if not in_overload or (body_parameter["type"]["type"] == "binary" and len(request_media_types) > 1):
745
745
  content_types = "'" + "', '".join(request_media_types) + "'"
746
746
  description += f" Known values are: {content_types}."
747
- if not in_overload and not in_overriden:
747
+ if not in_overload and not in_overridden:
748
748
  param["clientDefaultValue"] = body_parameter["defaultContentType"]
749
749
  param["language"]["default"]["description"] = description
750
750
  return param
@@ -758,7 +758,7 @@ class M4Reformatter(YamlUpdatePluginAutorest): # pylint: disable=too-many-publi
758
758
  request_media_types: List[str],
759
759
  *,
760
760
  in_overload: bool = False,
761
- in_overriden: bool = False,
761
+ in_overridden: bool = False,
762
762
  ) -> List[Dict[str, Any]]:
763
763
  retval: List[Dict[str, Any]] = []
764
764
  has_flattened_body = body_parameter and body_parameter.get("flattened")
@@ -785,9 +785,9 @@ class M4Reformatter(YamlUpdatePluginAutorest): # pylint: disable=too-many-publi
785
785
  body_parameter,
786
786
  request_media_types,
787
787
  in_overload=in_overload,
788
- in_overriden=in_overriden,
788
+ in_overridden=in_overridden,
789
789
  )
790
- updated_param = self.update_parameter(param, in_overload=in_overload, in_overriden=in_overriden)
790
+ updated_param = self.update_parameter(param, in_overload=in_overload, in_overridden=in_overridden)
791
791
  retval.append(updated_param)
792
792
  return retval
793
793
 
@@ -797,7 +797,7 @@ class M4Reformatter(YamlUpdatePluginAutorest): # pylint: disable=too-many-publi
797
797
  body_parameter: Optional[Dict[str, Any]],
798
798
  *,
799
799
  in_overload: bool = False,
800
- in_overriden: bool = False,
800
+ in_overridden: bool = False,
801
801
  ) -> List[Dict[str, Any]]:
802
802
  retval: List[Dict[str, Any]] = []
803
803
  seen_client_names: Set[str] = set()
@@ -812,7 +812,7 @@ class M4Reformatter(YamlUpdatePluginAutorest): # pylint: disable=too-many-publi
812
812
  groupers,
813
813
  request_media_types,
814
814
  in_overload=in_overload,
815
- in_overriden=in_overriden,
815
+ in_overridden=in_overridden,
816
816
  )
817
817
  )
818
818
  # now we handle content type and accept headers.
@@ -831,7 +831,7 @@ class M4Reformatter(YamlUpdatePluginAutorest): # pylint: disable=too-many-publi
831
831
  groupers,
832
832
  request_media_types,
833
833
  in_overload=in_overload,
834
- in_overriden=in_overriden,
834
+ in_overridden=in_overridden,
835
835
  )
836
836
  )
837
837
  all_params = (retval + [body_parameter]) if body_parameter else retval
@@ -853,7 +853,7 @@ class M4Reformatter(YamlUpdatePluginAutorest): # pylint: disable=too-many-publi
853
853
  *,
854
854
  override_client_name: Optional[str] = None,
855
855
  in_overload: bool = False,
856
- in_overriden: bool = False,
856
+ in_overridden: bool = False,
857
857
  ) -> Dict[str, Any]:
858
858
  param_base = self.update_parameter_base(yaml_data, override_client_name=override_client_name)
859
859
  type = get_type(yaml_data["schema"])
@@ -869,7 +869,7 @@ class M4Reformatter(YamlUpdatePluginAutorest): # pylint: disable=too-many-publi
869
869
  "inOverload": in_overload,
870
870
  "skipUrlEncoding": yaml_data.get("extensions", {}).get("x-ms-skip-url-encoding", False),
871
871
  "inDocstring": yaml_data.get("inDocstring", True),
872
- "inOverriden": in_overriden,
872
+ "inOverridden": in_overridden,
873
873
  "delimiter": update_parameter_delimiter(protocol_http.get("style")),
874
874
  }
875
875
  )
@@ -33,7 +33,7 @@ def __init__(
33
33
 
34
34
  class _SDKClient(object):
35
35
  def __init__(self, *args, **kwargs):
36
- """This is a fake class to support current implemetation of MultiApiClientMixin."
36
+ """This is a fake class to support current implementation of MultiApiClientMixin."
37
37
  Will be removed in final version of multiapi azure-core based client
38
38
  """
39
39
  pass
@@ -313,7 +313,7 @@ class CodeModel: # pylint: disable=too-many-public-methods, disable=too-many-in
313
313
  :param int schema_id: The yaml id of the schema
314
314
  :return: If created, we return the created schema, otherwise, we throw.
315
315
  :rtype: ~autorest.models.BaseType
316
- :raises: KeyError if schema is not found
316
+ :raises KeyError: if schema is not found
317
317
  """
318
318
  try:
319
319
  return next(type for id, type in self.types_map.items() if id == schema_id)
@@ -402,3 +402,7 @@ class CodeModel: # pylint: disable=too-many-public-methods, disable=too-many-in
402
402
  @property
403
403
  def is_legacy(self) -> bool:
404
404
  return _is_legacy(self.options)
405
+
406
+ @staticmethod
407
+ def has_non_json_models(models: List[ModelType]) -> bool:
408
+ return any(m for m in models if m.base != "json")
@@ -53,9 +53,10 @@ class CombinedType(BaseType):
53
53
  return self.yaml_data.get("clientDefaultValue")
54
54
 
55
55
  def description(self, *, is_operation_file: bool) -> str:
56
- if len(self.types) == 2:
57
- return f"Is either a {self.types[0].type_description} type or a {self.types[1].type_description} type."
58
- return f"Is one of the following types: {', '.join([t.type_description for t in self.types])}"
56
+ type_descriptions = list({t.type_description: None for t in self.types}.keys())
57
+ if len(type_descriptions) == 2:
58
+ return f"Is either a {type_descriptions[0]} type or a {type_descriptions[1]} type."
59
+ return f"Is one of the following types: {', '.join(t for t in type_descriptions)}"
59
60
 
60
61
  def docstring_text(self, **kwargs: Any) -> str:
61
62
  return " or ".join(t.docstring_text(**kwargs) for t in self.types)
@@ -198,6 +198,10 @@ class KeyCredentialType(CredentialType[KeyCredentialPolicyType]):
198
198
  def type_annotation(self, **kwargs: Any) -> str:
199
199
  return self.policy.credential_name
200
200
 
201
+ @property
202
+ def type_description(self) -> str:
203
+ return "key credential"
204
+
201
205
  @property
202
206
  def instance_check_template(self) -> str:
203
207
  return "isinstance({}, " + f"{self.policy.credential_name})"
@@ -35,6 +35,7 @@ from .parameter import (
35
35
  )
36
36
  from .parameter_list import ParameterList
37
37
  from .model_type import ModelType
38
+ from .primitive_types import BinaryIteratorType, BinaryType
38
39
  from .base import BaseType
39
40
  from .combined_type import CombinedType
40
41
  from .request_builder import OverloadedRequestBuilder, RequestBuilder
@@ -313,6 +314,10 @@ class OperationBase( # pylint: disable=too-many-public-methods,too-many-instanc
313
314
  )
314
315
  return file_import
315
316
 
317
+ @property
318
+ def need_deserialize(self) -> bool:
319
+ return any(r.type and not isinstance(r.type, BinaryIteratorType) for r in self.responses)
320
+
316
321
  def imports( # pylint: disable=too-many-branches, disable=too-many-statements
317
322
  self, async_mode: bool, **kwargs: Any
318
323
  ) -> FileImport:
@@ -432,7 +437,8 @@ class OperationBase( # pylint: disable=too-many-public-methods,too-many-instanc
432
437
  file_import.add_submodule_import("typing", "overload", ImportType.STDLIB)
433
438
  if self.code_model.options["models_mode"] == "dpg":
434
439
  relative_path = self.code_model.get_relative_import_path(serialize_namespace, module_name="_model_base")
435
- if self.parameters.has_body:
440
+ body_param = self.parameters.body_parameter if self.parameters.has_body else None
441
+ if body_param and not isinstance(body_param.type, BinaryType):
436
442
  if self.has_form_data_body:
437
443
  file_import.add_submodule_import(
438
444
  self.code_model.get_relative_import_path(serialize_namespace), "_model_base", ImportType.LOCAL
@@ -450,9 +456,9 @@ class OperationBase( # pylint: disable=too-many-public-methods,too-many-instanc
450
456
  ImportType.LOCAL,
451
457
  )
452
458
  file_import.add_import("json", ImportType.STDLIB)
453
- if any(xml_serializable(str(r.default_content_type)) for r in self.responses):
459
+ if any(xml_serializable(str(r.default_content_type)) for r in self.responses + self.exceptions):
454
460
  file_import.add_submodule_import(relative_path, "_deserialize_xml", ImportType.LOCAL)
455
- elif any(r.type for r in self.responses):
461
+ elif self.need_deserialize:
456
462
  file_import.add_submodule_import(relative_path, "_deserialize", ImportType.LOCAL)
457
463
  if self.default_error_deserialization or self.non_default_errors:
458
464
  file_import.add_submodule_import(relative_path, "_failsafe_deserialize", ImportType.LOCAL)
@@ -9,7 +9,7 @@ from .utils import OrderedSet
9
9
 
10
10
  from .base import BaseModel
11
11
  from .operation import get_operation
12
- from .imports import FileImport, ImportType, TypingSection
12
+ from .imports import FileImport, ImportType, TypingSection, MsrestImportType
13
13
  from .utils import add_to_pylint_disable, NamespaceType
14
14
  from .lro_operation import LROOperation
15
15
  from .lro_paging_operation import LROPagingOperation
@@ -152,6 +152,31 @@ class OperationGroup(BaseModel):
152
152
  f"{self.client.name}MixinABC",
153
153
  ImportType.LOCAL,
154
154
  )
155
+ else:
156
+ file_import.add_submodule_import(
157
+ "" if self.code_model.is_azure_flavor else "runtime",
158
+ f"{'Async' if async_mode else ''}PipelineClient",
159
+ ImportType.SDKCORE,
160
+ )
161
+ file_import.add_submodule_import(
162
+ self.code_model.get_relative_import_path(
163
+ serialize_namespace,
164
+ self.code_model.get_imported_namespace_for_client(self.client.client_namespace, async_mode),
165
+ module_name="_configuration",
166
+ ),
167
+ f"{self.client.name}Configuration",
168
+ ImportType.LOCAL,
169
+ )
170
+ file_import.add_msrest_import(
171
+ serialize_namespace=kwargs.get("serialize_namespace", self.code_model.namespace),
172
+ msrest_import_type=MsrestImportType.Serializer,
173
+ typing_section=TypingSection.REGULAR,
174
+ )
175
+ file_import.add_msrest_import(
176
+ serialize_namespace=kwargs.get("serialize_namespace", self.code_model.namespace),
177
+ msrest_import_type=MsrestImportType.SerializerDeserializer,
178
+ typing_section=TypingSection.REGULAR,
179
+ )
155
180
  if self.has_abstract_operations:
156
181
  file_import.add_submodule_import(
157
182
  # raise_if_not_implemented is always defined in _vendor of top namespace
@@ -150,7 +150,7 @@ class PagingOperationBase(OperationBase[PagingResponseType]):
150
150
  if self.code_model.options["models_mode"] == "dpg":
151
151
  relative_path = self.code_model.get_relative_import_path(serialize_namespace, module_name="_model_base")
152
152
  file_import.merge(self.item_type.imports(**kwargs))
153
- if self.default_error_deserialization or any(r.type for r in self.responses):
153
+ if self.default_error_deserialization or self.need_deserialize:
154
154
  file_import.add_submodule_import(relative_path, "_deserialize", ImportType.LOCAL)
155
155
  return file_import
156
156
 
@@ -102,7 +102,7 @@ class Property(BaseModel): # pylint: disable=too-many-instance-attributes
102
102
  if self.is_base_discriminator:
103
103
  return "str"
104
104
  types_type_annotation = self.type.type_annotation(is_operation_file=is_operation_file, **kwargs)
105
- if self.optional and self.client_default_value is None:
105
+ if (self.optional and self.client_default_value is None) or self.readonly:
106
106
  return f"Optional[{types_type_annotation}]"
107
107
  return types_type_annotation
108
108
 
@@ -144,7 +144,7 @@ class Property(BaseModel): # pylint: disable=too-many-instance-attributes
144
144
  if self.is_discriminator and isinstance(self.type, EnumType):
145
145
  return file_import
146
146
  file_import.merge(self.type.imports(**kwargs))
147
- if self.optional and self.client_default_value is None:
147
+ if (self.optional and self.client_default_value is None) or self.readonly:
148
148
  file_import.add_submodule_import("typing", "Optional", ImportType.STDLIB)
149
149
  if self.code_model.options["models_mode"] == "dpg":
150
150
  serialize_namespace = kwargs.get("serialize_namespace", self.code_model.namespace)
@@ -130,10 +130,10 @@ class JinjaSerializer(ReaderAndWriter):
130
130
  if self.code_model.options["package_mode"]:
131
131
  self._serialize_and_write_package_files(client_namespace)
132
132
 
133
- # write apiview_mapping_python.json
133
+ # write apiview-properties.json
134
134
  if self.code_model.options.get("emit_cross_language_definition_file"):
135
135
  self.write_file(
136
- exec_path / Path("apiview_mapping_python.json"),
136
+ exec_path / Path("apiview-properties.json"),
137
137
  general_serializer.serialize_cross_language_definition_file(),
138
138
  )
139
139
 
@@ -159,7 +159,9 @@ class JinjaSerializer(ReaderAndWriter):
159
159
  self._serialize_and_write_top_level_folder(env=env, namespace=client_namespace)
160
160
 
161
161
  # add models folder if there are models in this namespace
162
- if (client_namespace_type.models or client_namespace_type.enums) and self.code_model.options["models_mode"]:
162
+ if (
163
+ self.code_model.has_non_json_models(client_namespace_type.models) or client_namespace_type.enums
164
+ ) and self.code_model.options["models_mode"]:
163
165
  self._serialize_and_write_models_folder(
164
166
  env=env,
165
167
  namespace=client_namespace,
@@ -181,6 +183,14 @@ class JinjaSerializer(ReaderAndWriter):
181
183
  if self.code_model.options["multiapi"]:
182
184
  self._serialize_and_write_metadata(env=env, namespace=client_namespace)
183
185
 
186
+ # if there are only operations under this namespace, we need to add general __init__.py into `aio` folder
187
+ # to make sure all generated files could be packed into .zip/.whl/.tgz package
188
+ if not client_namespace_type.clients and client_namespace_type.operation_groups and self.has_aio_folder:
189
+ self.write_file(
190
+ exec_path / Path("aio/__init__.py"),
191
+ general_serializer.serialize_pkgutil_init_file(),
192
+ )
193
+
184
194
  def _serialize_and_write_package_files(self, client_namespace: str) -> None:
185
195
  root_of_sdk = self.exec_path(client_namespace)
186
196
  if self.code_model.options["package_mode"] in VALID_PACKAGE_MODE:
@@ -228,9 +238,9 @@ class JinjaSerializer(ReaderAndWriter):
228
238
  self, env: Environment, namespace: str, models: List[ModelType], enums: List[EnumType]
229
239
  ) -> None:
230
240
  # Write the models folder
231
- models_path = self.exec_path(namespace + ".models")
241
+ models_path = self.exec_path(namespace) / "models"
232
242
  serializer = DpgModelSerializer if self.code_model.options["models_mode"] == "dpg" else MsrestModelSerializer
233
- if models:
243
+ if self.code_model.has_non_json_models(models):
234
244
  self.write_file(
235
245
  models_path / Path(f"{self.code_model.models_filename}.py"),
236
246
  serializer(code_model=self.code_model, env=env, client_namespace=namespace, models=models).serialize(),
@@ -469,7 +479,12 @@ class JinjaSerializer(ReaderAndWriter):
469
479
  else Path(".")
470
480
  )
471
481
 
482
+ def exec_path_for_test_sample(self, namespace: str) -> Path:
483
+ return self.exec_path_compensation / Path(*namespace.split("."))
484
+
472
485
  def exec_path(self, namespace: str) -> Path:
486
+ if self.code_model.options["no_namespace_folders"] and not self.code_model.options["multiapi"]:
487
+ return Path(".")
473
488
  return self.exec_path_compensation / Path(*namespace.split("."))
474
489
 
475
490
  @property
@@ -482,7 +497,7 @@ class JinjaSerializer(ReaderAndWriter):
482
497
  return Path("")
483
498
 
484
499
  def _serialize_and_write_sample(self, env: Environment, namespace: str):
485
- out_path = self.exec_path(namespace) / Path("generated_samples")
500
+ out_path = self.exec_path_for_test_sample(namespace) / Path("generated_samples")
486
501
  for client in self.code_model.clients:
487
502
  for op_group in client.operation_groups:
488
503
  for operation in op_group.operations:
@@ -516,7 +531,7 @@ class JinjaSerializer(ReaderAndWriter):
516
531
 
517
532
  def _serialize_and_write_test(self, env: Environment, namespace: str):
518
533
  self.code_model.for_test = True
519
- out_path = self.exec_path(namespace) / Path("generated_tests")
534
+ out_path = self.exec_path_for_test_sample(namespace) / Path("generated_tests")
520
535
  general_serializer = TestGeneralSerializer(code_model=self.code_model, env=env)
521
536
  self.write_file(out_path / "conftest.py", general_serializer.serialize_conftest())
522
537
  if not self.code_model.options["azure_arm"]:
@@ -498,7 +498,11 @@ class RequestBuilderSerializer(_BuilderBaseSerializer[RequestBuilderType]):
498
498
  url_value = _escape_str(builder.url)
499
499
  else:
500
500
  url_value = f'kwargs.pop("template_url", {_escape_str(builder.url)})'
501
- return f"_url = {url_value}{' # pylint: disable=line-too-long' if len(url_value) > 114 else ''}"
501
+ result = "_url = " + url_value
502
+ # there will be always 4 spaces before the url
503
+ if len(result) + 4 > 120:
504
+ return result + " # pylint: disable=line-too-long"
505
+ return result
502
506
 
503
507
 
504
508
  ############################## NORMAL OPERATIONS ##############################
@@ -1001,7 +1005,7 @@ class _OperationSerializer(_BuilderBaseSerializer[OperationType]):
1001
1005
  retval.extend(deserialize_code)
1002
1006
  return retval
1003
1007
 
1004
- def handle_error_response(self, builder: OperationType) -> List[str]:
1008
+ def handle_error_response(self, builder: OperationType) -> List[str]: # pylint: disable=too-many-statements, too-many-branches
1005
1009
  async_await = "await " if self.async_mode else ""
1006
1010
  retval = [f"if response.status_code not in {str(builder.success_status_codes)}:"]
1007
1011
  response_read = [
@@ -1075,7 +1079,14 @@ class _OperationSerializer(_BuilderBaseSerializer[OperationType]):
1075
1079
  is_operation_file=True, skip_quote=True, serialize_namespace=self.serialize_namespace
1076
1080
  )
1077
1081
  if self.code_model.options["models_mode"] == "dpg":
1078
- retval.append(f" error = _failsafe_deserialize({type_annotation}, response.json())")
1082
+ if xml_serializable(str(e.default_content_type)):
1083
+ retval.append(
1084
+ f" error = _failsafe_deserialize_xml({type_annotation}, response.text())"
1085
+ )
1086
+ else:
1087
+ retval.append(
1088
+ f" error = _failsafe_deserialize({type_annotation}, response.json())"
1089
+ )
1079
1090
  else:
1080
1091
  retval.append(
1081
1092
  f" error = self._deserialize.failsafe_deserialize({type_annotation}, "
@@ -192,7 +192,8 @@ class MsrestModelSerializer(_ModelSerializer):
192
192
  if prop.is_discriminator:
193
193
  init_args.append(self.initialize_discriminator_property(model, prop))
194
194
  elif prop.readonly:
195
- init_args.append(f"self.{prop.client_name} = None")
195
+ # we want typing for readonly since typing isn't provided from the command line
196
+ init_args.append(f"self.{prop.client_name}: {prop.type_annotation()} = None")
196
197
  elif not prop.constant:
197
198
  init_args.append(f"self.{prop.client_name} = {prop.client_name}")
198
199
  return init_args
@@ -89,4 +89,5 @@ class OperationGroupsSerializer(BaseSerializer):
89
89
  client_namespace=self.client_namespace,
90
90
  ),
91
91
  get_request_builders=self._get_request_builders,
92
+ need_declare_serializer=any(operation_group.operations for operation_group in self.operation_groups),
92
93
  )
@@ -372,15 +372,34 @@ class _MyMutableMapping(MutableMapping[str, typing.Any]): # pylint: disable=uns
372
372
  return not self.__eq__(other)
373
373
 
374
374
  def keys(self) -> typing.KeysView[str]:
375
+ """
376
+ :returns: a set-like object providing a view on D's keys
377
+ :rtype: ~typing.KeysView
378
+ """
375
379
  return self._data.keys()
376
380
 
377
381
  def values(self) -> typing.ValuesView[typing.Any]:
382
+ """
383
+ :returns: an object providing a view on D's values
384
+ :rtype: ~typing.ValuesView
385
+ """
378
386
  return self._data.values()
379
387
 
380
388
  def items(self) -> typing.ItemsView[str, typing.Any]:
389
+ """
390
+ :returns: set-like object providing a view on D's items
391
+ :rtype: ~typing.ItemsView
392
+ """
381
393
  return self._data.items()
382
394
 
383
395
  def get(self, key: str, default: typing.Any = None) -> typing.Any:
396
+ """
397
+ Get the value for key if key is in the dictionary, else default.
398
+ :param str key: The key to look up.
399
+ :param any default: The value to return if key is not in the dictionary. Defaults to None
400
+ :returns: D[k] if k in D, else d.
401
+ :rtype: any
402
+ """
384
403
  try:
385
404
  return self[key]
386
405
  except KeyError:
@@ -396,17 +415,38 @@ class _MyMutableMapping(MutableMapping[str, typing.Any]): # pylint: disable=uns
396
415
  def pop(self, key: str, default: typing.Any) -> typing.Any: ...
397
416
 
398
417
  def pop(self, key: str, default: typing.Any = _UNSET) -> typing.Any:
418
+ """
419
+ Removes specified key and return the corresponding value.
420
+ :param str key: The key to pop.
421
+ :param any default: The value to return if key is not in the dictionary
422
+ :returns: The value corresponding to the key.
423
+ :rtype: any
424
+ :raises KeyError: If key is not found and default is not given.
425
+ """
399
426
  if default is _UNSET:
400
427
  return self._data.pop(key)
401
428
  return self._data.pop(key, default)
402
429
 
403
430
  def popitem(self) -> typing.Tuple[str, typing.Any]:
431
+ """
432
+ Removes and returns some (key, value) pair
433
+ :returns: The (key, value) pair.
434
+ :rtype: tuple
435
+ :raises KeyError: if D is empty.
436
+ """
404
437
  return self._data.popitem()
405
438
 
406
439
  def clear(self) -> None:
440
+ """
441
+ Remove all items from D.
442
+ """
407
443
  self._data.clear()
408
444
 
409
445
  def update(self, *args: typing.Any, **kwargs: typing.Any) -> None:
446
+ """
447
+ Updates D from mapping/iterable E and F.
448
+ :param any args: Either a mapping object or an iterable of key-value pairs.
449
+ """
410
450
  self._data.update(*args, **kwargs)
411
451
 
412
452
  @typing.overload
@@ -416,6 +456,13 @@ class _MyMutableMapping(MutableMapping[str, typing.Any]): # pylint: disable=uns
416
456
  def setdefault(self, key: str, default: typing.Any) -> typing.Any: ...
417
457
 
418
458
  def setdefault(self, key: str, default: typing.Any = _UNSET) -> typing.Any:
459
+ """
460
+ Same as calling D.get(k, d), and setting D[k]=d if k not found
461
+ :param str key: The key to look up.
462
+ :param any default: The value to set if key is not in the dictionary
463
+ :returns: D[k] if k in D, else d.
464
+ :rtype: any
465
+ """
419
466
  if default is _UNSET:
420
467
  return self._data.setdefault(key)
421
468
  return self._data.setdefault(key, default)
@@ -909,6 +956,20 @@ def _failsafe_deserialize(
909
956
  return None
910
957
 
911
958
 
959
+ def _failsafe_deserialize_xml(
960
+ deserializer: typing.Any,
961
+ value: typing.Any,
962
+ ) -> typing.Any:
963
+ try:
964
+ return _deserialize_xml(deserializer, value)
965
+ except DeserializationError:
966
+ _LOGGER.warning(
967
+ "Ran into a deserialization error. Ignoring since this is failsafe deserialization",
968
+ exc_info=True
969
+ )
970
+ return None
971
+
972
+
912
973
  class _RestField:
913
974
  def __init__(
914
975
  self,
@@ -31,10 +31,10 @@ class {{ operation_group.class_name }}: {{ operation_group.pylint_disable() }}
31
31
  {% endif %}
32
32
  def __init__(self, *args, **kwargs){{ return_none_type_annotation }}:
33
33
  input_args = list(args)
34
- self._client = input_args.pop(0) if input_args else kwargs.pop("client")
35
- self._config = input_args.pop(0) if input_args else kwargs.pop("config")
36
- self._serialize = input_args.pop(0) if input_args else kwargs.pop("serializer")
37
- self._deserialize = input_args.pop(0) if input_args else kwargs.pop("deserializer")
34
+ self._client: {{ 'Async' if async_mode else ''}}PipelineClient = input_args.pop(0) if input_args else kwargs.pop("client")
35
+ self._config: {{ operation_group.client.name }}Configuration = input_args.pop(0) if input_args else kwargs.pop("config")
36
+ self._serialize: Serializer = input_args.pop(0) if input_args else kwargs.pop("serializer")
37
+ self._deserialize: Deserializer = input_args.pop(0) if input_args else kwargs.pop("deserializer")
38
38
  {% if code_model.options["multiapi"] %}
39
39
  self._api_version = input_args.pop(0) if input_args else kwargs.pop("api_version")
40
40
  {% endif %}
@@ -6,7 +6,9 @@
6
6
  {{ imports }}
7
7
  {{ unset }}
8
8
  {% if code_model.options["builders_visibility"] == "embedded" and not async_mode %}
9
+ {% if need_declare_serializer %}
9
10
  {{ op_tools.declare_serializer(code_model) }}
11
+ {% endif %}
10
12
  {% for operation_group in operation_groups %}
11
13
  {% for request_builder in get_request_builders(operation_group) %}
12
14