@autorest/python 5.15.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 (86) hide show
  1. package/ChangeLog.md +20 -0
  2. package/autorest/__init__.py +1 -2
  3. package/autorest/black/__init__.py +12 -5
  4. package/autorest/codegen/__init__.py +145 -73
  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 +19 -18
  9. package/autorest/codegen/models/client.py +65 -21
  10. package/autorest/codegen/models/code_model.py +107 -61
  11. package/autorest/codegen/models/constant_schema.py +25 -13
  12. package/autorest/codegen/models/credential_model.py +23 -15
  13. package/autorest/codegen/models/credential_schema.py +18 -14
  14. package/autorest/codegen/models/credential_schema_policy.py +11 -15
  15. package/autorest/codegen/models/dictionary_schema.py +20 -17
  16. package/autorest/codegen/models/enum_schema.py +35 -25
  17. package/autorest/codegen/models/imports.py +70 -41
  18. package/autorest/codegen/models/list_schema.py +25 -13
  19. package/autorest/codegen/models/lro_operation.py +58 -22
  20. package/autorest/codegen/models/lro_paging_operation.py +2 -3
  21. package/autorest/codegen/models/object_schema.py +99 -49
  22. package/autorest/codegen/models/operation.py +236 -117
  23. package/autorest/codegen/models/operation_group.py +64 -34
  24. package/autorest/codegen/models/paging_operation.py +45 -18
  25. package/autorest/codegen/models/parameter.py +151 -83
  26. package/autorest/codegen/models/parameter_list.py +183 -162
  27. package/autorest/codegen/models/primitive_schemas.py +84 -55
  28. package/autorest/codegen/models/property.py +44 -26
  29. package/autorest/codegen/models/request_builder.py +65 -30
  30. package/autorest/codegen/models/request_builder_parameter.py +47 -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 +18 -13
  34. package/autorest/codegen/models/utils.py +5 -2
  35. package/autorest/codegen/serializers/__init__.py +182 -91
  36. package/autorest/codegen/serializers/builder_serializer.py +667 -331
  37. package/autorest/codegen/serializers/client_serializer.py +98 -37
  38. package/autorest/codegen/serializers/general_serializer.py +61 -26
  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 +35 -15
  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 +7 -6
  45. package/autorest/codegen/serializers/operation_groups_serializer.py +20 -9
  46. package/autorest/codegen/serializers/operations_init_serializer.py +23 -11
  47. package/autorest/codegen/serializers/patch_serializer.py +4 -1
  48. package/autorest/codegen/serializers/{rest_serializer.py → request_builders_serializer.py} +29 -12
  49. package/autorest/codegen/serializers/utils.py +35 -21
  50. package/autorest/codegen/templates/init.py.jinja2 +2 -2
  51. package/autorest/codegen/templates/lro_operation.py.jinja2 +5 -7
  52. package/autorest/codegen/templates/lro_paging_operation.py.jinja2 +5 -7
  53. package/autorest/codegen/templates/metadata.json.jinja2 +7 -6
  54. package/autorest/codegen/templates/operation.py.jinja2 +7 -9
  55. package/autorest/codegen/templates/operation_group.py.jinja2 +2 -8
  56. package/autorest/codegen/templates/operation_groups_container.py.jinja2 +1 -1
  57. package/autorest/codegen/templates/paging_operation.py.jinja2 +7 -8
  58. package/autorest/codegen/templates/request_builder.py.jinja2 +18 -11
  59. package/autorest/jsonrpc/__init__.py +7 -12
  60. package/autorest/jsonrpc/localapi.py +4 -3
  61. package/autorest/jsonrpc/server.py +13 -6
  62. package/autorest/jsonrpc/stdstream.py +13 -6
  63. package/autorest/m2r/__init__.py +5 -8
  64. package/autorest/multiapi/__init__.py +24 -14
  65. package/autorest/multiapi/models/client.py +21 -11
  66. package/autorest/multiapi/models/code_model.py +23 -10
  67. package/autorest/multiapi/models/config.py +4 -1
  68. package/autorest/multiapi/models/constant_global_parameter.py +1 -0
  69. package/autorest/multiapi/models/global_parameter.py +2 -1
  70. package/autorest/multiapi/models/global_parameters.py +14 -8
  71. package/autorest/multiapi/models/imports.py +24 -17
  72. package/autorest/multiapi/models/mixin_operation.py +5 -5
  73. package/autorest/multiapi/models/operation_group.py +2 -1
  74. package/autorest/multiapi/models/operation_mixin_group.py +21 -10
  75. package/autorest/multiapi/serializers/__init__.py +18 -23
  76. package/autorest/multiapi/serializers/import_serializer.py +47 -17
  77. package/autorest/multiapi/serializers/multiapi_serializer.py +17 -17
  78. package/autorest/multiapi/templates/multiapi_operations_mixin.py.jinja2 +1 -1
  79. package/autorest/multiapi/utils.py +3 -3
  80. package/autorest/namer/__init__.py +2 -4
  81. package/autorest/namer/name_converter.py +200 -103
  82. package/autorest/namer/python_mappings.py +10 -22
  83. package/package.json +2 -2
  84. package/run-python3.js +2 -3
  85. package/venvtools.py +1 -1
  86. 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, ParameterLocation
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,119 +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.type_annotation(is_operation_file=True) 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
204
  def imports(self, async_mode: bool, is_python3_file: bool) -> FileImport:
175
205
  file_import = self._imports_base(async_mode, is_python3_file)
176
- if self.has_response_body and not self.has_optional_return_type and not self.code_model.options["models_mode"]:
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
+ ):
177
213
  file_import.add_submodule_import("typing", "cast", ImportType.STDLIB)
178
214
  return file_import
179
215
 
180
216
  @staticmethod
181
- def has_kwargs_to_pop_with_default(kwargs_to_pop: List[Parameter], location: ParameterLocation) -> bool:
182
- return any(kwarg.has_default_value and kwarg.location == location for kwarg in kwargs_to_pop)
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
+ )
183
224
 
184
225
  def _imports_base(self, async_mode: bool, is_python3_file: bool) -> FileImport:
185
226
  file_import = self._imports_shared(async_mode)
186
227
 
187
228
  # Exceptions
188
- file_import.add_submodule_import("azure.core.exceptions", "map_error", ImportType.AZURECORE)
189
- if self.code_model.options["azure_arm"]:
190
- file_import.add_submodule_import("azure.mgmt.core.exceptions", "ARMErrorFormat", ImportType.AZURECORE)
191
- file_import.add_submodule_import("azure.core.exceptions", "HttpResponseError", ImportType.AZURECORE)
192
-
193
- file_import.add_submodule_import("typing", "Callable", ImportType.STDLIB, TypingSection.CONDITIONAL)
194
- file_import.add_submodule_import("typing", "Optional", ImportType.STDLIB, TypingSection.CONDITIONAL)
195
- file_import.add_submodule_import("typing", "Dict", ImportType.STDLIB, TypingSection.CONDITIONAL)
196
- file_import.add_submodule_import("typing", "TypeVar", ImportType.STDLIB, TypingSection.CONDITIONAL)
197
- file_import.add_submodule_import("azure.core.pipeline", "PipelineResponse", ImportType.AZURECORE)
198
- file_import.add_submodule_import("azure.core.rest", "HttpRequest", ImportType.AZURECORE)
199
- kwargs_to_pop = self.parameters.kwargs_to_pop(is_python3_file)
200
- if (self.has_kwargs_to_pop_with_default(kwargs_to_pop, ParameterLocation.Header) or
201
- self.has_kwargs_to_pop_with_default(kwargs_to_pop, ParameterLocation.Query)):
202
- file_import.add_submodule_import("azure.core.utils", "case_insensitive_dict", ImportType.AZURECORE)
203
- if async_mode:
204
- file_import.add_submodule_import("azure.core.pipeline.transport", "AsyncHttpResponse", ImportType.AZURECORE)
229
+ if self.abstract:
230
+ file_import.add_import("abc", ImportType.STDLIB)
205
231
  else:
206
- file_import.add_submodule_import("azure.core.pipeline.transport", "HttpResponse", ImportType.AZURECORE)
207
-
208
- if self.deprecated:
209
- 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
+ )
210
253
 
211
- if self.code_model.options["builders_visibility"] != "embedded":
212
- builder_group_name = self.request_builder.builder_group_name
213
- rest_import_path = "..." if async_mode else ".."
214
- 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
+ ):
215
260
  file_import.add_submodule_import(
216
- f"{rest_import_path}{self.code_model.rest_layer_name}",
217
- builder_group_name,
218
- import_type=ImportType.LOCAL,
219
- alias=f"rest_{builder_group_name}"
261
+ "azure.core.utils", "case_insensitive_dict", ImportType.AZURECORE
220
262
  )
221
- 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 ".."
222
284
  file_import.add_submodule_import(
223
- rest_import_path,
224
- self.code_model.rest_layer_name,
225
- import_type=ImportType.LOCAL,
226
- alias="rest"
285
+ f"{relative_path}_vendor", "_convert_request", ImportType.LOCAL
227
286
  )
228
- if self.code_model.options["builders_visibility"] == "embedded" and not async_mode:
229
- file_import.merge(self.request_builder.imports())
230
- if self.code_model.need_request_converter:
231
- relative_path = "..." if async_mode else ".."
287
+ if async_mode:
232
288
  file_import.add_submodule_import(
233
- f"{relative_path}_vendor", "_convert_request", ImportType.LOCAL
289
+ "azure.core.pipeline.transport",
290
+ "AsyncHttpResponse",
291
+ ImportType.AZURECORE,
234
292
  )
235
-
236
- if self.code_model.options["version_tolerant"] and (
237
- self.parameters.has_body or
238
- any(r for r in self.responses if r.has_body)
293
+ else:
294
+ file_import.add_submodule_import(
295
+ "azure.core.pipeline.transport", "HttpResponse", ImportType.AZURECORE
296
+ )
297
+ if (
298
+ self.code_model.options["builders_visibility"] == "embedded"
299
+ and not async_mode
239
300
  ):
240
- 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
+ )
241
320
  if self.code_model.options["tracing"] and self.want_tracing:
242
321
  file_import.add_submodule_import(
243
322
  f"azure.core.tracing.decorator{'_async' if async_mode else ''}",
244
323
  f"distributed_trace{'_async' if async_mode else ''}",
245
324
  ImportType.AZURECORE,
246
325
  )
326
+
247
327
  return file_import
248
328
 
249
329
  def _get_body_param_from_body_kwarg(self, body_kwarg: Parameter) -> Parameter:
250
330
  # determine which of the body parameters returned from m4 corresponds to this body_kwarg
251
331
  if not self.multiple_content_type_parameters.has_body:
252
332
  return self.parameters.body[0]
253
- if body_kwarg.serialized_name == "data":
254
- return next(p for p in self.multiple_content_type_parameters.body if p.is_data_input)
255
- if body_kwarg.serialized_name == "files":
256
- return next(p for p in self.multiple_content_type_parameters.body if p.is_multipart)
257
333
  if body_kwarg.serialized_name == "json":
258
334
  # first check if there's any non-binary. In the case of multiple content types, there's
259
335
  # usually one binary (for content), and one schema parameter (for json)
260
336
  try:
261
337
  return next(
262
- p for p in self.multiple_content_type_parameters.body
338
+ p
339
+ for p in self.multiple_content_type_parameters.body
263
340
  if not isinstance(p.schema, IOSchema)
264
341
  )
265
342
  except StopIteration:
266
- 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
+ )
267
348
  return self.multiple_content_type_parameters.body[0]
268
349
 
269
350
  def link_body_kwargs_to_body_params(self) -> None:
270
351
  if not self.parameters.has_body:
271
352
  return
