@autorest/python 5.12.6 → 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 (69) hide show
  1. package/ChangeLog.md +205 -125
  2. package/autorest/black/__init__.py +3 -0
  3. package/autorest/codegen/__init__.py +120 -48
  4. package/autorest/codegen/models/__init__.py +2 -1
  5. package/autorest/codegen/models/base_schema.py +2 -6
  6. package/autorest/codegen/models/client.py +6 -0
  7. package/autorest/codegen/models/code_model.py +43 -74
  8. package/autorest/codegen/models/constant_schema.py +7 -7
  9. package/autorest/codegen/models/credential_model.py +47 -0
  10. package/autorest/codegen/models/credential_schema.py +5 -4
  11. package/autorest/codegen/models/dictionary_schema.py +7 -7
  12. package/autorest/codegen/models/enum_schema.py +8 -39
  13. package/autorest/codegen/models/imports.py +3 -1
  14. package/autorest/codegen/models/list_schema.py +18 -8
  15. package/autorest/codegen/models/lro_operation.py +3 -3
  16. package/autorest/codegen/models/lro_paging_operation.py +3 -3
  17. package/autorest/codegen/models/object_schema.py +17 -13
  18. package/autorest/codegen/models/operation.py +38 -10
  19. package/autorest/codegen/models/operation_group.py +7 -2
  20. package/autorest/codegen/models/paging_operation.py +3 -3
  21. package/autorest/codegen/models/parameter.py +71 -22
  22. package/autorest/codegen/models/parameter_list.py +11 -5
  23. package/autorest/codegen/models/primitive_schemas.py +15 -25
  24. package/autorest/codegen/models/property.py +5 -5
  25. package/autorest/codegen/models/request_builder.py +4 -4
  26. package/autorest/codegen/models/request_builder_parameter.py +17 -5
  27. package/autorest/codegen/models/schema_response.py +23 -10
  28. package/autorest/codegen/models/utils.py +20 -0
  29. package/autorest/codegen/serializers/__init__.py +184 -87
  30. package/autorest/codegen/serializers/builder_serializer.py +113 -47
  31. package/autorest/codegen/serializers/client_serializer.py +16 -6
  32. package/autorest/codegen/serializers/general_serializer.py +28 -4
  33. package/autorest/codegen/serializers/import_serializer.py +1 -1
  34. package/autorest/codegen/serializers/metadata_serializer.py +1 -1
  35. package/autorest/codegen/serializers/model_base_serializer.py +8 -0
  36. package/autorest/codegen/serializers/model_python3_serializer.py +2 -2
  37. package/autorest/codegen/serializers/operation_groups_serializer.py +1 -0
  38. package/autorest/codegen/serializers/patch_serializer.py +12 -3
  39. package/autorest/codegen/serializers/utils.py +29 -4
  40. package/autorest/codegen/templates/CHANGELOG.md.jinja2 +6 -0
  41. package/autorest/codegen/templates/LICENSE.jinja2 +21 -0
  42. package/autorest/codegen/templates/MANIFEST.in.jinja2 +7 -0
  43. package/autorest/codegen/templates/README.md.jinja2 +105 -0
  44. package/autorest/codegen/templates/config.py.jinja2 +4 -4
  45. package/autorest/codegen/templates/dev_requirements.txt.jinja2 +10 -0
  46. package/autorest/codegen/templates/enum.py.jinja2 +1 -1
  47. package/autorest/codegen/templates/enum_container.py.jinja2 +0 -1
  48. package/autorest/codegen/templates/init.py.jinja2 +9 -6
  49. package/autorest/codegen/templates/keywords.jinja2 +14 -1
  50. package/autorest/codegen/templates/lro_operation.py.jinja2 +1 -1
  51. package/autorest/codegen/templates/lro_paging_operation.py.jinja2 +1 -1
  52. package/autorest/codegen/templates/metadata.json.jinja2 +3 -3
  53. package/autorest/codegen/templates/model.py.jinja2 +1 -6
  54. package/autorest/codegen/templates/model_init.py.jinja2 +7 -4
  55. package/autorest/codegen/templates/operation.py.jinja2 +2 -3
  56. package/autorest/codegen/templates/operation_group.py.jinja2 +20 -17
  57. package/autorest/codegen/templates/operation_groups_container.py.jinja2 +0 -1
  58. package/autorest/codegen/templates/operations_folder_init.py.jinja2 +4 -0
  59. package/autorest/codegen/templates/paging_operation.py.jinja2 +1 -1
  60. package/autorest/codegen/templates/patch.py.jinja2 +18 -29
  61. package/autorest/codegen/templates/request_builder.py.jinja2 +4 -6
  62. package/autorest/codegen/templates/setup.py.jinja2 +79 -20
  63. package/autorest/codegen/templates/vendor.py.jinja2 +12 -2
  64. package/autorest/multiapi/models/imports.py +21 -11
  65. package/autorest/multiapi/serializers/import_serializer.py +3 -1
  66. package/autorest/namer/name_converter.py +1 -1
  67. package/package.json +2 -2
  68. package/run-python3.js +1 -7
  69. package/venvtools.py +2 -2
