@autorest/python 5.12.4 → 5.13.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 (47) hide show
  1. package/ChangeLog.md +173 -109
  2. package/autorest/black/__init__.py +7 -1
  3. package/autorest/codegen/__init__.py +12 -2
  4. package/autorest/codegen/models/__init__.py +2 -1
  5. package/autorest/codegen/models/client.py +22 -19
  6. package/autorest/codegen/models/constant_schema.py +0 -4
  7. package/autorest/codegen/models/credential_schema.py +3 -3
  8. package/autorest/codegen/models/dictionary_schema.py +1 -1
  9. package/autorest/codegen/models/enum_schema.py +2 -2
  10. package/autorest/codegen/models/imports.py +90 -50
  11. package/autorest/codegen/models/list_schema.py +1 -1
  12. package/autorest/codegen/models/lro_operation.py +15 -9
  13. package/autorest/codegen/models/object_schema.py +2 -2
  14. package/autorest/codegen/models/operation.py +39 -30
  15. package/autorest/codegen/models/operation_group.py +5 -14
  16. package/autorest/codegen/models/paging_operation.py +9 -9
  17. package/autorest/codegen/models/parameter.py +37 -11
  18. package/autorest/codegen/models/parameter_list.py +11 -4
  19. package/autorest/codegen/models/primitive_schemas.py +2 -2
  20. package/autorest/codegen/models/property.py +1 -1
  21. package/autorest/codegen/models/request_builder.py +7 -6
  22. package/autorest/codegen/models/request_builder_parameter.py +5 -0
  23. package/autorest/codegen/models/request_builder_parameter_list.py +1 -0
  24. package/autorest/codegen/models/schema_response.py +1 -1
  25. package/autorest/codegen/serializers/__init__.py +75 -71
  26. package/autorest/codegen/serializers/builder_serializer.py +68 -37
  27. package/autorest/codegen/serializers/client_serializer.py +14 -3
  28. package/autorest/codegen/serializers/general_serializer.py +7 -7
  29. package/autorest/codegen/serializers/import_serializer.py +44 -46
  30. package/autorest/codegen/serializers/metadata_serializer.py +12 -10
  31. package/autorest/codegen/serializers/utils.py +5 -1
  32. package/autorest/codegen/templates/config.py.jinja2 +2 -7
  33. package/autorest/codegen/templates/lro_operation.py.jinja2 +3 -1
  34. package/autorest/codegen/templates/lro_paging_operation.py.jinja2 +2 -0
  35. package/autorest/codegen/templates/operation.py.jinja2 +8 -2
  36. package/autorest/codegen/templates/operation_group.py.jinja2 +2 -1
  37. package/autorest/codegen/templates/operation_groups_container.py.jinja2 +1 -0
  38. package/autorest/codegen/templates/operation_tools.jinja2 +3 -2
  39. package/autorest/codegen/templates/paging_operation.py.jinja2 +3 -1
  40. package/autorest/codegen/templates/request_builder.py.jinja2 +2 -7
  41. package/autorest/codegen/templates/service_client.py.jinja2 +1 -1
  42. package/autorest/multiapi/models/imports.py +1 -1
  43. package/autorest/multiapi/serializers/import_serializer.py +1 -1
  44. package/autorest/namer/name_converter.py +1 -1
  45. package/package.json +2 -2
  46. package/run-python3.js +1 -7
  47. package/venvtools.py +2 -2
@@ -27,12 +27,16 @@ from ..models import (
27
27
  SchemaResponse,
28
28
  IOSchema,
29
29
  ParameterStyle,
30
+ ParameterLocation
30
31
  )
31
32
  from . import utils
32
33
 
33
34
  T = TypeVar("T")
34
35
  OrderedSet = Dict[T, None]
35
36
 
37
+ def _escape_str(input_str: str) -> str:
38
+ replace = input_str.replace("'", "\\'")
39
+ return f'"{replace}"'
36
40
 
37
41
  def _improve_json_string(template_representation: str) -> Any:
38
42
  origin = template_representation.split('\n')
@@ -110,7 +114,7 @@ def _pop_parameters_kwarg(
110
114
  function_name: str,
111
115
  kwarg_name: str,
112
116
  ) -> str:
113
- return f'{function_name}_parameters = kwargs.pop("{kwarg_name}", {{}}) # type: Dict[str, Any]'
117
+ return f'_{function_name}_parameters = kwargs.pop("{kwarg_name}", {{}}) # type: Dict[str, Any]'
114
118
 
115
119
  def _serialize_grouped_body(builder) -> List[str]:
116
120
  retval: List[str] = []
@@ -149,12 +153,21 @@ def _serialize_flattened_body(builder) -> List[str]:
149
153
  return retval
150
154
 
151
155
  def _content_type_docstring(builder) -> str:
