@autorest/python 5.13.0 → 5.16.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 (101) hide show
  1. package/ChangeLog.md +67 -0
  2. package/autorest/__init__.py +1 -2
  3. package/autorest/black/__init__.py +12 -5
  4. package/autorest/codegen/__init__.py +239 -105
  5. package/autorest/codegen/models/__init__.py +29 -18
  6. package/autorest/codegen/models/base_builder.py +48 -11
  7. package/autorest/codegen/models/base_model.py +6 -4
  8. package/autorest/codegen/models/base_schema.py +21 -24
  9. package/autorest/codegen/models/client.py +70 -20
  10. package/autorest/codegen/models/code_model.py +144 -129
  11. package/autorest/codegen/models/constant_schema.py +32 -16
  12. package/autorest/codegen/models/credential_model.py +55 -0
  13. package/autorest/codegen/models/credential_schema.py +21 -16
  14. package/autorest/codegen/models/credential_schema_policy.py +11 -15
  15. package/autorest/codegen/models/dictionary_schema.py +27 -24
  16. package/autorest/codegen/models/enum_schema.py +41 -62
  17. package/autorest/codegen/models/imports.py +72 -41
  18. package/autorest/codegen/models/list_schema.py +40 -18
  19. package/autorest/codegen/models/lro_operation.py +61 -25
  20. package/autorest/codegen/models/lro_paging_operation.py +5 -6
  21. package/autorest/codegen/models/object_schema.py +113 -59
  22. package/autorest/codegen/models/operation.py +251 -111
  23. package/autorest/codegen/models/operation_group.py +67 -32
  24. package/autorest/codegen/models/paging_operation.py +48 -21
  25. package/autorest/codegen/models/parameter.py +182 -90
  26. package/autorest/codegen/models/parameter_list.py +184 -163
  27. package/autorest/codegen/models/primitive_schemas.py +89 -70
  28. package/autorest/codegen/models/property.py +49 -31
  29. package/autorest/codegen/models/request_builder.py +67 -32
  30. package/autorest/codegen/models/request_builder_parameter.py +54 -23
  31. package/autorest/codegen/models/request_builder_parameter_list.py +77 -108
  32. package/autorest/codegen/models/schema_request.py +16 -6
  33. package/autorest/codegen/models/schema_response.py +35 -17
  34. package/autorest/codegen/models/utils.py +24 -1
  35. package/autorest/codegen/serializers/__init__.py +273 -89
  36. package/autorest/codegen/serializers/builder_serializer.py +711 -333
  37. package/autorest/codegen/serializers/client_serializer.py +114 -43
  38. package/autorest/codegen/serializers/general_serializer.py +84 -25
  39. package/autorest/codegen/serializers/import_serializer.py +93 -31
  40. package/autorest/codegen/serializers/metadata_serializer.py +73 -24
  41. package/autorest/codegen/serializers/model_base_serializer.py +42 -14
  42. package/autorest/codegen/serializers/model_generic_serializer.py +1 -4
  43. package/autorest/codegen/serializers/model_init_serializer.py +5 -1
  44. package/autorest/codegen/serializers/model_python3_serializer.py +9 -8
  45. package/autorest/codegen/serializers/operation_groups_serializer.py +20 -8
  46. package/autorest/codegen/serializers/operations_init_serializer.py +23 -11
  47. package/autorest/codegen/serializers/patch_serializer.py +14 -2
  48. package/autorest/codegen/serializers/{rest_serializer.py → request_builders_serializer.py} +29 -12
  49. package/autorest/codegen/serializers/utils.py +60 -21
  50. package/autorest/codegen/templates/CHANGELOG.md.jinja2 +6 -0
  51. package/autorest/codegen/templates/LICENSE.jinja2 +21 -0
  52. package/autorest/codegen/templates/MANIFEST.in.jinja2 +7 -0
  53. package/autorest/codegen/templates/README.md.jinja2 +105 -0
  54. package/autorest/codegen/templates/config.py.jinja2 +4 -4
  55. package/autorest/codegen/templates/dev_requirements.txt.jinja2 +10 -0
  56. package/autorest/codegen/templates/enum.py.jinja2 +1 -1
  57. package/autorest/codegen/templates/enum_container.py.jinja2 +0 -1
  58. package/autorest/codegen/templates/init.py.jinja2 +9 -6
  59. package/autorest/codegen/templates/keywords.jinja2 +14 -1
  60. package/autorest/codegen/templates/lro_operation.py.jinja2 +5 -7
  61. package/autorest/codegen/templates/lro_paging_operation.py.jinja2 +5 -7
  62. package/autorest/codegen/templates/metadata.json.jinja2 +10 -9
  63. package/autorest/codegen/templates/model.py.jinja2 +1 -6
  64. package/autorest/codegen/templates/model_init.py.jinja2 +7 -4
  65. package/autorest/codegen/templates/operation.py.jinja2 +8 -11
  66. package/autorest/codegen/templates/operation_group.py.jinja2 +15 -18
  67. package/autorest/codegen/templates/operation_groups_container.py.jinja2 +1 -2
  68. package/autorest/codegen/templates/operations_folder_init.py.jinja2 +4 -0
  69. package/autorest/codegen/templates/paging_operation.py.jinja2 +7 -8
  70. package/autorest/codegen/templates/patch.py.jinja2 +18 -29
  71. package/autorest/codegen/templates/request_builder.py.jinja2 +19 -14
  72. package/autorest/codegen/templates/setup.py.jinja2 +79 -20
  73. package/autorest/codegen/templates/vendor.py.jinja2 +12 -2
  74. package/autorest/jsonrpc/__init__.py +7 -12
  75. package/autorest/jsonrpc/localapi.py +4 -3
  76. package/autorest/jsonrpc/server.py +13 -6
  77. package/autorest/jsonrpc/stdstream.py +13 -6
  78. package/autorest/m2r/__init__.py +5 -8
  79. package/autorest/multiapi/__init__.py +24 -14
  80. package/autorest/multiapi/models/client.py +21 -11
  81. package/autorest/multiapi/models/code_model.py +23 -10
  82. package/autorest/multiapi/models/config.py +4 -1
  83. package/autorest/multiapi/models/constant_global_parameter.py +1 -0
  84. package/autorest/multiapi/models/global_parameter.py +2 -1
  85. package/autorest/multiapi/models/global_parameters.py +14 -8
  86. package/autorest/multiapi/models/imports.py +35 -18
  87. package/autorest/multiapi/models/mixin_operation.py +5 -5
  88. package/autorest/multiapi/models/operation_group.py +2 -1
  89. package/autorest/multiapi/models/operation_mixin_group.py +21 -10
  90. package/autorest/multiapi/serializers/__init__.py +18 -23
  91. package/autorest/multiapi/serializers/import_serializer.py +47 -15
  92. package/autorest/multiapi/serializers/multiapi_serializer.py +17 -17
  93. package/autorest/multiapi/templates/multiapi_operations_mixin.py.jinja2 +1 -1
  94. package/autorest/multiapi/utils.py +3 -3
  95. package/autorest/namer/__init__.py +2 -4
  96. package/autorest/namer/name_converter.py +200 -103
  97. package/autorest/namer/python_mappings.py +10 -22
  98. package/package.json +3 -3
  99. package/run-python3.js +2 -3
  100. package/venvtools.py +1 -1
  101. package/autorest/codegen/models/rest.py +0 -42