@@ -27,6 +27,7 @@ from ..models import (
27
27
  SchemaResponse,
28
28
  IOSchema,
29
29
  ParameterStyle,
30
+ ParameterLocation
30
31
  )
31
32
  from . import utils
32
33
 
@@ -109,12 +110,6 @@ def _serialize_files_and_data_body(builder, param_name: str) -> List[str]:
109
110
  retval.append("}")
110
111
  return retval
111
112
 
112
- def _pop_parameters_kwarg(
113
- function_name: str,
114
- kwarg_name: str,
115
- ) -> str:
116
- return f'_{function_name}_parameters = kwargs.pop("{kwarg_name}", {{}}) # type: Dict[str, Any]'
117
-
118
113
  def _serialize_grouped_body(builder) -> List[str]:
119
114
  retval: List[str] = []
120
115
  for grouped_parameter in builder.parameters.grouped:
@@ -152,12 +147,21 @@ def _serialize_flattened_body(builder) -> List[str]:
152
147
  return retval
153
148
 
154
149
  def _content_type_docstring(builder) -> str:
155
- content_type_str = (
156
- ":keyword str content_type: Media type of the body sent to the API. " +
157
- f'Default value is "{builder.parameters.default_content_type}". ' +
158
- 'Allowed values are: "{}."'.format('", "'.join(builder.parameters.content_types))
150
+ content_types = [f'"{c}"' for c in builder.parameters.content_types]
151
+ if len(content_types) == 2:
152
+ possible_values_str = " or ".join(content_types)
153
+ else:
154
+ possible_values_str = ", ".join(
155
+ content_types[: len(content_types) - 1]
156
+ ) + f", and {content_types[-1]}"
157
+ default_value = next(
158
+ p for p in builder.parameters.method if p.rest_api_name == "Content-Type"
159
+ ).default_value_declaration
160
+ return (
161
+ ":keyword content_type: Media type of the body sent to the API. " +
162
+ f"Known values are: {possible_values_str}. " +
163
+ f"Default value is {default_value}."
159
164
  )
160
- return content_type_str
161
165
 
162
166
  class _BuilderSerializerProtocol(ABC):
163
167
  @property
@@ -304,13 +308,14 @@ class _BuilderBaseSerializer(_BuilderSerializerProtocol): # pylint: disable=abs
304
308
  description_list.append(
305
309
  f":{param.docstring_type_keyword} { param.serialized_name }: { param.docstring_type }"
306
310
  )
307
- try:
308
- request_builder: RequestBuilder = cast(Operation, builder).request_builder
309
- except AttributeError:
310
- request_builder = cast(RequestBuilder, builder)
311
311
 
312
- if len(request_builder.schema_requests) > 1:
313
- description_list.append(_content_type_docstring(builder))
312
+ if len(builder.parameters.content_types) > 1:
313
+ description_list = [
314
+ _content_type_docstring(builder) if l.startswith(":keyword content_type:") else l
315
+ for l in description_list
316
+ ]
317
+ if not any(l for l in description_list if l.startswith(":keyword content_type:")):
318
+ description_list.append(_content_type_docstring(builder))
314
319
  return description_list
315
320
 
316
321
  def param_description_and_response_docstring(self, builder) -> List[str]:
@@ -400,10 +405,11 @@ class _BuilderBaseSerializer(_BuilderSerializerProtocol): # pylint: disable=abs
400
405
  ...
401
406
 
402
407
  def _serialize_parameter(
403
- self, param: Parameter, function_name: str
408
+ self, param: Parameter, kwarg_name: str
404
409
  ) -> List[str]:
405
- set_parameter = "_{}_parameters['{}'] = {}".format(
406
- function_name,
410
+ function_name = "header" if kwarg_name == "headers" else "query"
411
+ set_parameter = "_{}['{}'] = {}".format(
412
+ kwarg_name,
407
413
  param.rest_api_name,
408
414
  utils.build_serialize_data_call(param, function_name, self.serializer_name)
409
415
  )
@@ -423,10 +429,6 @@ class _BuilderBaseSerializer(_BuilderSerializerProtocol): # pylint: disable=abs
423
429
  template.extend(f"response.json() == {response_body}".splitlines())
424
430
  return template
425
431
 
426
-
427
- def pop_kwargs_from_signature(self, builder) -> List[str]:
428
- return utils.pop_kwargs_from_signature(self._get_kwargs_to_pop(builder))
429
-
430
432
  def serialize_path(self, builder) -> List[str]:
431
433
  return utils.serialize_path(builder.parameters.path, self.serializer_name)
432
434
 
@@ -452,6 +454,21 @@ class _RequestBuilderBaseSerializer(_BuilderBaseSerializer): # pylint: disable=
452
454
  def serializer_name(self) -> str:
453
455
  return "_SERIALIZER"
454
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
+
455
472
  def want_example_template(self, builder) -> bool:
456
473
  if self.code_model.options["builders_visibility"] != "public":
457
474
  return False # if we're not exposing rest layer, don't need to generate
@@ -496,14 +513,24 @@ class _RequestBuilderBaseSerializer(_BuilderBaseSerializer): # pylint: disable=
496
513
  def _body_params_to_pass_to_request_creation(self, builder) -> List[str]:
497
514
  ...
498
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
+
499
526
  def create_http_request(self, builder) -> List[str]:
500
527
  retval = ["return HttpRequest("]
501
528
  retval.append(f' method="{builder.method}",')
502
529
  retval.append(" url=_url,")
503
530
  if builder.parameters.query:
504
- retval.append(" params=_query_parameters,")
531
+ retval.append(" params=_params,")
505
532
  if builder.parameters.headers:
506
- retval.append(" headers=_header_parameters,")
533
+ retval.append(" headers=_headers,")
507
534
  if builder.parameters.has_body:
508
535
  retval.extend([
509
536
  f" {body_kwarg}={body_kwarg},"
@@ -515,21 +542,19 @@ class _RequestBuilderBaseSerializer(_BuilderBaseSerializer): # pylint: disable=
515
542
 
516
543
  def serialize_headers(self, builder) -> List[str]:
517
544
  retval = ["# Construct headers"]
518
- retval.append(_pop_parameters_kwarg("header", "headers"))
519
545
  for parameter in builder.parameters.headers:
520
546
  retval.extend(self._serialize_parameter(
521
547
  parameter,
522
- function_name="header",
548
+ kwarg_name="headers",
523
549
  ))
524
550
  return retval
525
551
 
526
552
  def serialize_query(self, builder) -> List[str]:
527
553
  retval = ["# Construct parameters"]
528
- retval.append(_pop_parameters_kwarg("query", "params"))
529
554
  for parameter in builder.parameters.query:
530
555
  retval.extend(self._serialize_parameter(
531
556
  parameter,
532
- function_name="query",
557
+ kwarg_name="params",
533
558
  ))
534
559
  return retval
535
560
 
@@ -633,7 +658,7 @@ class _OperationBaseSerializer(_BuilderBaseSerializer): # pylint: disable=abstr
633
658
  return "bool"
634
659
  response_body_annotations: OrderedSet[str] = {}
635
660
  for response in [r for r in builder.responses if r.has_body]:
636
- response_body_annotations[response.operation_type_annotation] = None
661
+ response_body_annotations[response.type_annotation(is_operation_file=True)] = None
637
662
  response_str = ", ".join(response_body_annotations.keys()) or "None"
638
663
  if len(response_body_annotations) > 1:
639
664
  response_str = f"Union[{response_str}]"
@@ -641,6 +666,19 @@ class _OperationBaseSerializer(_BuilderBaseSerializer): # pylint: disable=abstr
641
666
  response_str = f"Optional[{response_str}]"
642
667
  return response_str
643
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
+
644
682
  def cls_type_annotation(self, builder) -> str:
645
683
  return f"# type: ClsType[{self._response_type_annotation(builder, modify_if_head_as_boolean=False)}]"
646
684
 
@@ -769,6 +807,7 @@ class _OperationBaseSerializer(_BuilderBaseSerializer): # pylint: disable=abstr
769
807
  if len(body_kwargs) == 1:
770
808
  retval.extend(self._set_body_content_kwarg(builder, builder.parameters.body[0], body_kwargs[0]))
771
809
  else:
810
+ retval.append('content_type = content_type or ""')
772
811
  for idx, body_kwarg in enumerate(body_kwargs):
773
812
  body_param = next(
774
813
  b for b in builder_params
@@ -788,6 +827,7 @@ class _OperationBaseSerializer(_BuilderBaseSerializer): # pylint: disable=abstr
788
827
  builder,
789
828
  request_builder: RequestBuilder,
790
829
  template_url: Optional[str] = None,
830
+ is_next_request: bool = False,
791
831
  ) -> List[str]:
792
832
  retval = []
793
833
  if len(builder.body_kwargs_to_pass_to_request_builder) > 1:
@@ -827,11 +867,23 @@ class _OperationBaseSerializer(_BuilderBaseSerializer): # pylint: disable=abstr
827
867
  parameter.serialized_name not in builder.body_kwargs_to_pass_to_request_builder
828
868
  ):
829
869
  continue
870
+ if (
871
+ is_next_request and
872
+ not bool(builder.next_request_builder) and
873
+ not self.code_model.options["reformat_next_link"] and
874
+ parameter.location == ParameterLocation.Query
875
+ ):
876
+ # if we don't want to reformat query parameters for next link calls
877
+ # in paging operations with a single swagger operation defintion,
878
+ # we skip passing query params when building the next request
879
+ continue
830
880
  high_level_name = cast(RequestBuilderParameter, parameter).name_in_high_level_operation
831
881
  retval.append(f" {parameter.serialized_name}={high_level_name},")
832
882
  if not self.code_model.options["version_tolerant"]:
833
883
  template_url = template_url or f"self.{builder.name}.metadata['url']"
834
884
  retval.append(f" template_url={template_url},")
885
+ retval.append(' headers=_headers,')
886
+ retval.append(' params=_params,')
835
887
  retval.append(f")")
836
888
  if not self.code_model.options["version_tolerant"]:
837
889
  pass_files = ""
@@ -844,7 +896,7 @@ class _OperationBaseSerializer(_BuilderBaseSerializer): # pylint: disable=abstr
844
896
  if self.code_model.options["version_tolerant"] and template_url:
845
897
  url_to_format = template_url
846
898
  retval.append(
847
- "request.url = self._client.format_url({}{})".format(
899
+ "request.url = self._client.format_url({}{}) # type: ignore".format(
848
900
  url_to_format,
849
901
  ", **path_format_arguments" if builder.parameters.path else ""
850
902
  )
@@ -879,12 +931,11 @@ class _OperationBaseSerializer(_BuilderBaseSerializer): # pylint: disable=abstr
879
931
  retval.append(f"deserialized = self._deserialize('{response.serialization_type}', pipeline_response)")
880
932
  else:
881
933
  is_xml = any(["xml" in ct for ct in response.content_types])
882
- deserialized_value = ""
883
934
  deserialized_value = "ET.fromstring(response.text())" if is_xml else "response.json()"
884
935
  retval.append(f"if response.content:")
885
936
  retval.append(f" deserialized = {deserialized_value}")
886
937
  retval.append("else:")
887
- retval.append(" deserialized = None")
938
+ retval.append(f" deserialized = None")
888
939
  return retval
889
940
 
890
941
  @property
@@ -932,14 +983,18 @@ class _OperationBaseSerializer(_BuilderBaseSerializer): # pylint: disable=abstr
932
983
  builder.responses[0]
933
984
  ))
934
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)"
935
990
  retval.append("if cls:")
936
991
  retval.append(" return cls(pipeline_response, {}, {})".format(
937
- "deserialized" if builder.has_response_body else "None",
992
+ deserialized if builder.has_response_body else "None",
938
993
  "response_headers" if builder.any_response_has_headers else '{}'
939
994
  ))
940
995
  if builder.has_response_body:
941
996
  retval.append("")
942
- retval.append("return deserialized")
997
+ retval.append(f"return {deserialized}")
943
998
  if builder.request_builder.method == 'HEAD' and self.code_model.options['head_as_boolean']:
944
999
  retval.append("return 200 <= response.status_code <= 299")
945
1000
  return retval
@@ -988,7 +1043,7 @@ class _OperationBaseSerializer(_BuilderBaseSerializer): # pylint: disable=abstr
988
1043
  else:
989
1044
  retval.append(" 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError")
990
1045
  retval.append("}")
991
- retval.append("error_map.update(kwargs.pop('error_map', {}))")
1046
+ retval.append("error_map.update(kwargs.pop('error_map', {}) or {})")
992
1047
  return retval
993
1048
 
994
1049
  @staticmethod
@@ -1073,11 +1128,13 @@ class _PagingOperationBaseSerializer(_OperationBaseSerializer): # pylint: disab
1073
1128
  else:
1074
1129
  request_builder = builder.request_builder
1075
1130
  template_url = "next_link"
1131
+
1076
1132
  request_builder = builder.next_request_builder or builder.request_builder
1077
1133
  return self._call_request_builder_helper(
1078
1134
  builder,
1079
1135
  request_builder,
1080
1136
  template_url=template_url,
1137
+ is_next_request=True
1081
1138
  )
1082
1139
 
1083
1140
  def _prepare_request_callback(self, builder) -> List[str]:
@@ -1161,7 +1218,7 @@ class _PagingOperationBaseSerializer(_OperationBaseSerializer): # pylint: disab
1161
1218
  return retval
1162
1219
 
1163
1220
  def set_up_params_for_pager(self, builder) -> List[str]:
1164
- retval = [f"cls = kwargs.pop('cls', None) {self.cls_type_annotation(builder)}"]
1221
+ retval = []
1165
1222
  retval.extend(self.error_map(builder))
1166
1223
  retval.extend(self._prepare_request_callback(builder))
1167
1224
  retval.append("")
@@ -1252,19 +1309,20 @@ class _LROOperationBaseSerializer(_OperationBaseSerializer): # pylint: disable=
1252
1309
 
1253
1310
  def initial_call(self, builder) -> List[str]:
1254
1311
  retval = [f"polling = kwargs.pop('polling', True) # type: Union[bool, {self._polling_method_type}]"]
1255
- retval.append(f"cls = kwargs.pop('cls', None) {self.cls_type_annotation(builder)}")
1256
1312
  retval.append("lro_delay = kwargs.pop(")
1257
1313
  retval.append(" 'polling_interval',")
1258
1314
  retval.append(" self._config.polling_interval")
1259
1315
  retval.append(")")
1260
1316
  retval.append("cont_token = kwargs.pop('continuation_token', None) # type: Optional[str]")
1261
1317
  retval.append("if cont_token is None:")
1262
- 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")
1263
1319
  retval.extend([
1264
1320
  f" {parameter.serialized_name}={parameter.serialized_name},"
1265
1321
  for parameter in builder.parameters.method
1266
1322
  ])
1267
1323
  retval.append(" cls=lambda x,y,z: x,")
1324
+ retval.append(" headers=_headers,")
1325
+ retval.append(" params=_params,")
1268
1326
  retval.append(" **kwargs")
1269
1327
  retval.append(" )")
1270
1328
  retval.append("kwargs.pop('error_map', None)")
@@ -1273,20 +1331,27 @@ class _LROOperationBaseSerializer(_OperationBaseSerializer): # pylint: disable=
1273
1331
  def return_lro_poller(self, builder) -> List[str]:
1274
1332
  retval = []
1275
1333
  lro_options_str = (
1276
- ", lro_options={'final-state-via': '" + builder.lro_options['final-state-via'] + "'}"
1334
+ "lro_options={'final-state-via': '" + builder.lro_options['final-state-via'] + "'},"
1277
1335
  if builder.lro_options else ""
1278
1336
  )
1279
1337
  path_format_arguments_str = ""
1280
1338
  if builder.parameters.path:
1281
- path_format_arguments_str = ", path_format_arguments=path_format_arguments"
1339
+ path_format_arguments_str = "path_format_arguments=path_format_arguments,"
1282
1340
  retval.extend(self.serialize_path(builder))
1283
1341
  retval.append("")
1284
- retval.append(
1285
- f"if polling is True: polling_method = {self._default_polling_method(builder)}" +
1286
- 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
+ ]
1287
1351
  )
1288
1352
  retval.append(
1289
- 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)}())"
1290
1355
  )