272
353
  body_kwargs = [
273
- p for p in self.request_builder.parameters.body
274
- if p.content_types
354
+ p for p in self.request_builder.parameters.body if p.content_types
275
355
  ]
276
356
  if len(body_kwargs) == 1:
277
357
  self.parameters.body[0].body_kwargs = [body_kwargs[0]]
@@ -281,59 +361,96 @@ class Operation(BaseBuilder): # pylint: disable=too-many-public-methods, too-ma
281
361
  body_param.body_kwargs.append(body_kwarg)
282
362
 
283
363
  def convert_multiple_content_type_parameters(self) -> None:
284
- type_annot = ", ".join([
285
- param.schema.type_annotation(is_operation_file=True)
286
- for param in self.multiple_content_type_parameters
287
- ])
288
- docstring_type = " or ".join([
289
- param.schema.docstring_type for param in self.multiple_content_type_parameters
290
- ])
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
+ )
291
376
  try:
292
377
  # get an optional param with object first. These params are the top choice
293
378
  # bc they have more info about how to serialize the body
294
379
  chosen_parameter = next(
295
- p for p in self.multiple_content_type_parameters
380
+ p
381
+ for p in self.multiple_content_type_parameters
296
382
  if not p.required and isinstance(p.schema, ObjectSchema)
297
383
  )
298
384
  except StopIteration: # pylint: disable=broad-except
299
385
  # otherwise, we get the first optional param, if that exists. If not, we just grab the first one
300
- 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
+ ]
301
389
  chosen_parameter = (
302
- 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]
303
393
  )
304
394
  if not chosen_parameter:
305
- 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
+ )
306
398
  chosen_parameter.multiple_content_types_type_annot = f"Union[{type_annot}]"
307
399
  chosen_parameter.multiple_content_types_docstring_type = docstring_type
308
400
  self.parameters.append(chosen_parameter)
309
401
 
310
402
  @classmethod
311
- 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":
312
406
  name = yaml_data["language"]["python"]["name"]
313
407
  _LOGGER.debug("Parsing %s operation", name)
314
408
 
315
409
  parameter_creator = get_parameter(code_model).from_yaml
316
- parameter_list_creator = get_parameter_list(code_model)
317
- 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
+ ]
318
414
  parameters, multiple_content_type_parameters = create_parameters(
319
415
  yaml_data, code_model, parameter_creator
320
416
  )
321
- parameter_list = parameter_list_creator(code_model, parameters, schema_requests)
322
- multiple_content_type_parameter_list = parameter_list_creator(
417
+ parameter_list = ParameterList(code_model, parameters, schema_requests)
418
+ multiple_content_type_parameter_list = ParameterList(
323
419
  code_model, multiple_content_type_parameters, schema_requests
324
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
325
438
 
326
439
  if len(parameter_list.content_types) > 1:
327
440
  for p in parameter_list.parameters:
328
441
  if p.rest_api_name == "Content-Type":
329
- p.is_keyword_only = True
442
+ p.method_location = ParameterMethodLocation.KEYWORD_ONLY
443
+ request_builder = code_model.lookup_request_builder(id(yaml_data))
330
444
 
331
445
  return cls(
332
446
  code_model=code_model,
333
447
  yaml_data=yaml_data,
448
+ request_builder=request_builder,
334
449
  name=name,
335
450
  description=yaml_data["language"]["python"]["description"],
336
- 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
+ ),
337
454
  parameters=parameter_list,
338
455
  multiple_content_type_parameters=multiple_content_type_parameter_list,
339
456
  schema_requests=schema_requests,
@@ -345,6 +462,8 @@ class Operation(BaseBuilder): # pylint: disable=too-many-public-methods, too-ma
345
462
  # Exception with no schema means default exception, we don't store them
346
463
  exceptions=[
347
464
  SchemaResponse.from_yaml(yaml, code_model=code_model)
348
- for yaml in yaml_data.get("exceptions", []) if "schema" in yaml
465
+ for yaml in yaml_data.get("exceptions", [])
466
+ if "schema" in yaml
349
467
  ],
468
+ abstract=abstract,
350
469
  )