@@ -5,29 +5,40 @@
5
5
  # --------------------------------------------------------------------------
6
6
  from itertools import chain
7
7
  import logging
8
- from typing import cast, Dict, List, Any, Optional, Union, Set
8
+ from typing import cast, Dict, List, Any, Optional, Union, Set, TYPE_CHECKING
9
9
 
10
10
  from .base_builder import BaseBuilder, create_parameters
11
11
  from .imports import FileImport, ImportType, TypingSection
12
12
  from .schema_response import SchemaResponse
13
- from .parameter import Parameter, get_parameter
14
- from .parameter_list import ParameterList, get_parameter_list
13
+ from .parameter import (
14
+ Parameter,
15
+ ParameterMethodLocation,
16
+ get_parameter,
17
+ ParameterLocation,
18
+ )
19
+ from .parameter_list import ParameterList
15
20
  from .base_schema import BaseSchema
16
21
  from .object_schema import ObjectSchema
17
22
  from .request_builder import RequestBuilder
18
23
  from .schema_request import SchemaRequest
19
24
  from .primitive_schemas import IOSchema
20
25
 
26
+ if TYPE_CHECKING:
27
+ from .code_model import CodeModel
28
+
21
29
  _LOGGER = logging.getLogger(__name__)
22
30
 
23
- class Operation(BaseBuilder): # pylint: disable=too-many-public-methods, too-many-instance-attributes
24
- """Represent an self.
25
- """
31
+
32
+ class Operation(
33
+ BaseBuilder
34
+ ): # pylint: disable=too-many-public-methods, too-many-instance-attributes
35
+ """Represent an self."""
26
36
 