152
- content_type_str = (
153
- ":keyword str content_type: Media type of the body sent to the API. " +
154
- f'Default value is "{builder.parameters.default_content_type}". ' +
155
- 'Allowed values are: "{}."'.format('", "'.join(builder.parameters.content_types))
156
+ content_types = [f'"{c}"' for c in builder.parameters.content_types]
157
+ if len(content_types) == 2:
158
+ possible_values_str = " or ".join(content_types)
159
+ else:
160
+ possible_values_str = ", ".join(
161
+ content_types[: len(content_types) - 1]
162
+ ) + f", and {content_types[-1]}"
163
+ default_value = next(
164
+ p for p in builder.parameters.method if p.rest_api_name == "Content-Type"
165
+ ).default_value_declaration
166
+ return (
167
+ ":keyword content_type: Media type of the body sent to the API. " +
168
+ f"Possible values are: {possible_values_str}. " +
169
+ f"Default value is {default_value}."
156
170
  )
157
- return content_type_str
158
171
 
159
172
  class _BuilderSerializerProtocol(ABC):
160
173
  @property
@@ -180,11 +193,6 @@ class _BuilderSerializerProtocol(ABC):
180
193
  """Whether you want inline type hints. If false, your type hints will be commented'"""
181
194
  ...
182
195
 
183
- @abstractmethod
184
- def _method_signature(self, builder) -> str:
185
- """Signature of the builder. Does not include return type annotation"""
186
- ...
187
-
188
196
  @abstractmethod
189
197
  def _response_type_annotation(self, builder, modify_if_head_as_boolean: bool = True) -> str:
190
198
  """The mypy type annotation for the response"""
@@ -266,20 +274,22 @@ class _BuilderBaseSerializer(_BuilderSerializerProtocol): # pylint: disable=abs
266
274
  def _cls_docstring_rtype(self) -> str:
267
275
  return "" if self.code_model.options["version_tolerant"] else " or the result of cls(response)"
268
276
 
269
- def _method_signature(self, builder) -> str:
277
+ def _method_signature(self, builder: Operation, response_type_annotation: str) -> str:
270
278
  return utils.serialize_method(
271
279
  function_def=self._function_definition,
272
280
  method_name=builder.name,
273
281
  is_in_class=self._is_in_class,
274
282
  method_param_signatures=builder.parameters.method_signature(self._want_inline_type_hints),
283
+ ignore_inconsistent_return_statements=(response_type_annotation == "None")
275
284
  )
276
285
 
277
286
  def _response_type_annotation_wrapper(self, builder) -> List[str]:
278
287
  return []
279
288
 
280
289
  def method_signature_and_response_type_annotation(self, builder) -> str:
281
- method_signature = self._method_signature(builder)
282
290
  response_type_annotation = self._response_type_annotation(builder)
291
+ # want pre-wrapped response type. As long as it's None, pylint will get mad about inconsistent return types
292
+ method_signature = self._method_signature(builder, response_type_annotation)
283
293
  for wrapper in self._response_type_annotation_wrapper(builder)[::-1]:
284
294
  response_type_annotation = f"{wrapper}[{response_type_annotation}]"
285
295
  return self._method_signature_and_response_type_annotation_template(method_signature, response_type_annotation)
@@ -304,13 +314,14 @@ class _BuilderBaseSerializer(_BuilderSerializerProtocol): # pylint: disable=abs
304
314
  description_list.append(
305
315
  f":{param.docstring_type_keyword} { param.serialized_name }: { param.docstring_type }"
306
316
  )
307
- try:
308
- request_builder: RequestBuilder = cast(Operation, builder).request_builder
309
- except AttributeError:
310
- request_builder = cast(RequestBuilder, builder)
311
317
 
312
- if len(request_builder.schema_requests) > 1:
313
- description_list.append(_content_type_docstring(builder))
318
+ if len(builder.parameters.content_types) > 1:
319
+ description_list = [
320
+ _content_type_docstring(builder) if l.startswith(":keyword content_type:") else l
321
+ for l in description_list
322
+ ]
323
+ if not any(l for l in description_list if l.startswith(":keyword content_type:")):
324
+ description_list.append(_content_type_docstring(builder))
314
325
  return description_list
315
326
 
316
327
  def param_description_and_response_docstring(self, builder) -> List[str]:
@@ -402,7 +413,7 @@ class _BuilderBaseSerializer(_BuilderSerializerProtocol): # pylint: disable=abs
402
413
  def _serialize_parameter(
403
414
  self, param: Parameter, function_name: str
404
415
  ) -> List[str]:
405
- set_parameter = "{}_parameters['{}'] = {}".format(
416
+ set_parameter = "_{}_parameters['{}'] = {}".format(
406
417
  function_name,
407
418
  param.rest_api_name,
408
419
  utils.build_serialize_data_call(param, function_name, self.serializer_name)
@@ -499,11 +510,11 @@ class _RequestBuilderBaseSerializer(_BuilderBaseSerializer): # pylint: disable=
499
510
  def create_http_request(self, builder) -> List[str]:
500
511
  retval = ["return HttpRequest("]
501
512
  retval.append(f' method="{builder.method}",')
502
- retval.append(" url=url,")
513
+ retval.append(" url=_url,")
503
514
  if builder.parameters.query:
504
- retval.append(" params=query_parameters,")
515
+ retval.append(" params=_query_parameters,")
505
516
  if builder.parameters.headers:
506
- retval.append(" headers=header_parameters,")
517
+ retval.append(" headers=_header_parameters,")
507
518
  if builder.parameters.has_body:
508
519
  retval.extend([
509
520
  f" {body_kwarg}={body_kwarg},"
@@ -533,6 +544,13 @@ class _RequestBuilderBaseSerializer(_BuilderBaseSerializer): # pylint: disable=
533
544
  ))
534
545
  return retval
535
546
 
547
+ def construct_url(self, builder) -> str:
548
+ if any(o for o in ["low_level_client", "version_tolerant"] if self.code_model.options.get(o)):
549
+ url_value = _escape_str(builder.url)
550
+ else:
551
+ url_value = f'kwargs.pop("template_url", {_escape_str(builder.url)})'
552
+ return f"_url = {url_value}{' # pylint: disable=line-too-long' if len(url_value) > 114 else ''}"
553
+
536
554
  class RequestBuilderGenericSerializer(_RequestBuilderBaseSerializer):
537
555
  @property
538
556
  def _want_inline_type_hints(self) -> bool:
@@ -711,7 +729,7 @@ class _OperationBaseSerializer(_BuilderBaseSerializer): # pylint: disable=abstr
711
729
  )
712
730
  ser_ctxt_name = "serialization_ctxt"
713
731
  ser_ctxt = builder.parameters.body[0].xml_serialization_ctxt if send_xml else None
714
- if ser_ctxt:
732
+ if ser_ctxt and self.code_model.options["models_mode"]:
715
733
  retval.append(f'{ser_ctxt_name} = {{"xml": {{{ser_ctxt}}}}}')
716
734
  serialize_body_call = self._serialize_body_call(
717
735
  builder,
@@ -781,6 +799,7 @@ class _OperationBaseSerializer(_BuilderBaseSerializer): # pylint: disable=abstr
781
799
  builder,
782
800
  request_builder: RequestBuilder,
783
801
  template_url: Optional[str] = None,
802
+ is_next_request: bool = False,
784
803
  ) -> List[str]:
785
804
  retval = []
786
805
  if len(builder.body_kwargs_to_pass_to_request_builder) > 1:
@@ -820,6 +839,16 @@ class _OperationBaseSerializer(_BuilderBaseSerializer): # pylint: disable=abstr
820
839
  parameter.serialized_name not in builder.body_kwargs_to_pass_to_request_builder
821
840
  ):
822
841
  continue
842
+ if (
843
+ is_next_request and
844
+ not bool(builder.next_request_builder) and
845
+ not self.code_model.options["reformat_next_link"] and
846
+ parameter.location == ParameterLocation.Query
847
+ ):
848
+ # if we don't want to reformat query parameters for next link calls
849
+ # in paging operations with a single swagger operation defintion,
850
+ # we skip passing query params when building the next request
851
+ continue
823
852
  high_level_name = cast(RequestBuilderParameter, parameter).name_in_high_level_operation
824
853
  retval.append(f" {parameter.serialized_name}={high_level_name},")
825
854
  if not self.code_model.options["version_tolerant"]:
@@ -986,7 +1015,8 @@ class _OperationBaseSerializer(_BuilderBaseSerializer): # pylint: disable=abstr
986
1015
 
987
1016
  @staticmethod
988
1017
  def get_metadata_url(builder) -> str:
989
- return f"{builder.python_name}.metadata = {{'url': '{ builder.request_builder.url }'}} # type: ignore"
1018
+ url = _escape_str(builder.request_builder.url)
1019
+ return f"{builder.python_name}.metadata = {{'url': { url }}} # type: ignore"
990
1020
 
991
1021
  class _SyncOperationBaseSerializer(_OperationBaseSerializer): # pylint: disable=abstract-method
992
1022
  @property
@@ -1065,11 +1095,13 @@ class _PagingOperationBaseSerializer(_OperationBaseSerializer): # pylint: disab
1065
1095
  else:
1066
1096
  request_builder = builder.request_builder
1067
1097
  template_url = "next_link"
1098
+
1068
1099
  request_builder = builder.next_request_builder or builder.request_builder
1069
1100
  return self._call_request_builder_helper(
1070
1101
  builder,
1071
1102
  request_builder,
1072
1103
  template_url=template_url,
1104
+ is_next_request=True
1073
1105
  )
1074
1106
 
1075
1107
  def _prepare_request_callback(self, builder) -> List[str]:
@@ -1114,7 +1146,7 @@ class _PagingOperationBaseSerializer(_OperationBaseSerializer): # pylint: disab
1114
1146
  deserialized = (
1115
1147
  f'self._deserialize("{response.serialization_type}", pipeline_response)'
1116
1148
  if self.code_model.options["models_mode"] else
1117
- "_loads(pipeline_response.http_response.body())"
1149
+ "pipeline_response.http_response.json()"
1118
1150
  )
1119
1151
  retval.append(f" deserialized = {deserialized}")
1120
1152
  item_name = builder.item_name(self.code_model)
@@ -1137,10 +1169,11 @@ class _PagingOperationBaseSerializer(_OperationBaseSerializer): # pylint: disab
1137
1169
  retval = [f"{self._def} get_next(next_link=None):"]
1138
1170
  retval.append(" request = prepare_request(next_link)")
1139
1171
  retval.append("")
1140
- retval.append(
1141
- f" pipeline_response = {self._call_method}self._client._pipeline.run(request, "
1142
- f"stream={builder.is_stream_response}, **kwargs)"
1143
- )
1172
+ retval.append(f" pipeline_response = {self._call_method}self._client._pipeline.run( # pylint: disable=protected-access")
1173
+ retval.append(" request,")
1174
+ retval.append(f" stream={builder.is_stream_response},")
1175
+ retval.append(" **kwargs")
1176
+ retval.append(" )")
1144
1177
  retval.append(" response = pipeline_response.http_response")
1145
1178
  retval.append("")
1146
1179
  retval.extend([
@@ -1234,7 +1267,7 @@ class _LROOperationBaseSerializer(_OperationBaseSerializer): # pylint: disable=
1234
1267
  "Pass in False for this operation to not poll, or pass in your own initialized polling object for a"
1235
1268
  " personal polling strategy."
1236
1269
  )
1237
- retval.append(f":paramtype polling: bool or ~{self._polling_method_type}")
1270
+ retval.append(f":paramtype polling: bool or ~azure.core.polling.{self._polling_method_type}")
1238
1271
  retval.append(
1239
1272
  ":keyword int polling_interval: Default waiting time between two polls for LRO operations "
1240
1273
  "if no Retry-After header is present."
@@ -1287,9 +1320,8 @@ class _LROOperationBaseSerializer(_OperationBaseSerializer): # pylint: disable=
1287
1320
  retval.append(" client=self._client,")
1288
1321
  retval.append(" deserialization_callback=get_long_running_output")
1289
1322
  retval.append(" )")
1290
- retval.append("else:")
1291
1323
  retval.append(
1292
- f" return {self._poller(builder)}"
1324
+ f"return {self._poller(builder)}"
1293
1325
  "(self._client, raw_result, get_long_running_output, polling_method)"
1294
1326
  )
1295
1327
  return retval
@@ -1335,7 +1367,7 @@ class _SyncLROOperationBaseSerializer(_LROOperationBaseSerializer, _SyncOperatio
1335
1367
 
1336
1368
  @property
1337
1369
  def _polling_method_type(self):
1338
- return "azure.core.polling.PollingMethod"
1370
+ return "PollingMethod"
1339
1371
 
1340
1372
  def _poller(self, builder) -> str:
1341
1373
  return builder.get_poller(async_mode=False)
@@ -1368,7 +1400,7 @@ class AsyncLROOperationSerializer(_LROOperationBaseSerializer, AsyncOperationSer
1368
1400
 
1369
1401
  @property
1370
1402
  def _polling_method_type(self):
1371
- return "azure.core.polling.AsyncPollingMethod"
1403
+ return "AsyncPollingMethod"
1372
1404
 
1373
1405
  def _poller(self, builder) -> str:
1374
1406
  return builder.get_poller(async_mode=True)
@@ -1383,8 +1415,7 @@ class _LROPagingOperationBaseSerializer(_LROOperationBaseSerializer, _PagingOper
1383
1415
  retval.append(f" {self._def} internal_get_next(next_link=None):")
1384
1416
  retval.append(" if next_link is None:")
1385
1417
  retval.append(" return pipeline_response")
1386
- retval.append(" else:")
1387
- retval.append(f" return {self._call_method}get_next(next_link)")
1418
+ retval.append(f" return {self._call_method}get_next(next_link)")
1388
1419
  retval.append("")
1389
1420
  retval.append(f" return {self._pager(builder)}(")
1390
1421
  retval.append(" internal_get_next, extract_data")
@@ -44,9 +44,12 @@ class ClientSerializer:
44
44
  base_class = f"{class_name}OperationsMixin"
45
45
  elif not (async_mode or self.is_python3_file):
46
46
  base_class = "object"
47
+ disable = ""
48
+ if len(self.code_model.operation_groups) > 6:
49
+ disable = " # pylint: disable=too-many-instance-attributes"
47
50
  if base_class:
48
- return f"class {class_name}({base_class}):"
49
- return f"class {class_name}:"
51
+ return f"class {class_name}({base_class}):{disable}"
52
+ return f"class {class_name}:{disable}"
50
53
 
51
54
  def property_descriptions(self, async_mode: bool) -> List[str]:
52
55
  retval: List[str] = []
@@ -113,7 +116,7 @@ class ClientSerializer:
113
116
  method_name=self.code_model.send_request_name,
114
117
  is_in_class=True,
115
118
  method_param_signatures=self.code_model.service_client.send_request_signature(
116
- async_mode, async_mode or self.is_python3_file
119
+ async_mode or self.is_python3_file
117
120
  ),
118
121
  )
119
122
 
@@ -227,3 +230,11 @@ class ConfigSerializer:
227
230
  for p in self.code_model.global_parameters.config_method
228
231
  if p.required and not p.constant
229
232
  ]
233
+
234
+ def property_descriptions(self) -> List[str]:
235
+ retval: List[str] = []
236
+ for p in self.code_model.global_parameters.config_method:
237
+ retval.append(f":{p.description_keyword} {p.serialized_name}: {p.description}")
238
+ retval.append(f":{p.docstring_type_keyword} {p.serialized_name}: {p.docstring_type}")
239
+ retval.append('"""')
240
+ return retval
@@ -10,17 +10,17 @@ from .client_serializer import ClientSerializer, ConfigSerializer
10
10
 
11
11
  def config_imports(code_model, global_parameters: ParameterList, async_mode: bool) -> FileImport:
12
12
  file_import = FileImport()
13
- file_import.add_from_import("azure.core.configuration", "Configuration", ImportType.AZURECORE)
14
- file_import.add_from_import("azure.core.pipeline", "policies", ImportType.AZURECORE)
15
- file_import.add_from_import("typing", "Any", ImportType.STDLIB, TypingSection.CONDITIONAL)
13
+ file_import.add_submodule_import("azure.core.configuration", "Configuration", ImportType.AZURECORE)
14
+ file_import.add_submodule_import("azure.core.pipeline", "policies", ImportType.AZURECORE)
15
+ file_import.add_submodule_import("typing", "Any", ImportType.STDLIB, TypingSection.CONDITIONAL)
16
16
  if code_model.options["package_version"]:
17
- file_import.add_from_import(".._version" if async_mode else "._version", "VERSION", ImportType.LOCAL)
17
+ file_import.add_submodule_import(".._version" if async_mode else "._version", "VERSION", ImportType.LOCAL)
18
18
  for gp in global_parameters:
19
19
  file_import.merge(gp.imports())
20
20
  if code_model.options["azure_arm"]:
21
21
  policy = "AsyncARMChallengeAuthenticationPolicy" if async_mode else "ARMChallengeAuthenticationPolicy"
22
- file_import.add_from_import("azure.mgmt.core.policies", "ARMHttpLoggingPolicy", ImportType.AZURECORE)
23
- file_import.add_from_import("azure.mgmt.core.policies", policy, ImportType.AZURECORE)
22
+ file_import.add_submodule_import("azure.mgmt.core.policies", "ARMHttpLoggingPolicy", ImportType.AZURECORE)
23
+ file_import.add_submodule_import("azure.mgmt.core.policies", policy, ImportType.AZURECORE)
24
24
  return file_import
25
25
 
26
26
 
@@ -71,7 +71,7 @@ class GeneralSerializer:
71
71
  # configure imports
72
72
  file_import = FileImport()
73
73
  if self.code_model.need_request_converter:
74
- file_import.add_from_import(
74
+ file_import.add_submodule_import(
75
75
  "azure.core.pipeline.transport",
76
76
  "HttpRequest",
77
77
  ImportType.AZURECORE,
@@ -4,75 +4,73 @@
4
4
  # license information.
5
5
  # --------------------------------------------------------------------------
6
6
  from copy import deepcopy
7
- from typing import Dict, Set, Optional, List, Tuple, Union
8
- from ..models.imports import ImportType, FileImport, TypingSection
7
+ from typing import List
8
+ from ..models.imports import ImportType, FileImport, ImportModel, TypingSection
9
9
 
10
10
  def _serialize_package(
11
- package_name: str, module_list: Set[Optional[Union[str, Tuple[str, str]]]], delimiter: str
11
+ imports: List[ImportModel], delimiter: str
12
12
  ) -> str:
13
13
  buffer = []
14
- if None in module_list:
15
- buffer.append(f"import {package_name}")
16
- if module_list != {None}:
17
- buffer.append(
18
- "from {} import {}".format(
19
- package_name, ", ".join(sorted([
20
- mod if isinstance(mod, str) else f"{mod[0]} as {mod[1]}" for mod in module_list if mod is not None
21
- ]))
22
- )
23
- )
14
+ if any(i for i in imports if i.submodule_name is None):
15
+ buffer.append(f"import {imports[0].module_name}")
16
+ else:
17
+ import_str = ", ".join(sorted([
18
+ f"{i.submodule_name} as {i.alias}" if i.alias else i.submodule_name for i in imports # type: ignore
19
+ ]))
20
+ buffer.append(f"from {imports[0].module_name} import {import_str}")
24
21
  return delimiter.join(buffer)
25
22
 
26
- def _serialize_type(import_type_dict: Dict[str, Set[Optional[Union[str, Tuple[str, str]]]]], delimiter: str) -> str:
23
+ def _serialize_import_type(imports: List[ImportModel], delimiter: str) -> str:
27
24
  """Serialize a given import type."""
28
25
  import_list = []
29
- for package_name in sorted(list(import_type_dict.keys())):
30
- module_list = import_type_dict[package_name]
31
- import_list.append(_serialize_package(package_name, module_list, delimiter))
26
+ for module_name in sorted(set(i.module_name for i in imports)):
27
+
28
+ import_list.append(_serialize_package([
29
+ i for i in imports if i.module_name == module_name
30
+ ], delimiter))
32
31
  return delimiter.join(import_list)
33
32
 
34
33
  def _get_import_clauses(
35
- imports: Dict[ImportType, Dict[str, Set[Optional[Union[str, Tuple[str, str]]]]]], delimiter: str
34
+ imports: List[ImportModel], delimiter: str
36
35
  ) -> List[str]:
37
36
  import_clause = []
38
37
  for import_type in ImportType:
39
- if import_type in imports:
40
- import_clause.append(_serialize_type(imports[import_type], delimiter))
38
+ imports_with_import_type = [i for i in imports if i.import_type == import_type]
39
+ if imports_with_import_type:
40
+ import_clause.append(_serialize_import_type(imports_with_import_type, delimiter))
41
41
  return import_clause
42
42
 
43
43
 
44
44
  class FileImportSerializer:
45
45
  def __init__(self, file_import: FileImport, is_python3_file: bool, async_mode: bool = False) -> None:
46
- self._file_import = file_import
46
+ self.file_import = file_import
47
47
  self.is_python3_file = is_python3_file
48
48
  self.async_mode = async_mode
49
49
 
50
- def _switch_typing_section_key(self, new_key: TypingSection):
51
- switched_dictionary = {}
52
- switched_dictionary[new_key] = self._file_import.imports[TypingSection.CONDITIONAL]
53
- return switched_dictionary
54
-
55
- def _get_imports_dict(self, baseline_typing_section: TypingSection, add_conditional_typing: bool):
50
+ def _get_imports_list(self, baseline_typing_section: TypingSection, add_conditional_typing: bool):
56
51
  # If this is a python 3 file, our regular imports include the CONDITIONAL category
57
52
  # If this is not a python 3 file, our typing imports include the CONDITIONAL category
58
- file_import_copy = deepcopy(self._file_import)
59
- if add_conditional_typing and self._file_import.imports.get(TypingSection.CONDITIONAL):
53
+ file_import_copy = deepcopy(self.file_import)
54
+ if add_conditional_typing and any(
55
+ self.file_import.get_imports_from_section(TypingSection.CONDITIONAL)
56
+ ):
60
57
  # we switch the TypingSection key for the CONDITIONAL typing imports so we can merge
61
58
  # the imports together
62
- switched_imports_dictionary = self._switch_typing_section_key(baseline_typing_section)
63
- switched_imports = FileImport(switched_imports_dictionary)
64
- file_import_copy.merge(switched_imports)
65
- return file_import_copy.imports.get(baseline_typing_section, {})
59
+ for i in file_import_copy.imports:
60
+ if i.typing_section == TypingSection.CONDITIONAL:
61
+ i.typing_section = baseline_typing_section
62
+ return file_import_copy.get_imports_from_section(baseline_typing_section)
66
63
 
67
64
  def _add_type_checking_import(self):
68
- if (
69
- self._file_import.imports.get(TypingSection.TYPING) or
70
- (not self.is_python3_file and self._file_import.imports.get(TypingSection.CONDITIONAL))
71
- ):
72
- self._file_import.add_from_import("typing", "TYPE_CHECKING", ImportType.STDLIB)
65
+ any_typing = any(self.file_import.get_imports_from_section(TypingSection.TYPING))
66
+ conditional_and_not_py3 = not self.is_python3_file and any(
67
+ self.file_import.get_imports_from_section(TypingSection.CONDITIONAL)
68
+ )
69
+ if any_typing or conditional_and_not_py3:
70
+ self.file_import.add_submodule_import("typing", "TYPE_CHECKING", ImportType.STDLIB)
73
71
 
74
72
  def _get_typing_definitions(self) -> str:
75
- if not self._file_import.type_definitions:
73
+ if not self.file_import.type_definitions:
76
74
  return ""
77
75
  spacing = "" if self.is_python3_file else " "
78
76
  declarations: List[str] = [f"\n{spacing}T = TypeVar('T')"]
@@ -82,27 +80,27 @@ class FileImportSerializer:
82
80
  type_name,
83
81
  values[1] if self.async_mode else values[0]
84
82
  )
85
- for type_name, values in self._file_import.type_definitions.items()
83
+ for type_name, values in self.file_import.type_definitions.items()
86
84
  ])
87
85
  return "\n".join(declarations)
88
86
 
89
87
  def __str__(self) -> str:
90
88
  self._add_type_checking_import()
91
89
  regular_imports = ""
92
- regular_imports_dict = self._get_imports_dict(
90
+ regular_imports_list = self._get_imports_list(
93
91
  baseline_typing_section=TypingSection.REGULAR, add_conditional_typing=self.is_python3_file
94
92
  )
95
93
 
96
- if regular_imports_dict:
94
+ if regular_imports_list:
97
95
  regular_imports = "\n\n".join(
98
- _get_import_clauses(regular_imports_dict, "\n")
96
+ _get_import_clauses(regular_imports_list, "\n")
99
97
  )
100
98
 
101
99
  typing_imports = ""
102
- typing_imports_dict = self._get_imports_dict(
100
+ typing_imports_list = self._get_imports_list(
103
101
  baseline_typing_section=TypingSection.TYPING, add_conditional_typing=not self.is_python3_file
104
102
  )
105
- if typing_imports_dict:
103
+ if typing_imports_list:
106
104
  typing_imports += "\n\nif TYPE_CHECKING:\n # pylint: disable=unused-import,ungrouped-imports\n "
107
- typing_imports += "\n\n ".join(_get_import_clauses(typing_imports_dict, "\n "))
105
+ typing_imports += "\n\n ".join(_get_import_clauses(typing_imports_list, "\n "))
108
106
  return regular_imports + typing_imports + self._get_typing_definitions()
@@ -62,7 +62,7 @@ def _mixin_imports(mixin_operation_group: Optional[OperationGroup]) -> Tuple[Opt
62
62
  sync_mixin_imports = mixin_operation_group.imports_for_multiapi(async_mode=False)
63
63
  async_mixin_imports = mixin_operation_group.imports_for_multiapi(async_mode=True)
64
64
 
65
- return _json_serialize_imports(sync_mixin_imports.imports), _json_serialize_imports(async_mixin_imports.imports)
65
+ return _json_serialize_imports(sync_mixin_imports.to_dict()), _json_serialize_imports(async_mixin_imports.to_dict())
66
66
 
67
67
 
68
68
  class MetadataSerializer:
@@ -102,20 +102,22 @@ class MetadataSerializer:
102
102
  file_import = FileImport()
103
103
  for gp in global_parameters:
104
104
  file_import.merge(gp.imports())
105
- file_import.add_from_import("azure.profiles", "KnownProfiles", import_type=ImportType.AZURECORE)
106
- file_import.add_from_import("azure.profiles", "ProfileDefinition", import_type=ImportType.AZURECORE)
107
- file_import.add_from_import(
105
+ file_import.add_submodule_import("azure.profiles", "KnownProfiles", import_type=ImportType.AZURECORE)
106
+ file_import.add_submodule_import("azure.profiles", "ProfileDefinition", import_type=ImportType.AZURECORE)
107
+ file_import.add_submodule_import(
108
108
  "azure.profiles.multiapiclient", "MultiApiClientMixin", import_type=ImportType.AZURECORE
109
109
  )
110
- file_import.add_from_import("._configuration", f"{self.code_model.class_name}Configuration", ImportType.LOCAL)
110
+ file_import.add_submodule_import(
111
+ "._configuration", f"{self.code_model.class_name}Configuration", ImportType.LOCAL
112
+ )
111
113
  # api_version and potentially endpoint require Optional typing
112
- file_import.add_from_import("typing", "Optional", ImportType.STDLIB, TypingSection.CONDITIONAL)
114
+ file_import.add_submodule_import("typing", "Optional", ImportType.STDLIB, TypingSection.CONDITIONAL)
113
115
  if mixin_operation_group:
114
- file_import.add_from_import(
116
+ file_import.add_submodule_import(
115
117
  "._operations_mixin", f"{self.code_model.class_name}OperationsMixin", ImportType.LOCAL
116
118
  )
117
119
  file_import.merge(self.code_model.service_client.imports_for_multiapi(async_mode=async_mode))
118
- return _json_serialize_imports(file_import.imports)
120
+ return _json_serialize_imports(file_import.to_dict())
119
121
 
120
122
  def serialize(self) -> str:
121
123
  def _is_lro(operation):
@@ -179,10 +181,10 @@ class MetadataSerializer:
179
181
  sync_client_imports=sync_client_imports,
180
182
  async_client_imports=async_client_imports,
181
183
  sync_config_imports=_json_serialize_imports(
182
- config_imports(self.code_model, self.code_model.global_parameters, async_mode=False).imports
184
+ config_imports(self.code_model, self.code_model.global_parameters, async_mode=False).to_dict()
183
185
  ),
184
186
  async_config_imports=_json_serialize_imports(
185
- config_imports(self.code_model, async_global_parameters, async_mode=True).imports
187
+ config_imports(self.code_model, async_global_parameters, async_mode=True).to_dict()
186
188
  ),
187
189
  get_async_operation_serializer=functools.partial(
188
190
  get_operation_serializer, code_model=self.code_model, async_mode=True, is_python3_file=True
@@ -13,9 +13,13 @@ def serialize_method(
13
13
  method_name: str,
14
14
  is_in_class: bool,
15
15
  method_param_signatures: List[str],
16
+ ignore_inconsistent_return_statements: bool = False,
16
17
  ):
17
18
  lines: List[str] = []
18
- lines.append(f"{function_def} {method_name}(")
19
+ first_line = f"{function_def} {method_name}("
20
+ if ignore_inconsistent_return_statements:
21
+ first_line += " # pylint: disable=inconsistent-return-statements"
22
+ lines.append(first_line)
19
23
  if is_in_class:
20
24
  lines.append(" self,")
21
25
  lines.extend([
@@ -11,7 +11,7 @@
11
11
  VERSION = "unknown"
12
12
  {% endif %}
13
13
 
14
- class {{ code_model.class_name }}Configuration(Configuration):
14
+ class {{ code_model.class_name }}Configuration(Configuration): # pylint: disable=too-many-instance-attributes
15
15
  """Configuration for {{ code_model.class_name }}.
16
16
 
17
17
  Note that all parameters used to create this instance are saved as instance
@@ -19,12 +19,7 @@ class {{ code_model.class_name }}Configuration(Configuration):
19
19
  {% if code_model.global_parameters.config_method | first %}
20
20
 
21
21
  {% endif %}
22
- {% for parameter in code_model.global_parameters.config_method %}
23
- :{{ parameter.description_keyword }} {{ parameter.serialized_name }}: {{ parameter.description }}
24
- :{{ parameter.docstring_type_keyword }} {{ parameter.serialized_name }}: {{ parameter.docstring_type }}
25
- {% endfor %}
26
- """
27
-
22
+ {{ op_tools.serialize_with_wrap(serializer.property_descriptions(), "\n ") | indent }}
28
23
  {{ serializer.init_signature_and_response_type_annotation(async_mode) | indent }}
29
24
  super({{ code_model.class_name }}Configuration, self).__init__(**kwargs)
30
25
  {% if code_model.service_client.parameters.config_kwargs_to_pop(async_mode) %}
@@ -13,4 +13,6 @@
13
13
  {{ op_tools.serialize(operation_serializer.get_long_running_output(operation)) | indent }}
14
14
 
15
15
  {{ op_tools.serialize(operation_serializer.return_lro_poller(operation)) | indent }}
16
- {{ operation_serializer.get_metadata_url(operation) }}
16
+ {% if not code_model.options["version_tolerant"] %}
17
+ {{ operation_serializer.get_metadata_url(operation) -}}
18
+ {% endif %}
@@ -15,4 +15,6 @@
15
15
  {{ op_tools.serialize(operation_serializer.initial_call(operation)) | indent }}
16
16
  {{ op_tools.serialize(operation_serializer.get_long_running_output(operation)) | indent }}
17
17
  {{ op_tools.serialize(operation_serializer.return_lro_poller(operation)) | indent }}
18
+ {% if not code_model.options["version_tolerant"] %}
18
19
  {{ operation_serializer.get_metadata_url(operation) }}
20
+ {% endif %}
@@ -18,6 +18,12 @@
18
18
  {{ op_tools.serialize(operation_serializer.pop_kwargs_from_signature(operation)) | indent }}
19
19
  {% endif %}
20
20
  {{ op_tools.serialize(operation_serializer.call_request_builder(operation)) | indent }}
21
- pipeline_response = {{ keywords.await }}self._client._pipeline.run(request, {{ stream_request_parameter }}, **kwargs)
21
+ pipeline_response = {{ keywords.await }}self._client._pipeline.run( # pylint: disable=protected-access
22
+ request,
23
+ {{ stream_request_parameter }},
24
+ **kwargs
25
+ )
22
26
  {{ op_tools.serialize(operation_serializer.handle_response(operation)) | indent }}
23
- {{ operation.python_name }}.metadata = {'url': {{ keywords.escape_str(request_builder.url) }}} # type: ignore
27
+ {% if not code_model.options["version_tolerant"] %}
28
+ {{ operation_serializer.get_metadata_url(operation) }}
29
+ {% endif %}
@@ -1,4 +1,5 @@
1
- class {{ operation_group.class_name }}{{ object_base_class }}:
1
+ {% set disable = " # pylint: disable=too-many-public-methods" if operation_group.operations | length > 20 else "" %}
2
+ class {{ operation_group.class_name }}{{ object_base_class }}:{{ disable }}
2
3
  {% if not operation_group.is_empty_operation_group %}
3
4
  """{{ operation_group.class_name }} {{ operations_description }}.
4
5
 
@@ -2,6 +2,7 @@
2
2
  {% set object_base_class = "" if async_mode else "(object)" %}
3
3
  {% set operations_description = "async operations" if async_mode else "operations" %}
4
4
  {% set return_none_type_annotation = " -> None" if async_mode else "" %}
5
+ # pylint: disable=too-many-lines
5
6
  # coding=utf-8
6
7
  {{ code_model.options['license_header'] }}
7
8
  {{ imports }}