@autorest/python 5.14.0 → 5.15.0

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 (58) hide show
  1. package/ChangeLog.md +29 -0
  2. package/autorest/codegen/__init__.py +87 -47
  3. package/autorest/codegen/models/base_schema.py +2 -6
  4. package/autorest/codegen/models/client.py +6 -0
  5. package/autorest/codegen/models/code_model.py +40 -74
  6. package/autorest/codegen/models/constant_schema.py +7 -3
  7. package/autorest/codegen/models/credential_model.py +47 -0
  8. package/autorest/codegen/models/credential_schema.py +5 -4
  9. package/autorest/codegen/models/dictionary_schema.py +7 -7
  10. package/autorest/codegen/models/enum_schema.py +8 -39
  11. package/autorest/codegen/models/imports.py +3 -1
  12. package/autorest/codegen/models/list_schema.py +18 -8
  13. package/autorest/codegen/models/lro_operation.py +3 -3
  14. package/autorest/codegen/models/lro_paging_operation.py +3 -3
  15. package/autorest/codegen/models/object_schema.py +17 -13
  16. package/autorest/codegen/models/operation.py +27 -6
  17. package/autorest/codegen/models/operation_group.py +7 -2
  18. package/autorest/codegen/models/paging_operation.py +3 -3
  19. package/autorest/codegen/models/parameter.py +39 -15
  20. package/autorest/codegen/models/parameter_list.py +1 -1
  21. package/autorest/codegen/models/primitive_schemas.py +15 -25
  22. package/autorest/codegen/models/property.py +5 -5
  23. package/autorest/codegen/models/request_builder.py +4 -4
  24. package/autorest/codegen/models/request_builder_parameter.py +12 -5
  25. package/autorest/codegen/models/schema_response.py +23 -10
  26. package/autorest/codegen/models/utils.py +20 -0
  27. package/autorest/codegen/serializers/__init__.py +49 -25
  28. package/autorest/codegen/serializers/builder_serializer.py +79 -37
  29. package/autorest/codegen/serializers/client_serializer.py +16 -6
  30. package/autorest/codegen/serializers/general_serializer.py +24 -3
  31. package/autorest/codegen/serializers/import_serializer.py +1 -1
  32. package/autorest/codegen/serializers/metadata_serializer.py +1 -1
  33. package/autorest/codegen/serializers/model_base_serializer.py +8 -0
  34. package/autorest/codegen/serializers/model_python3_serializer.py +2 -2
  35. package/autorest/codegen/serializers/operation_groups_serializer.py +1 -0
  36. package/autorest/codegen/serializers/patch_serializer.py +12 -3
  37. package/autorest/codegen/serializers/utils.py +29 -4
  38. package/autorest/codegen/templates/config.py.jinja2 +4 -4
  39. package/autorest/codegen/templates/enum.py.jinja2 +1 -1
  40. package/autorest/codegen/templates/enum_container.py.jinja2 +0 -1
  41. package/autorest/codegen/templates/init.py.jinja2 +9 -6
  42. package/autorest/codegen/templates/keywords.jinja2 +14 -1
  43. package/autorest/codegen/templates/lro_operation.py.jinja2 +1 -1
  44. package/autorest/codegen/templates/lro_paging_operation.py.jinja2 +1 -1
  45. package/autorest/codegen/templates/metadata.json.jinja2 +3 -3
  46. package/autorest/codegen/templates/model.py.jinja2 +1 -6
  47. package/autorest/codegen/templates/model_init.py.jinja2 +7 -4
  48. package/autorest/codegen/templates/operation.py.jinja2 +2 -3
  49. package/autorest/codegen/templates/operation_group.py.jinja2 +12 -5
  50. package/autorest/codegen/templates/operation_groups_container.py.jinja2 +0 -1
  51. package/autorest/codegen/templates/operations_folder_init.py.jinja2 +4 -0
  52. package/autorest/codegen/templates/paging_operation.py.jinja2 +1 -1
  53. package/autorest/codegen/templates/patch.py.jinja2 +18 -29
  54. package/autorest/codegen/templates/request_builder.py.jinja2 +4 -6
  55. package/autorest/codegen/templates/vendor.py.jinja2 +12 -2
  56. package/autorest/multiapi/models/imports.py +21 -11
  57. package/autorest/multiapi/serializers/import_serializer.py +3 -1
  58. package/package.json +2 -2
@@ -110,12 +110,6 @@ def _serialize_files_and_data_body(builder, param_name: str) -> List[str]:
110
110
  retval.append("}")
111
111
  return retval
112
112
 
113
- def _pop_parameters_kwarg(
114
- function_name: str,
115
- kwarg_name: str,
116
- ) -> str:
117
- return f'_{function_name}_parameters = kwargs.pop("{kwarg_name}", {{}}) # type: Dict[str, Any]'
118
-
119
113
  def _serialize_grouped_body(builder) -> List[str]:
120
114
  retval: List[str] = []
121
115
  for grouped_parameter in builder.parameters.grouped:
@@ -165,7 +159,7 @@ def _content_type_docstring(builder) -> str:
165
159
  ).default_value_declaration
166
160
  return (
167
161
  ":keyword content_type: Media type of the body sent to the API. " +
168
- f"Possible values are: {possible_values_str}. " +
162
+ f"Known values are: {possible_values_str}. " +
169
163
  f"Default value is {default_value}."
170
164
  )
171
165
 
@@ -411,10 +405,11 @@ class _BuilderBaseSerializer(_BuilderSerializerProtocol): # pylint: disable=abs
411
405
  ...
412
406
 
413
407
  def _serialize_parameter(
414
- self, param: Parameter, function_name: str
408
+ self, param: Parameter, kwarg_name: str
415
409
  ) -> List[str]:
416
- set_parameter = "_{}_parameters['{}'] = {}".format(
417
- function_name,
410
+ function_name = "header" if kwarg_name == "headers" else "query"
411
+ set_parameter = "_{}['{}'] = {}".format(
412
+ kwarg_name,
418
413
  param.rest_api_name,
419
414
  utils.build_serialize_data_call(param, function_name, self.serializer_name)
420
415
  )
@@ -434,10 +429,6 @@ class _BuilderBaseSerializer(_BuilderSerializerProtocol): # pylint: disable=abs
434
429
  template.extend(f"response.json() == {response_body}".splitlines())
435
430
  return template
436
431
 
437
-
438
- def pop_kwargs_from_signature(self, builder) -> List[str]:
439
- return utils.pop_kwargs_from_signature(self._get_kwargs_to_pop(builder))
440
-
441
432
  def serialize_path(self, builder) -> List[str]:
442
433
  return utils.serialize_path(builder.parameters.path, self.serializer_name)
443
434
 
@@ -463,6 +454,21 @@ class _RequestBuilderBaseSerializer(_BuilderBaseSerializer): # pylint: disable=
463
454
  def serializer_name(self) -> str:
464
455
  return "_SERIALIZER"
465
456
 
457
+ @staticmethod
458
+ def declare_non_inputtable_constants(builder) -> List[str]:
459
+ def _get_value(param: Parameter):
460
+ if param.location in [ParameterLocation.Header, ParameterLocation.Query]:
461
+ kwarg_dict = "headers" if param.location == ParameterLocation.Header else "params"
462
+ return f"_{kwarg_dict}.pop('{param.rest_api_name}', {param.constant_declaration})"
463
+ return f"{param.constant_declaration}"
464
+ return [
465
+ f"{p.serialized_name} = {_get_value(p)}"
466
+ for p in builder.parameters.constant
467
+ if p.original_parameter is None and
468
+ p.in_method_code and
469
+ not p.in_method_signature
470
+ ]
471
+
466
472
  def want_example_template(self, builder) -> bool:
467
473
  if self.code_model.options["builders_visibility"] != "public":
468
474
  return False # if we're not exposing rest layer, don't need to generate
@@ -507,14 +513,24 @@ class _RequestBuilderBaseSerializer(_BuilderBaseSerializer): # pylint: disable=
507
513
  def _body_params_to_pass_to_request_creation(self, builder) -> List[str]:
508
514
  ...
509
515
 
516
+ def pop_kwargs_from_signature(self, builder) -> List[str]:
517
+ return utils.pop_kwargs_from_signature(
518
+ self._get_kwargs_to_pop(builder),
519
+ check_kwarg_dict=True,
520
+ pop_headers_kwarg=utils.PopKwargType.CASE_INSENSITIVE if bool(builder.parameters.headers)
521
+ else utils.PopKwargType.NO,
522
+ pop_params_kwarg=utils.PopKwargType.CASE_INSENSITIVE if bool(builder.parameters.query)
523
+ else utils.PopKwargType.NO,
524
+ )
525
+
510
526
  def create_http_request(self, builder) -> List[str]:
511
527
  retval = ["return HttpRequest("]
512
528
  retval.append(f' method="{builder.method}",')
513
529
  retval.append(" url=_url,")
514
530
  if builder.parameters.query:
515
- retval.append(" params=_query_parameters,")
531
+ retval.append(" params=_params,")
516
532
  if builder.parameters.headers:
517
- retval.append(" headers=_header_parameters,")
533
+ retval.append(" headers=_headers,")
518
534
  if builder.parameters.has_body:
519
535
  retval.extend([
520
536
  f" {body_kwarg}={body_kwarg},"
@@ -526,21 +542,19 @@ class _RequestBuilderBaseSerializer(_BuilderBaseSerializer): # pylint: disable=
526
542
 
527
543
  def serialize_headers(self, builder) -> List[str]:
528
544
  retval = ["# Construct headers"]
529
- retval.append(_pop_parameters_kwarg("header", "headers"))
530
545
  for parameter in builder.parameters.headers:
531
546
  retval.extend(self._serialize_parameter(
532
547
  parameter,
533
- function_name="header",
548
+ kwarg_name="headers",
534
549
  ))
535
550
  return retval
536
551
 
537
552
  def serialize_query(self, builder) -> List[str]:
538
553
  retval = ["# Construct parameters"]
539
- retval.append(_pop_parameters_kwarg("query", "params"))
540
554
  for parameter in builder.parameters.query:
541
555
  retval.extend(self._serialize_parameter(
542
556
  parameter,
543
- function_name="query",
557
+ kwarg_name="params",
544
558
  ))
545
559
  return retval
546
560
 
@@ -644,7 +658,7 @@ class _OperationBaseSerializer(_BuilderBaseSerializer): # pylint: disable=abstr
644
658
  return "bool"
645
659
  response_body_annotations: OrderedSet[str] = {}
646
660
  for response in [r for r in builder.responses if r.has_body]:
647
- response_body_annotations[response.operation_type_annotation] = None
661
+ response_body_annotations[response.type_annotation(is_operation_file=True)] = None
648
662
  response_str = ", ".join(response_body_annotations.keys()) or "None"
649
663
  if len(response_body_annotations) > 1:
650
664
  response_str = f"Union[{response_str}]"
@@ -652,6 +666,19 @@ class _OperationBaseSerializer(_BuilderBaseSerializer): # pylint: disable=abstr
652
666
  response_str = f"Optional[{response_str}]"
653
667
  return response_str
654
668
 
669
+ def pop_kwargs_from_signature(self, builder) -> List[str]:
670
+ kwargs_to_pop = self._get_kwargs_to_pop(builder)
671
+ kwargs = utils.pop_kwargs_from_signature(
672
+ kwargs_to_pop,
673
+ check_kwarg_dict=True,
674
+ pop_headers_kwarg=utils.PopKwargType.CASE_INSENSITIVE if builder.has_kwargs_to_pop_with_default(
675
+ kwargs_to_pop, ParameterLocation.Header) else utils.PopKwargType.SIMPLE,
676
+ pop_params_kwarg=utils.PopKwargType.CASE_INSENSITIVE if builder.has_kwargs_to_pop_with_default(
677
+ kwargs_to_pop, ParameterLocation.Query) else utils.PopKwargType.SIMPLE,
678
+ )
679
+ kwargs.append(f"cls = kwargs.pop('cls', None) {self.cls_type_annotation(builder)}")
680
+ return kwargs
681
+
655
682
  def cls_type_annotation(self, builder) -> str:
656
683
  return f"# type: ClsType[{self._response_type_annotation(builder, modify_if_head_as_boolean=False)}]"
657
684
 
@@ -780,6 +807,7 @@ class _OperationBaseSerializer(_BuilderBaseSerializer): # pylint: disable=abstr
780
807
  if len(body_kwargs) == 1:
781
808
  retval.extend(self._set_body_content_kwarg(builder, builder.parameters.body[0], body_kwargs[0]))
782
809
  else:
810
+ retval.append('content_type = content_type or ""')
783
811
  for idx, body_kwarg in enumerate(body_kwargs):
784
812
  body_param = next(
785
813
  b for b in builder_params
@@ -854,6 +882,8 @@ class _OperationBaseSerializer(_BuilderBaseSerializer): # pylint: disable=abstr
854
882
  if not self.code_model.options["version_tolerant"]:
855
883
  template_url = template_url or f"self.{builder.name}.metadata['url']"
856
884
  retval.append(f" template_url={template_url},")
885
+ retval.append(' headers=_headers,')
886
+ retval.append(' params=_params,')
857
887
  retval.append(f")")
858
888
  if not self.code_model.options["version_tolerant"]:
859
889
  pass_files = ""
@@ -866,7 +896,7 @@ class _OperationBaseSerializer(_BuilderBaseSerializer): # pylint: disable=abstr
866
896
  if self.code_model.options["version_tolerant"] and template_url:
867
897
  url_to_format = template_url
868
898
  retval.append(
869
- "request.url = self._client.format_url({}{})".format(
899
+ "request.url = self._client.format_url({}{}) # type: ignore".format(
870
900
  url_to_format,
871
901
  ", **path_format_arguments" if builder.parameters.path else ""
872
902
  )
@@ -901,12 +931,11 @@ class _OperationBaseSerializer(_BuilderBaseSerializer): # pylint: disable=abstr
901
931
  retval.append(f"deserialized = self._deserialize('{response.serialization_type}', pipeline_response)")
902
932
  else:
903
933
  is_xml = any(["xml" in ct for ct in response.content_types])
904
- deserialized_value = ""
905
934
  deserialized_value = "ET.fromstring(response.text())" if is_xml else "response.json()"
906
935
  retval.append(f"if response.content:")
907
936
  retval.append(f" deserialized = {deserialized_value}")
908
937
  retval.append("else:")
909
- retval.append(" deserialized = None")
938
+ retval.append(f" deserialized = None")
910
939
  return retval
911
940
 
912
941
  @property
@@ -954,14 +983,18 @@ class _OperationBaseSerializer(_BuilderBaseSerializer): # pylint: disable=abstr
954
983
  builder.responses[0]
955
984
  ))
956
985
  retval.append("")
986
+ if builder.has_optional_return_type or self.code_model.options["models_mode"]:
987
+ deserialized = "deserialized"
988
+ else:
989
+ deserialized = f"cast({self._response_type_annotation(builder)}, deserialized)"
957
990
  retval.append("if cls:")
958
991
  retval.append(" return cls(pipeline_response, {}, {})".format(
959
- "deserialized" if builder.has_response_body else "None",
992
+ deserialized if builder.has_response_body else "None",
960
993
  "response_headers" if builder.any_response_has_headers else '{}'
961
994
  ))
962
995
  if builder.has_response_body:
963
996
  retval.append("")
964
- retval.append("return deserialized")
997
+ retval.append(f"return {deserialized}")
965
998
  if builder.request_builder.method == 'HEAD' and self.code_model.options['head_as_boolean']:
966
999
  retval.append("return 200 <= response.status_code <= 299")
967
1000
  return retval
@@ -1010,7 +1043,7 @@ class _OperationBaseSerializer(_BuilderBaseSerializer): # pylint: disable=abstr
1010
1043
  else:
1011
1044
  retval.append(" 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError")
1012
1045
  retval.append("}")
1013
- retval.append("error_map.update(kwargs.pop('error_map', {}))")
1046
+ retval.append("error_map.update(kwargs.pop('error_map', {}) or {})")
1014
1047
  return retval
1015
1048
 
1016
1049
  @staticmethod
@@ -1185,7 +1218,7 @@ class _PagingOperationBaseSerializer(_OperationBaseSerializer): # pylint: disab
1185
1218
  return retval
1186
1219
 
1187
1220
  def set_up_params_for_pager(self, builder) -> List[str]:
1188
- retval = [f"cls = kwargs.pop('cls', None) {self.cls_type_annotation(builder)}"]
1221
+ retval = []
1189
1222
  retval.extend(self.error_map(builder))
1190
1223
  retval.extend(self._prepare_request_callback(builder))
1191
1224
  retval.append("")
@@ -1276,19 +1309,20 @@ class _LROOperationBaseSerializer(_OperationBaseSerializer): # pylint: disable=
1276
1309
 
1277
1310
  def initial_call(self, builder) -> List[str]:
1278
1311
  retval = [f"polling = kwargs.pop('polling', True) # type: Union[bool, {self._polling_method_type}]"]
1279
- retval.append(f"cls = kwargs.pop('cls', None) {self.cls_type_annotation(builder)}")
1280
1312
  retval.append("lro_delay = kwargs.pop(")
1281
1313
  retval.append(" 'polling_interval',")
1282
1314
  retval.append(" self._config.polling_interval")
1283
1315
  retval.append(")")
1284
1316
  retval.append("cont_token = kwargs.pop('continuation_token', None) # type: Optional[str]")
1285
1317
  retval.append("if cont_token is None:")
1286
- retval.append(f" raw_result = {self._call_method}self.{builder.initial_operation.name}(")
1318
+ retval.append(f" raw_result = {self._call_method}self.{builder.initial_operation.name}( # type: ignore")
1287
1319
  retval.extend([
1288
1320
  f" {parameter.serialized_name}={parameter.serialized_name},"
1289
1321
  for parameter in builder.parameters.method
1290
1322
  ])
1291
1323
  retval.append(" cls=lambda x,y,z: x,")
1324
+ retval.append(" headers=_headers,")
1325
+ retval.append(" params=_params,")
1292
1326
  retval.append(" **kwargs")
1293
1327
  retval.append(" )")
1294
1328
  retval.append("kwargs.pop('error_map', None)")
@@ -1297,20 +1331,27 @@ class _LROOperationBaseSerializer(_OperationBaseSerializer): # pylint: disable=
1297
1331
  def return_lro_poller(self, builder) -> List[str]:
1298
1332
  retval = []
1299
1333
  lro_options_str = (
1300
- ", lro_options={'final-state-via': '" + builder.lro_options['final-state-via'] + "'}"
1334
+ "lro_options={'final-state-via': '" + builder.lro_options['final-state-via'] + "'},"
1301
1335
  if builder.lro_options else ""
1302
1336
  )
1303
1337
  path_format_arguments_str = ""
1304
1338
  if builder.parameters.path:
1305
- path_format_arguments_str = ", path_format_arguments=path_format_arguments"
1339
+ path_format_arguments_str = "path_format_arguments=path_format_arguments,"
1306
1340
  retval.extend(self.serialize_path(builder))
1307
1341
  retval.append("")
1308
- retval.append(
1309
- f"if polling is True: polling_method = {self._default_polling_method(builder)}" +
1310
- f"(lro_delay{lro_options_str}{path_format_arguments_str}, **kwargs)"
1342
+ retval.extend([
1343
+ "if polling is True:",
1344
+ f" polling_method = cast({self._polling_method_type}, {self._default_polling_method(builder)}(",
1345
+ " lro_delay,",
1346
+ f" {lro_options_str}",
1347
+ f" {path_format_arguments_str}",
1348
+ " **kwargs",
1349
+ f")) # type: {self._polling_method_type}",
1350
+ ]
1311
1351
  )
1312
1352
  retval.append(
1313
- f"elif polling is False: polling_method = {self._default_no_polling_method(builder)}()"
1353
+ f"elif polling is False: polling_method = cast({self._polling_method_type}, "
1354
+ f"{self._default_no_polling_method(builder)}())"
1314
1355
  )
1315
1356
  retval.append("else: polling_method = polling")
1316
1357
  retval.append("if cont_token:")
@@ -1331,7 +1372,8 @@ class _LROOperationBaseSerializer(_OperationBaseSerializer): # pylint: disable=
1331
1372
  if builder.lro_response:
1332
1373
  if builder.lro_response.has_headers:
1333
1374
  retval.append(" response_headers = {}")
1334
- retval.append(" response = pipeline_response.http_response")
1375
+ if not self.code_model.options["models_mode"] or builder.lro_response.has_headers:
1376
+ retval.append(" response = pipeline_response.http_response")
1335
1377
  retval.extend([
1336
1378
  f" {line}"
1337
1379
  for line in self.response_headers_and_deserialization(builder.lro_response)
@@ -32,9 +32,14 @@ class ClientSerializer:
32
32
  )
33
33
 
34
34
  def pop_kwargs_from_signature(self, async_mode: bool) -> List[str]:
35
- return utils.pop_kwargs_from_signature(self.code_model.service_client.parameters.kwargs_to_pop(
36
- async_mode or self.is_python3_file
37
- ))
35
+ return utils.pop_kwargs_from_signature(
36
+ self.code_model.service_client.parameters.kwargs_to_pop(
37
+ async_mode or self.is_python3_file,
38
+ ),
39
+ check_kwarg_dict=False,
40
+ pop_headers_kwarg=utils.PopKwargType.NO,
41
+ pop_params_kwarg=utils.PopKwargType.NO,
42
+ )
38
43
 
39
44
  def class_definition(self, async_mode) -> str:
40
45
  class_name = self.code_model.class_name
@@ -212,9 +217,14 @@ class ConfigSerializer:
212
217
  )
213
218
 
214
219
  def pop_kwargs_from_signature(self, async_mode: bool) -> List[str]:
215
- return utils.pop_kwargs_from_signature(self.code_model.global_parameters.config_kwargs_to_pop(
216
- async_mode or self.is_python3_file
217
- ))
220
+ return utils.pop_kwargs_from_signature(
221
+ self.code_model.global_parameters.config_kwargs_to_pop(
222
+ async_mode or self.is_python3_file
223
+ ),
224
+ check_kwarg_dict=False,
225
+ pop_headers_kwarg=utils.PopKwargType.NO,
226
+ pop_params_kwarg=utils.PopKwargType.NO,
227
+ )
218
228
 
219
229
  def set_constants(self) -> List[str]:
220
230
  return [
@@ -50,7 +50,7 @@ class GeneralSerializer:
50
50
 
51
51
  if (
52
52
  self.code_model.options['credential'] and
53
- isinstance(self.code_model.credential_schema_policy.credential, TokenCredentialSchema)
53
+ isinstance(self.code_model.credential_model.credential_schema_policy.credential, TokenCredentialSchema)
54
54
  ):
55
55
  self._correct_credential_parameter()
56
56
 
@@ -77,12 +77,33 @@ class GeneralSerializer:
77
77
  ImportType.AZURECORE,
78
78
  )
79
79
 
80
+ if self.code_model.need_mixin_abc:
81
+ file_import.add_submodule_import(
82
+ "abc",
83
+ "ABC",
84
+ ImportType.STDLIB,
85
+ )
86
+ file_import.add_submodule_import(
87
+ "azure.core",
88
+ f"{'Async' if self.async_mode else ''}PipelineClient",
89
+ ImportType.AZURECORE,
90
+ TypingSection.TYPING,
91
+ )
92
+ file_import.add_submodule_import(
93
+ "._configuration",
94
+ f"{self.code_model.class_name}Configuration",
95
+ ImportType.LOCAL
96
+ )
97
+ file_import.add_submodule_import("msrest", "Serializer", ImportType.THIRDPARTY, TypingSection.TYPING)
98
+ file_import.add_submodule_import("msrest", "Deserializer", ImportType.THIRDPARTY, TypingSection.TYPING)
99
+
80
100
  return template.render(
81
101
  code_model=self.code_model,
82
102
  imports=FileImportSerializer(
83
103
  file_import,
84
104
  is_python3_file=self.async_mode,
85
- )
105
+ ),
106
+ async_mode=self.async_mode,
86
107
  )
87
108
 
88
109
 
@@ -95,7 +116,7 @@ class GeneralSerializer:
95
116
 
96
117
  if (
97
118
  self.code_model.options['credential'] and
98
- isinstance(self.code_model.credential_schema_policy.credential, TokenCredentialSchema)
119
+ isinstance(self.code_model.credential_model.credential_schema_policy.credential, TokenCredentialSchema)
99
120
  ):
100
121
  self._correct_credential_parameter()
101
122
 
@@ -12,7 +12,7 @@ def _serialize_package(
12
12
  ) -> str:
13
13
  buffer = []
14
14
  if any(i for i in imports if i.submodule_name is None):
15
- buffer.append(f"import {imports[0].module_name}")
15
+ buffer.append(f"import {imports[0].module_name}{f' as {imports[0].alias}' if imports[0].alias else ''}")
16
16
  else:
17
17
  import_str = ", ".join(sorted([
18
18
  f"{i.submodule_name} as {i.alias}" if i.alias else i.submodule_name for i in imports # type: ignore
@@ -145,7 +145,7 @@ class MetadataSerializer:
145
145
  async_global_parameters = self.code_model.global_parameters
146
146
  if (
147
147
  self.code_model.options['credential'] and
148
- isinstance(self.code_model.credential_schema_policy.credential, TokenCredentialSchema)
148
+ isinstance(self.code_model.credential_model.credential_schema_policy.credential, TokenCredentialSchema)
149
149
  ):
150
150
  # this ensures that the TokenCredentialSchema showing up in the list of code model's global parameters
151
151
  # is sync. This way we only have to make a copy for an async_credential
@@ -40,6 +40,7 @@ class ModelBaseSerializer:
40
40
  init_args=self.init_args,
41
41
  input_documentation_string=ModelBaseSerializer.input_documentation_string,
42
42
  variable_documentation_string=ModelBaseSerializer.variable_documentation_string,
43
+ declare_model=ModelBaseSerializer.declare_model,
43
44
  )
44
45
 
45
46
  def imports(self) -> FileImport:
@@ -62,6 +63,13 @@ class ModelBaseSerializer:
62
63
  properties_to_initialize = model.properties
63
64
  return properties_to_initialize
64
65
 
66
+ @staticmethod
67
+ def declare_model(model: ObjectSchema) -> str:
68
+ basename = "msrest.serialization.Model"
69
+ if model.base_models:
70
+ basename = ", ".join([cast(ObjectSchema, m).name for m in model.base_models])
71
+ return f"class {model.name}({basename}):"
72
+
65
73
  @staticmethod
66
74
  def input_documentation_string(prop: Property) -> List[str]:
67
75
  # building the param line of the property doc
@@ -46,11 +46,11 @@ class ModelPython3Serializer(ModelBaseSerializer):
46
46
  return ", ".join(properties_to_pass_to_super)
47
47
 
48
48
  def required_property_no_default_init(self, prop: Property) -> str:
49
- return f"{prop.name}: {prop.type_annotation}"
49
+ return f"{prop.name}: {prop.type_annotation()}"
50
50
 
51
51
  def optional_property_init(self, prop: Property) -> str:
52
52
  default = prop.default_value_declaration
53
- return f"{prop.name}: {prop.type_annotation} = {default}"
53
+ return f"{prop.name}: {prop.type_annotation()} = {default}"
54
54
 
55
55
  def initialize_standard_arg(self, prop: Property) -> str:
56
56
  return f"self.{prop.name} = {prop.name}"
@@ -43,6 +43,7 @@ class OperationGroupsSerializer:
43
43
  for operation_group in operation_groups:
44
44
  imports.merge(operation_group.imports(
45
45
  async_mode=self.async_mode,
46
+ is_python3_file=self.is_python3_file,
46
47
  ))
47
48
 
48
49
  template = self.env.get_or_select_template("operation_groups_container.py.jinja2")
@@ -4,12 +4,21 @@
4
4
  # license information.
5
5
  # --------------------------------------------------------------------------
6
6
  from jinja2 import Environment
7
-
7
+ from .import_serializer import FileImportSerializer
8
+ from ..models import CodeModel, FileImport, ImportType, TypingSection
8
9
 
9
10
  class PatchSerializer:
10
- def __init__(self, env: Environment) -> None:
11
+ def __init__(self, env: Environment, code_model: CodeModel) -> None:
11
12
  self.env = env
13
+ self.code_model = code_model
12
14
 
13
15
  def serialize(self) -> str:
14
16
  template = self.env.get_template("patch.py.jinja2")
15
- return template.render()
17
+ imports = FileImport()
18
+ imports.add_submodule_import("typing", "List", ImportType.STDLIB, TypingSection.CONDITIONAL)
19
+ is_python3_file = self.code_model.options["python3_only"]
20
+ return template.render(
21
+ code_model=self.code_model,
22
+ imports=FileImportSerializer(imports, is_python3_file=is_python3_file),
23
+ is_python3_file=is_python3_file,
24
+ )
@@ -3,8 +3,9 @@
3
3
  # Licensed under the MIT License. See License.txt in the project root for
4
4
  # license information.
5
5
  # --------------------------------------------------------------------------
6
+ from enum import Enum, auto
6
7
  from typing import List
7
- from ..models import ParameterStyle, ListSchema, Parameter
8
+ from ..models import ParameterStyle, ListSchema, Parameter, ParameterLocation
8
9
 
9
10
 
10
11
  def serialize_method(
@@ -102,16 +103,40 @@ def method_signature_and_response_type_annotation_template(
102
103
  return f"{method_signature} -> {response_type_annotation}:"
103
104
  return f"{method_signature}:\n # type: (...) -> {response_type_annotation}"
104
105
 
105
- def pop_kwargs_from_signature(kwargs_to_pop: List[Parameter]) -> List[str]:
106
+ class PopKwargType(Enum):
107
+ NO = auto()
108
+ SIMPLE = auto()
109
+ CASE_INSENSITIVE = auto()
110
+
111
+ def pop_kwargs_from_signature(
112
+ kwargs_to_pop: List[Parameter],
113
+ check_kwarg_dict: bool,
114
+ pop_headers_kwarg: PopKwargType,
115
+ pop_params_kwarg: PopKwargType,
116
+ ) -> List[str]:
106
117
  retval = []
118
+ def append_pop_kwarg(key: str, pop_type: PopKwargType) -> None:
119
+ if PopKwargType.CASE_INSENSITIVE == pop_type:
120
+ retval.append(f'_{key} = case_insensitive_dict(kwargs.pop("{key}", {{}}) or {{}})')
121
+ elif PopKwargType.SIMPLE == pop_type:
122
+ retval.append(f'_{key} = kwargs.pop("{key}", {{}}) or {{}}')
123
+ append_pop_kwarg("headers", pop_headers_kwarg)
124
+ append_pop_kwarg("params", pop_params_kwarg)
125
+ if pop_headers_kwarg != PopKwargType.NO or pop_params_kwarg != PopKwargType.NO:
126
+ retval.append("")
107
127
  for kwarg in kwargs_to_pop:
108
128
  if kwarg.has_default_value:
129
+ default_value = kwarg.default_value_declaration
130
+ if check_kwarg_dict and (kwarg.location in [ParameterLocation.Header, ParameterLocation.Query]):
131
+ kwarg_dict = "headers" if kwarg.location == ParameterLocation.Header else "params"
132
+ default_value = f"_{kwarg_dict}.pop('{kwarg.rest_api_name}', {default_value})"
109
133
  retval.append(
110
134
  f"{kwarg.serialized_name} = kwargs.pop('{kwarg.serialized_name}', "
111
- + f"{kwarg.default_value_declaration}) # type: {kwarg.type_annotation}"
135
+ + f"{default_value}) # type: {kwarg.type_annotation(is_operation_file=True)}"
112
136
  )
113
137
  else:
138
+ type_annot = kwarg.type_annotation(is_operation_file=True)
114
139
  retval.append(
115
- f"{kwarg.serialized_name} = kwargs.pop('{kwarg.serialized_name}') # type: {kwarg.type_annotation}"
140
+ f"{kwarg.serialized_name} = kwargs.pop('{kwarg.serialized_name}') # type: {type_annot}"
116
141
  )
117
142
  return retval
@@ -35,8 +35,8 @@ class {{ code_model.class_name }}Configuration(Configuration): # pylint: disabl
35
35
  {% if serializer.set_constants() %}
36
36
  {{ op_tools.serialize(serializer.set_constants()) | indent(8) -}}
37
37
  {% endif %}
38
- {% if code_model.options['credential'] and code_model.credential_schema_policy.credential_scopes is defined %}
39
- self.credential_scopes = kwargs.pop('credential_scopes', {{ code_model.credential_schema_policy.credential_scopes }})
38
+ {% if code_model.options['credential'] and code_model.credential_model.credential_schema_policy.credential_scopes is defined %}
39
+ self.credential_scopes = kwargs.pop('credential_scopes', {{ code_model.credential_model.credential_schema_policy.credential_scopes }})
40
40
  {% endif %}
41
41
  kwargs.setdefault('sdk_moniker', '{{ sdk_moniker }}/{}'.format(VERSION))
42
42
  self._configure(**kwargs)
@@ -59,10 +59,10 @@ class {{ code_model.class_name }}Configuration(Configuration): # pylint: disabl
59
59
  self.authentication_policy = kwargs.get('authentication_policy')
60
60
  {% if code_model.options['credential'] %}
61
61
  {# only adding this if credential_scopes is not passed during code generation #}
62
- {% if code_model.credential_schema_policy.credential_scopes is defined and code_model.credential_schema_policy.credential_scopes|length == 0 %}
62
+ {% if code_model.credential_model.credential_schema_policy.credential_scopes is defined and code_model.credential_model.credential_schema_policy.credential_scopes|length == 0 %}
63
63
  if not self.credential_scopes and not self.authentication_policy:
64
64
  raise ValueError("You must provide either credential_scopes or authentication_policy as kwargs")
65
65
  {% endif %}
66
66
  if self.credential and not self.authentication_policy:
67
- self.authentication_policy = {{ code_model.credential_schema_policy.call(async_mode) }}
67
+ self.authentication_policy = {{ code_model.credential_model.credential_schema_policy.call(async_mode) }}
68
68
  {% endif %}
@@ -1,5 +1,5 @@
1
1
 
2
- class {{ enum.name }}(with_metaclass(CaseInsensitiveEnumMeta, {{ enum.enum_type.type_annotation }}, Enum)):
2
+ class {{ enum.name }}({{ enum.enum_type.type_annotation() }}, Enum, metaclass=CaseInsensitiveEnumMeta):
3
3
  {% if enum.description %}
4
4
  """{{ enum.description | wordwrap(width=95, break_long_words=False, break_on_hyphens=False, wrapstring='\n ') }}
5
5
  """
@@ -2,7 +2,6 @@
2
2
  {{ code_model.options['license_header'] }}
3
3
 
4
4
  from enum import Enum
5
- from six import with_metaclass
6
5
  from azure.core import CaseInsensitiveEnumMeta
7
6
 
8
7
  {% for enum in code_model.enums.values() | sort %}
@@ -1,15 +1,18 @@
1
+ {% import 'keywords.jinja2' as keywords %}
1
2
  # coding=utf-8
2
3
  {{ code_model.options['license_header'] }}
3
4
 
4
- from ._{{ code_model.module_name }} import {{ code_model.class_name }}
5
+ {% if code_model.rest.request_builders %}
6
+ from .{{ code_model.service_client.filename }} import {{ code_model.class_name }}
7
+ {% endif %}
5
8
  {% if not async_mode and code_model.options['package_version']%}
6
9
  from ._version import VERSION
7
10
 
8
11
  __version__ = VERSION
9
12
  {% endif %}
10
- __all__ = ['{{ code_model.class_name }}']
11
13
 
12
- # `._patch.py` is used for handwritten extensions to the generated code
13
- # Example: https://github.com/Azure/azure-sdk-for-python/blob/main/doc/dev/customize_code/how-to-patch-sdk-code.md
14
- from ._patch import patch_sdk
15
- patch_sdk()
14
+ {{ keywords.patch_imports(try_except=True) }}
15
+ __all__ = [{{("'" + code_model.class_name + "'") if code_model.rest.request_builders else ""}}]
16
+ {{ keywords.extend_all }}
17
+
18
+ _patch_sdk()
@@ -3,4 +3,17 @@
3
3
  {% set await = "await " if async_mode else "" %}
4
4
  {% set async_class = "Async" if async_mode else "" %}
5
5
  {% macro escape_str(s) %}'{{ s|replace("'", "\\'") }}'{% endmacro %}
6
- {% set kwargs_declaration = "**kwargs: Any" if async_mode else "**kwargs # type: Any" %}
6
+ {% set kwargs_declaration = "**kwargs: Any" if async_mode else "**kwargs # type: Any" %}
7
+ {% set extend_all = "__all__.extend([p for p in _patch_all if p not in __all__])" %}
8
+ {% macro patch_imports(try_except=False) %}
9
+ {% set indentation = " " if try_except else "" %}
10
+ {% if try_except %}
11
+ try:
12
+ {% endif %}
13
+ {{ indentation }}from ._patch import __all__ as _patch_all
14
+ {{ indentation }}from ._patch import * # type: ignore # pylint: disable=unused-wildcard-import
15
+ {% if try_except %}
16
+ except ImportError:
17
+ _patch_all = []
18
+ {% endif %}
19
+ from ._patch import patch_sdk as _patch_sdk{% endmacro %}
@@ -6,7 +6,7 @@
6
6
  {% endif %}
7
7
  {{ operation_serializer.method_signature_and_response_type_annotation(operation) }}
8
8
  {{ op_tools.description(operation, operation_serializer) | indent -}}
9
- {% if operation.parameters.kwargs_to_pop(async_mode) %}
9
+ {% if operation_serializer.pop_kwargs_from_signature(operation) %}
10
10
  {{ op_tools.serialize(operation_serializer.pop_kwargs_from_signature(operation)) | indent }}
11
11
  {%- endif %}
12
12
  {{ op_tools.serialize(operation_serializer.initial_call(operation)) | indent }}
@@ -7,7 +7,7 @@
7
7
  {% endif %}
8
8
  {{ operation_serializer.method_signature_and_response_type_annotation(operation) }}
9
9
  {{ op_tools.description(operation, operation_serializer) | indent }}
10
- {% if operation.parameters.kwargs_to_pop(async_mode) %}
10
+ {% if operation_serializer.pop_kwargs_from_signature(operation) %}
11
11
  {{ op_tools.serialize(operation_serializer.pop_kwargs_from_signature(operation)) | indent }}
12
12
  {% endif %}
13
13
  {{ op_tools.serialize(operation_serializer.set_up_params_for_pager(operation)) | indent }}