27
37
  def __init__(
28
38
  self,
29
- code_model,
30
39
  yaml_data: Dict[str, Any],
40
+ code_model: "CodeModel",
41
+ request_builder: RequestBuilder,
31
42
  name: str,
32
43
  description: str,
33
44
  api_versions: Set[str],
@@ -39,6 +50,8 @@ class Operation(BaseBuilder): # pylint: disable=too-many-public-methods, too-ma
39
50
  exceptions: Optional[List[SchemaResponse]] = None,
40
51
  want_description_docstring: bool = True,
41
52
  want_tracing: bool = True,
53
+ *,
54
+ abstract: bool = False,
42
55
  ) -> None:
43
56
  super().__init__(
44
57
  code_model=code_model,
@@ -49,33 +62,21 @@ class Operation(BaseBuilder): # pylint: disable=too-many-public-methods, too-ma
49
62
  responses=responses,
50
63
  schema_requests=schema_requests,
51
64
  summary=summary,
65
+ abstract=abstract,
66
+ want_tracing=want_tracing,
52
67
  )
53
68
  self.multiple_content_type_parameters = multiple_content_type_parameters
54
69
  self.api_versions = api_versions
55
70
  self.multiple_content_type_parameters = multiple_content_type_parameters
56
71
  self.exceptions = exceptions or []
57
72
  self.want_description_docstring = want_description_docstring
58
- self.want_tracing = want_tracing
59
- self._request_builder: Optional[RequestBuilder] = None
73
+ self.request_builder = request_builder
60
74
  self.deprecated = False
61
75
 
62
76
  @property
63
77
  def python_name(self) -> str:
64
78
  return self.name
65
79
 
66
- @property
67
- def request_builder(self) -> RequestBuilder:
68
- if not self._request_builder:
69
- raise ValueError(
70
- "You're calling request_builder when you haven't linked up operation to its "
71
- "request builder through the code model"
72
- )
73
- return self._request_builder
74
-
75
- @request_builder.setter
76
- def request_builder(self, r: RequestBuilder) -> None:
77
- self._request_builder = r
78
-
79
80
  @property
80
81
  def is_stream_response(self) -> bool:
81
82
  """Is the response expected to be streamable, like a download."""
@@ -93,19 +94,22 @@ class Operation(BaseBuilder): # pylint: disable=too-many-public-methods, too-ma
93
94
 
94
95
  # successful status codes of responses that have bodies
95
96
  status_codes_for_responses_with_bodies = [
96
- code for code in self.success_status_code
97
+ code
98
+ for code in self.success_status_code
97
99
  if isinstance(code, int) and self.get_response_from_status(code).has_body
98
100
  ]
99
101
 
100
102
  successful_responses = [
101
- response for response in self.responses
103
+ response
104
+ for response in self.responses
102
105
  if any(code in self.success_status_code for code in response.status_codes)
103
106
  ]
104
107
 
105
108
  return (
106
- self.has_response_body and
107
- len(successful_responses) > 1 and
108
- len(self.success_status_code) != len(status_codes_for_responses_with_bodies)
109
+ self.has_response_body
110
+ and len(successful_responses) > 1
111
+ and len(self.success_status_code)
112
+ != len(status_codes_for_responses_with_bodies)
109
113
  )
110
114
 
111
115
  @property
@@ -115,9 +119,11 @@ class Operation(BaseBuilder): # pylint: disable=too-many-public-methods, too-ma
115
119
 
116
120
  @property
117
121
  def has_response_body(self) -> bool:
118
- """Tell if at least one response has a body.
119
- """
120
- return any(response.has_body or response.is_stream_response for response in self.responses)
122
+ """Tell if at least one response has a body."""
123
+ return any(
124
+ response.has_body or response.is_stream_response
125
+ for response in self.responses
126
+ )
121
127
 
122
128
  @property
123
129
  def any_response_has_headers(self) -> bool:
@@ -125,30 +131,45 @@ class Operation(BaseBuilder): # pylint: disable=too-many-public-methods, too-ma
125
131
 
126
132
  @property
127
133
  def default_exception(self) -> Optional[str]:
128
- default_excp = [excp for excp in self.exceptions for code in excp.status_codes if code == "default"]
134
+ default_excp = [
135
+ excp
136
+ for excp in self.exceptions
137
+ for code in excp.status_codes
138
+ if code == "default"
139
+ ]
129
140
  if not default_excp:
130
141
  return None
131
142
  excep_schema = default_excp[0].schema
132
143
  if isinstance(excep_schema, ObjectSchema):
133
144
  return f"_models.{excep_schema.name}"
134
145
  # in this case, it's just an AnySchema
135
- return "\'object\'"
146
+ return "'object'"
136
147
 
137
148
  @property
138
149
  def status_code_exceptions(self) -> List[SchemaResponse]:
139
- return [excp for excp in self.exceptions if list(excp.status_codes) != ["default"]]
150
+ return [
151
+ excp for excp in self.exceptions if list(excp.status_codes) != ["default"]
152
+ ]
140
153
 
141
154
  @property
142
155
  def status_code_exceptions_status_codes(self) -> List[Union[str, int]]:
143
156
  """Actually returns all of the status codes from exceptions (besides default)"""
144
- return list(chain.from_iterable([
145
- excp.status_codes for excp in self.status_code_exceptions
146
- ]))
157
+ return list(
158
+ chain.from_iterable(
159
+ [excp.status_codes for excp in self.status_code_exceptions]
160
+ )
161
+ )
147
162
 
148
- def _imports_shared(self, async_mode: bool) -> FileImport: # pylint: disable=unused-argument
163
+ def _imports_shared(
164
+ self, async_mode: bool # pylint: disable=unused-argument
165
+ ) -> FileImport:
149
166
  file_import = FileImport()
150
- file_import.add_submodule_import("typing", "Any", ImportType.STDLIB, TypingSection.CONDITIONAL)
167
+ file_import.add_submodule_import(
168
+ "typing", "Any", ImportType.STDLIB, TypingSection.CONDITIONAL
169
+ )
151
170
  for param in self.parameters.method:
171
+ if self.abstract and (param.is_multipart or param.is_data_input):
172
+ continue
152
173
  file_import.merge(param.imports())
153
174
 
154
175
  for param in self.multiple_content_type_parameters:
@@ -159,104 +180,178 @@ class Operation(BaseBuilder): # pylint: disable=too-many-public-methods, too-ma
159
180
  if response.has_body:
160
181
  file_import.merge(cast(BaseSchema, response.schema).imports())
161
182
 
162
- response_types = [r.operation_type_annotation for r in self.responses if r.has_body]
183
+ response_types = [
184
+ r.type_annotation(is_operation_file=True)
185
+ for r in self.responses
186
+ if r.has_body
187
+ ]
163
188
  if len(set(response_types)) > 1:
164
- file_import.add_submodule_import("typing", "Union", ImportType.STDLIB, TypingSection.CONDITIONAL)
189
+ file_import.add_submodule_import(
190
+ "typing", "Union", ImportType.STDLIB, TypingSection.CONDITIONAL
191
+ )
165
192
 
166
193
  if self.is_stream_response:
167
- file_import.add_submodule_import("typing", "IO", ImportType.STDLIB, TypingSection.CONDITIONAL)
194
+ file_import.add_submodule_import(
195
+ "typing", "IO", ImportType.STDLIB, TypingSection.CONDITIONAL
196
+ )
168
197
  return file_import
169
198
 
170
-
171
- def imports_for_multiapi(self, async_mode: bool) -> FileImport: # pylint: disable=unused-argument
199
+ def imports_for_multiapi(
200
+ self, async_mode: bool
201
+ ) -> FileImport: # pylint: disable=unused-argument
172
202
  return self._imports_shared(async_mode)