1291
1356
  retval.append("else: polling_method = polling")
1292
1357
  retval.append("if cont_token:")
@@ -1307,7 +1372,8 @@ class _LROOperationBaseSerializer(_OperationBaseSerializer): # pylint: disable=
1307
1372
  if builder.lro_response:
1308
1373
  if builder.lro_response.has_headers:
1309
1374
  retval.append(" response_headers = {}")
1310
- 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")
1311
1377
  retval.extend([
1312
1378
  f" {line}"
1313
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
 
@@ -119,4 +140,7 @@ class GeneralSerializer:
119
140
 
120
141
  def serialize_setup_file(self) -> str:
121
142
  template = self.env.get_template("setup.py.jinja2")
122
- return template.render(code_model=self.code_model)
143
+ params = {}
144
+ params.update(self.code_model.options)
145
+ params.update(self.code_model.package_dependency)
146
+ return template.render(code_model=self.code_model, **params)
@@ -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
@@ -0,0 +1,6 @@
1
+ # Release History
2
+
3
+ ## 1.0.0b1 (1970-01-01)
4
+
5
+ - Initial version
6
+
@@ -0,0 +1,21 @@
1
+ Copyright (c) Microsoft Corporation.
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,7 @@
1
+ include *.md
2
+ include LICENSE
3
+ recursive-include tests *.py
4
+ recursive-include samples *.py *.md
5
+ {%- for init_name in init_names %}
6
+ include {{ init_name }}
7
+ {%- endfor %}