173
203
 
174
- def imports(self, async_mode: bool) -> FileImport:
204
+ def imports(self, async_mode: bool, is_python3_file: bool) -> FileImport:
205
+ file_import = self._imports_base(async_mode, is_python3_file)
206
+ if self.abstract:
207
+ return file_import
208
+ if (
209
+ self.has_response_body
210
+ and not self.has_optional_return_type
211
+ and not self.code_model.options["models_mode"]
212
+ ):
213
+ file_import.add_submodule_import("typing", "cast", ImportType.STDLIB)
214
+ return file_import
215
+
216
+ @staticmethod
217
+ def has_kwargs_to_pop_with_default(
218
+ kwargs_to_pop: List[Parameter], location: ParameterLocation
219
+ ) -> bool:
220
+ return any(
221
+ kwarg.has_default_value and kwarg.location == location
222
+ for kwarg in kwargs_to_pop
223
+ )
224
+
225
+ def _imports_base(self, async_mode: bool, is_python3_file: bool) -> FileImport:
175
226
  file_import = self._imports_shared(async_mode)
176
227
 
177
228
  # Exceptions
178
- file_import.add_submodule_import("azure.core.exceptions", "map_error", ImportType.AZURECORE)
179
- if self.code_model.options["azure_arm"]:
180
- file_import.add_submodule_import("azure.mgmt.core.exceptions", "ARMErrorFormat", ImportType.AZURECORE)
181
- file_import.add_submodule_import("azure.core.exceptions", "HttpResponseError", ImportType.AZURECORE)
182
-
183
- file_import.add_submodule_import("typing", "Callable", ImportType.STDLIB, TypingSection.CONDITIONAL)
184
- file_import.add_submodule_import("typing", "Optional", ImportType.STDLIB, TypingSection.CONDITIONAL)
185
- file_import.add_submodule_import("typing", "Dict", ImportType.STDLIB, TypingSection.CONDITIONAL)
186
- file_import.add_submodule_import("typing", "TypeVar", ImportType.STDLIB, TypingSection.CONDITIONAL)
187
- file_import.add_submodule_import("azure.core.pipeline", "PipelineResponse", ImportType.AZURECORE)
188
- file_import.add_submodule_import("azure.core.rest", "HttpRequest", ImportType.AZURECORE)
189
- if async_mode:
190
- file_import.add_submodule_import("azure.core.pipeline.transport", "AsyncHttpResponse", ImportType.AZURECORE)
229
+ if self.abstract:
230
+ file_import.add_import("abc", ImportType.STDLIB)
191
231
  else:
192
- file_import.add_submodule_import("azure.core.pipeline.transport", "HttpResponse", ImportType.AZURECORE)
193
-
194
- if self.deprecated:
195
- file_import.add_import("warnings", ImportType.STDLIB)
232
+ file_import.add_submodule_import(
233
+ "azure.core.exceptions", "map_error", ImportType.AZURECORE
234
+ )
235
+ if self.code_model.options["azure_arm"]:
236
+ file_import.add_submodule_import(
237
+ "azure.mgmt.core.exceptions", "ARMErrorFormat", ImportType.AZURECORE
238
+ )
239
+ file_import.add_submodule_import(
240
+ "azure.core.exceptions", "HttpResponseError", ImportType.AZURECORE
241
+ )
242
+ file_import.add_submodule_import(
243
+ "azure.core.exceptions",
244
+ "ClientAuthenticationError",
245
+ ImportType.AZURECORE,
246
+ )
247
+ file_import.add_submodule_import(
248
+ "azure.core.exceptions", "ResourceNotFoundError", ImportType.AZURECORE
249
+ )
250
+ file_import.add_submodule_import(
251
+ "azure.core.exceptions", "ResourceExistsError", ImportType.AZURECORE
252
+ )
196
253
 
197
- if self.code_model.options["builders_visibility"] != "embedded":
198
- builder_group_name = self.request_builder.builder_group_name
199
- rest_import_path = "..." if async_mode else ".."
200
- if builder_group_name:
254
+ kwargs_to_pop = self.parameters.kwargs_to_pop(is_python3_file)
255
+ if self.has_kwargs_to_pop_with_default(
256
+ kwargs_to_pop, ParameterLocation.Header
257
+ ) or self.has_kwargs_to_pop_with_default(
258
+ kwargs_to_pop, ParameterLocation.Query
259
+ ):
201
260
  file_import.add_submodule_import(
202
- f"{rest_import_path}{self.code_model.rest_layer_name}",
203
- builder_group_name,
204
- import_type=ImportType.LOCAL,
205
- alias=f"rest_{builder_group_name}"
261
+ "azure.core.utils", "case_insensitive_dict", ImportType.AZURECORE
206
262
  )
207
- else:
263
+ if self.deprecated:
264
+ file_import.add_import("warnings", ImportType.STDLIB)
265
+ if self.code_model.options["builders_visibility"] != "embedded":
266
+ builder_group_name = self.request_builder.builder_group_name
267
+ rest_import_path = "..." if async_mode else ".."
268
+ if builder_group_name:
269
+ file_import.add_submodule_import(
270
+ f"{rest_import_path}{self.code_model.rest_layer_name}",
271
+ builder_group_name,
272
+ import_type=ImportType.LOCAL,
273
+ alias=f"rest_{builder_group_name}",
274
+ )
275
+ else:
276
+ file_import.add_submodule_import(
277
+ rest_import_path,
278
+ self.code_model.rest_layer_name,
279
+ import_type=ImportType.LOCAL,
280
+ alias="rest",
281
+ )
282
+ if self.code_model.need_request_converter:
283
+ relative_path = "..." if async_mode else ".."
208
284
  file_import.add_submodule_import(
209
- rest_import_path,
210
- self.code_model.rest_layer_name,
211
- import_type=ImportType.LOCAL,
212
- alias="rest"
285
+ f"{relative_path}_vendor", "_convert_request", ImportType.LOCAL
213
286
  )
214
- if self.code_model.options["builders_visibility"] == "embedded" and not async_mode:
215
- file_import.merge(self.request_builder.imports())
216
- if self.code_model.need_request_converter:
217
- relative_path = "..." if async_mode else ".."
287
+ if async_mode:
288
+ file_import.add_submodule_import(
289
+ "azure.core.pipeline.transport",
290
+ "AsyncHttpResponse",
291
+ ImportType.AZURECORE,
292
+ )
293
+ else:
218
294
  file_import.add_submodule_import(
219
- f"{relative_path}_vendor", "_convert_request", ImportType.LOCAL
295
+ "azure.core.pipeline.transport", "HttpResponse", ImportType.AZURECORE
220
296
  )
221
- if self.code_model.options["version_tolerant"] and (
222
- self.parameters.has_body or
223
- any(r for r in self.responses if r.has_body)
297
+ if (
298
+ self.code_model.options["builders_visibility"] == "embedded"
299
+ and not async_mode
224
300
  ):
225
- file_import.define_mypy_type("JSONType", "Any")
301
+ file_import.merge(self.request_builder.imports())
302
+ file_import.add_submodule_import(
303
+ "azure.core.pipeline", "PipelineResponse", ImportType.AZURECORE
304
+ )
305
+ file_import.add_submodule_import(
306
+ "azure.core.rest", "HttpRequest", ImportType.AZURECORE
307
+ )
308
+ file_import.add_submodule_import(
309
+ "typing", "Callable", ImportType.STDLIB, TypingSection.CONDITIONAL
310
+ )
311
+ file_import.add_submodule_import(
312
+ "typing", "Optional", ImportType.STDLIB, TypingSection.CONDITIONAL
313
+ )
314
+ file_import.add_submodule_import(
315
+ "typing", "Dict", ImportType.STDLIB, TypingSection.CONDITIONAL
316
+ )
317
+ file_import.add_submodule_import(
318
+ "typing", "TypeVar", ImportType.STDLIB, TypingSection.CONDITIONAL
319
+ )
226
320
  if self.code_model.options["tracing"] and self.want_tracing:
227
321
  file_import.add_submodule_import(
228
322
  f"azure.core.tracing.decorator{'_async' if async_mode else ''}",
229
323
  f"distributed_trace{'_async' if async_mode else ''}",
230
324
  ImportType.AZURECORE,
231
325
  )
326
+
232
327
  return file_import
233
328
 
234
329
  def _get_body_param_from_body_kwarg(self, body_kwarg: Parameter) -> Parameter:
235
330
  # determine which of the body parameters returned from m4 corresponds to this body_kwarg
236
331
  if not self.multiple_content_type_parameters.has_body:
237
332
  return self.parameters.body[0]
238
- if body_kwarg.serialized_name == "data":
239
- return next(p for p in self.multiple_content_type_parameters.body if p.is_data_input)
240
- if body_kwarg.serialized_name == "files":
241
- return next(p for p in self.multiple_content_type_parameters.body if p.is_multipart)
242
333
  if body_kwarg.serialized_name == "json":
243
334
  # first check if there's any non-binary. In the case of multiple content types, there's
244
335
  # usually one binary (for content), and one schema parameter (for json)
245
336
  try:
246
337
  return next(
247
- p for p in self.multiple_content_type_parameters.body
338
+ p
339
+ for p in self.multiple_content_type_parameters.body
248
340
  if not isinstance(p.schema, IOSchema)
249
341
  )
250
342
  except StopIteration:
251
- return next(p for p in self.multiple_content_type_parameters.body if p.is_json_parameter)
343
+ return next(
344
+ p
345
+ for p in self.multiple_content_type_parameters.body
346
+ if p.is_json_parameter
347
+ )
252
348
  return self.multiple_content_type_parameters.body[0]
253
349
 
254
350
  def link_body_kwargs_to_body_params(self) -> None:
255
351
  if not self.parameters.has_body:
256
352
  return
257
353
  body_kwargs = [
258
- p for p in self.request_builder.parameters.body
259
- if p.content_types
354
+ p for p in self.request_builder.parameters.body if p.content_types
260
355
  ]
261
356
  if len(body_kwargs) == 1:
262
357
  self.parameters.body[0].body_kwargs = [body_kwargs[0]]
@@ -266,64 +361,109 @@ class Operation(BaseBuilder): # pylint: disable=too-many-public-methods, too-ma
266
361
  body_param.body_kwargs.append(body_kwarg)
267
362
 
268
363
  def convert_multiple_content_type_parameters(self) -> None:
269
- type_annot = ", ".join([
270
- param.schema.operation_type_annotation
271
- for param in self.multiple_content_type_parameters
272
- ])
273
- docstring_type = " or ".join([
274
- param.schema.docstring_type for param in self.multiple_content_type_parameters
275
- ])
364
+ type_annot = ", ".join(
365
+ [
366
+ param.schema.type_annotation(is_operation_file=True)
367
+ for param in self.multiple_content_type_parameters
368
+ ]
369
+ )
370
+ docstring_type = " or ".join(
371
+ [
372
+ param.schema.docstring_type
373
+ for param in self.multiple_content_type_parameters
374
+ ]
375
+ )
276
376
  try:
277
377
  # get an optional param with object first. These params are the top choice
278
378
  # bc they have more info about how to serialize the body
279
379
  chosen_parameter = next(
280
- p for p in self.multiple_content_type_parameters
380
+ p
381
+ for p in self.multiple_content_type_parameters
281
382
  if not p.required and isinstance(p.schema, ObjectSchema)
282
383
  )
283
384
  except StopIteration: # pylint: disable=broad-except
284
385
  # otherwise, we get the first optional param, if that exists. If not, we just grab the first one
285
- optional_parameters = [p for p in self.multiple_content_type_parameters if not p.required]
386
+ optional_parameters = [
387
+ p for p in self.multiple_content_type_parameters if not p.required
388
+ ]
286
389
  chosen_parameter = (
287
- optional_parameters[0] if optional_parameters else self.multiple_content_type_parameters[0]
390
+ optional_parameters[0]
391
+ if optional_parameters
392
+ else self.multiple_content_type_parameters[0]
288
393
  )
289
394
  if not chosen_parameter:
290
- raise ValueError("You are missing a parameter that has multiple media types")
395
+ raise ValueError(
396
+ "You are missing a parameter that has multiple media types"
397
+ )
291
398
  chosen_parameter.multiple_content_types_type_annot = f"Union[{type_annot}]"
292
399
  chosen_parameter.multiple_content_types_docstring_type = docstring_type
293
400
  self.parameters.append(chosen_parameter)
294
401
 
295
402
  @classmethod
296
- def from_yaml(cls, yaml_data: Dict[str, Any], *, code_model) -> "Operation":
403
+ def from_yaml(
404
+ cls, yaml_data: Dict[str, Any], code_model: "CodeModel"
405
+ ) -> "Operation":
297
406
  name = yaml_data["language"]["python"]["name"]
298
407
  _LOGGER.debug("Parsing %s operation", name)
299
408
 
300
409
  parameter_creator = get_parameter(code_model).from_yaml
301
- parameter_list_creator = get_parameter_list(code_model)
302
- schema_requests = [SchemaRequest.from_yaml(yaml, code_model=code_model) for yaml in yaml_data["requests"]]
410
+ schema_requests = [
411
+ SchemaRequest.from_yaml(yaml, code_model=code_model)
412
+ for yaml in yaml_data["requests"]
413
+ ]
303
414
  parameters, multiple_content_type_parameters = create_parameters(
304
415
  yaml_data, code_model, parameter_creator
305
416
  )
306
- parameter_list = parameter_list_creator(code_model, parameters, schema_requests)
307
- multiple_content_type_parameter_list = parameter_list_creator(
417
+ parameter_list = ParameterList(code_model, parameters, schema_requests)
418
+ multiple_content_type_parameter_list = ParameterList(
308
419
  code_model, multiple_content_type_parameters, schema_requests
309
420
  )
421
+ abstract = False
422
+ if code_model.options["version_tolerant"] and (
423
+ any(p for p in parameter_list if p.is_multipart or p.is_data_input)
424
+ or any(
425
+ p
426
+ for p in multiple_content_type_parameter_list
427
+ if p.is_multipart or p.is_data_input
428
+ )
429
+ ):
430
+ _LOGGER.warning(
431
+ 'Not going to generate operation "%s" because it has multipart / urlencoded body parameters. '
432
+ "Multipart / urlencoded body parameters are not supported for version tolerant generation right now. "
433
+ 'Please write your own custom operation in the "_patch.py" file '
434
+ "following https://aka.ms/azsdk/python/dpcodegen/python/customize",
435
+ name,
436
+ )
437
+ abstract = True
310
438
 
311
439
  if len(parameter_list.content_types) > 1:
312
440
  for p in parameter_list.parameters:
313
441
  if p.rest_api_name == "Content-Type":
314
- p.is_keyword_only = True
442
+ p.method_location = ParameterMethodLocation.KEYWORD_ONLY
443
+ request_builder = code_model.lookup_request_builder(id(yaml_data))
315
444
 
316
445
  return cls(
317
446
  code_model=code_model,
318
447
  yaml_data=yaml_data,
448
+ request_builder=request_builder,
319
449
  name=name,
320
450
  description=yaml_data["language"]["python"]["description"],
321
- api_versions=set(value_dict["version"] for value_dict in yaml_data["apiVersions"]),
451
+ api_versions=set(
452
+ value_dict["version"] for value_dict in yaml_data["apiVersions"]
453
+ ),
322
454
  parameters=parameter_list,
323
455
  multiple_content_type_parameters=multiple_content_type_parameter_list,
324
456
  schema_requests=schema_requests,
325
457
  summary=yaml_data["language"]["python"].get("summary"),
326
- responses=[SchemaResponse.from_yaml(yaml) for yaml in yaml_data.get("responses", [])],
458
+ responses=[
459
+ SchemaResponse.from_yaml(yaml, code_model=code_model)
460
+ for yaml in yaml_data.get("responses", [])
461
+ ],
327
462
  # Exception with no schema means default exception, we don't store them
328
- exceptions=[SchemaResponse.from_yaml(yaml) for yaml in yaml_data.get("exceptions", []) if "schema" in yaml],
463
+ exceptions=[
464
+ SchemaResponse.from_yaml(yaml, code_model=code_model)
465
+ for yaml in yaml_data.get("exceptions", [])
466
+ if "schema" in yaml
467
+ ],
468
+ abstract=abstract,
329
469
  )