@azure-tools/typespec-python 0.24.3 → 0.26.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 (137) hide show
  1. package/dist/src/code-model.d.ts.map +1 -1
  2. package/dist/src/code-model.js +3 -6
  3. package/dist/src/code-model.js.map +1 -1
  4. package/dist/src/emitter.d.ts.map +1 -1
  5. package/dist/src/emitter.js +6 -5
  6. package/dist/src/emitter.js.map +1 -1
  7. package/dist/src/external-process.d.ts +0 -9
  8. package/dist/src/external-process.d.ts.map +1 -1
  9. package/dist/src/external-process.js +1 -25
  10. package/dist/src/external-process.js.map +1 -1
  11. package/dist/src/http.d.ts.map +1 -1
  12. package/dist/src/http.js +2 -1
  13. package/dist/src/http.js.map +1 -1
  14. package/dist/src/types.d.ts.map +1 -1
  15. package/dist/src/types.js +2 -0
  16. package/dist/src/types.js.map +1 -1
  17. package/dist/src/utils.js +1 -1
  18. package/dist/src/utils.js.map +1 -1
  19. package/generator/LICENSE +21 -0
  20. package/generator/README.md +1 -0
  21. package/generator/dev_requirements.txt +5 -0
  22. package/generator/pygen/__init__.py +107 -0
  23. package/generator/pygen/_version.py +7 -0
  24. package/generator/pygen/black.py +71 -0
  25. package/generator/pygen/codegen/__init__.py +338 -0
  26. package/generator/pygen/codegen/_utils.py +16 -0
  27. package/generator/pygen/codegen/models/__init__.py +202 -0
  28. package/generator/pygen/codegen/models/base.py +186 -0
  29. package/generator/pygen/codegen/models/base_builder.py +119 -0
  30. package/generator/pygen/codegen/models/client.py +430 -0
  31. package/generator/pygen/codegen/models/code_model.py +239 -0
  32. package/generator/pygen/codegen/models/combined_type.py +149 -0
  33. package/generator/pygen/codegen/models/constant_type.py +129 -0
  34. package/generator/pygen/codegen/models/credential_types.py +221 -0
  35. package/generator/pygen/codegen/models/dictionary_type.py +127 -0
  36. package/generator/pygen/codegen/models/enum_type.py +238 -0
  37. package/generator/pygen/codegen/models/imports.py +291 -0
  38. package/generator/pygen/codegen/models/list_type.py +143 -0
  39. package/generator/pygen/codegen/models/lro_operation.py +143 -0
  40. package/generator/pygen/codegen/models/lro_paging_operation.py +32 -0
  41. package/generator/pygen/codegen/models/model_type.py +361 -0
  42. package/generator/pygen/codegen/models/operation.py +520 -0
  43. package/generator/pygen/codegen/models/operation_group.py +184 -0
  44. package/generator/pygen/codegen/models/paging_operation.py +156 -0
  45. package/generator/pygen/codegen/models/parameter.py +402 -0
  46. package/generator/pygen/codegen/models/parameter_list.py +390 -0
  47. package/generator/pygen/codegen/models/primitive_types.py +626 -0
  48. package/generator/pygen/codegen/models/property.py +175 -0
  49. package/generator/pygen/codegen/models/request_builder.py +189 -0
  50. package/generator/pygen/codegen/models/request_builder_parameter.py +115 -0
  51. package/generator/pygen/codegen/models/response.py +348 -0
  52. package/generator/pygen/codegen/models/utils.py +23 -0
  53. package/generator/pygen/codegen/serializers/__init__.py +574 -0
  54. package/generator/pygen/codegen/serializers/base_serializer.py +21 -0
  55. package/generator/pygen/codegen/serializers/builder_serializer.py +1473 -0
  56. package/generator/pygen/codegen/serializers/client_serializer.py +295 -0
  57. package/generator/pygen/codegen/serializers/enum_serializer.py +15 -0
  58. package/generator/pygen/codegen/serializers/general_serializer.py +212 -0
  59. package/generator/pygen/codegen/serializers/import_serializer.py +127 -0
  60. package/generator/pygen/codegen/serializers/metadata_serializer.py +198 -0
  61. package/generator/pygen/codegen/serializers/model_init_serializer.py +33 -0
  62. package/generator/pygen/codegen/serializers/model_serializer.py +287 -0
  63. package/generator/pygen/codegen/serializers/operation_groups_serializer.py +89 -0
  64. package/generator/pygen/codegen/serializers/operations_init_serializer.py +44 -0
  65. package/generator/pygen/codegen/serializers/parameter_serializer.py +221 -0
  66. package/generator/pygen/codegen/serializers/patch_serializer.py +19 -0
  67. package/generator/pygen/codegen/serializers/request_builders_serializer.py +52 -0
  68. package/generator/pygen/codegen/serializers/sample_serializer.py +163 -0
  69. package/generator/pygen/codegen/serializers/test_serializer.py +287 -0
  70. package/generator/pygen/codegen/serializers/types_serializer.py +31 -0
  71. package/generator/pygen/codegen/serializers/utils.py +68 -0
  72. package/generator/pygen/codegen/templates/client.py.jinja2 +37 -0
  73. package/generator/pygen/codegen/templates/client_container.py.jinja2 +12 -0
  74. package/generator/pygen/codegen/templates/config.py.jinja2 +73 -0
  75. package/generator/pygen/codegen/templates/config_container.py.jinja2 +16 -0
  76. package/generator/pygen/codegen/templates/conftest.py.jinja2 +28 -0
  77. package/generator/pygen/codegen/templates/enum.py.jinja2 +13 -0
  78. package/generator/pygen/codegen/templates/enum_container.py.jinja2 +10 -0
  79. package/generator/pygen/codegen/templates/init.py.jinja2 +24 -0
  80. package/generator/pygen/codegen/templates/keywords.jinja2 +19 -0
  81. package/generator/pygen/codegen/templates/lro_operation.py.jinja2 +16 -0
  82. package/generator/pygen/codegen/templates/lro_paging_operation.py.jinja2 +18 -0
  83. package/generator/pygen/codegen/templates/macros.jinja2 +12 -0
  84. package/generator/pygen/codegen/templates/metadata.json.jinja2 +167 -0
  85. package/generator/pygen/codegen/templates/model_base.py.jinja2 +899 -0
  86. package/generator/pygen/codegen/templates/model_container.py.jinja2 +13 -0
  87. package/generator/pygen/codegen/templates/model_dpg.py.jinja2 +92 -0
  88. package/generator/pygen/codegen/templates/model_init.py.jinja2 +28 -0
  89. package/generator/pygen/codegen/templates/model_msrest.py.jinja2 +92 -0
  90. package/generator/pygen/codegen/templates/operation.py.jinja2 +21 -0
  91. package/generator/pygen/codegen/templates/operation_group.py.jinja2 +75 -0
  92. package/generator/pygen/codegen/templates/operation_groups_container.py.jinja2 +20 -0
  93. package/generator/pygen/codegen/templates/operation_tools.jinja2 +74 -0
  94. package/generator/pygen/codegen/templates/operations_folder_init.py.jinja2 +17 -0
  95. package/generator/pygen/codegen/templates/packaging_templates/CHANGELOG.md.jinja2 +6 -0
  96. package/generator/pygen/codegen/templates/packaging_templates/LICENSE.jinja2 +21 -0
  97. package/generator/pygen/codegen/templates/packaging_templates/MANIFEST.in.jinja2 +8 -0
  98. package/generator/pygen/codegen/templates/packaging_templates/README.md.jinja2 +107 -0
  99. package/generator/pygen/codegen/templates/packaging_templates/dev_requirements.txt.jinja2 +9 -0
  100. package/generator/pygen/codegen/templates/packaging_templates/setup.py.jinja2 +108 -0
  101. package/generator/pygen/codegen/templates/paging_operation.py.jinja2 +21 -0
  102. package/generator/pygen/codegen/templates/patch.py.jinja2 +19 -0
  103. package/generator/pygen/codegen/templates/pkgutil_init.py.jinja2 +1 -0
  104. package/generator/pygen/codegen/templates/request_builder.py.jinja2 +28 -0
  105. package/generator/pygen/codegen/templates/request_builders.py.jinja2 +10 -0
  106. package/generator/pygen/codegen/templates/rest_init.py.jinja2 +12 -0
  107. package/generator/pygen/codegen/templates/sample.py.jinja2 +44 -0
  108. package/generator/pygen/codegen/templates/serialization.py.jinja2 +2006 -0
  109. package/generator/pygen/codegen/templates/test.py.jinja2 +50 -0
  110. package/generator/pygen/codegen/templates/testpreparer.py.jinja2 +26 -0
  111. package/generator/pygen/codegen/templates/types.py.jinja2 +8 -0
  112. package/generator/pygen/codegen/templates/validation.py.jinja2 +38 -0
  113. package/generator/pygen/codegen/templates/vendor.py.jinja2 +98 -0
  114. package/generator/pygen/codegen/templates/version.py.jinja2 +4 -0
  115. package/generator/pygen/m2r.py +65 -0
  116. package/generator/pygen/postprocess/__init__.py +183 -0
  117. package/generator/pygen/postprocess/get_all.py +19 -0
  118. package/generator/pygen/postprocess/venvtools.py +77 -0
  119. package/generator/pygen/preprocess/__init__.py +509 -0
  120. package/generator/pygen/preprocess/helpers.py +27 -0
  121. package/generator/pygen/preprocess/python_mappings.py +224 -0
  122. package/generator/pygen/utils.py +153 -0
  123. package/generator/pygen.egg-info/PKG-INFO +25 -0
  124. package/generator/pygen.egg-info/SOURCES.txt +66 -0
  125. package/generator/pygen.egg-info/dependency_links.txt +1 -0
  126. package/generator/pygen.egg-info/requires.txt +4 -0
  127. package/generator/pygen.egg-info/top_level.txt +1 -0
  128. package/generator/requirements.txt +12 -0
  129. package/generator/setup.py +55 -0
  130. package/package.json +31 -26
  131. package/scripts/__pycache__/venvtools.cpython-38.pyc +0 -0
  132. package/scripts/install.py +49 -0
  133. package/scripts/prepare.py +38 -0
  134. package/scripts/run-python3.cjs +22 -0
  135. package/scripts/run_tsp.py +40 -0
  136. package/scripts/system-requirements.cjs +180 -0
  137. package/scripts/venvtools.py +81 -0
@@ -0,0 +1,1473 @@
1
+ # pylint: disable=too-many-lines,multiple-statements
2
+ # -------------------------------------------------------------------------
3
+ # Copyright (c) Microsoft Corporation. All rights reserved.
4
+ # Licensed under the MIT License. See License.txt in the project root for
5
+ # license information.
6
+ # --------------------------------------------------------------------------
7
+ from abc import abstractmethod
8
+ from collections import defaultdict
9
+ from typing import Generic, List, Type, TypeVar, Dict, Union, Optional, cast
10
+
11
+ from ..models import (
12
+ Operation,
13
+ PagingOperation,
14
+ CodeModel,
15
+ LROOperation,
16
+ LROPagingOperation,
17
+ ModelType,
18
+ DictionaryType,
19
+ ListType,
20
+ RequestBuilder,
21
+ ParameterLocation,
22
+ Response,
23
+ BinaryType,
24
+ BodyParameter,
25
+ ParameterMethodLocation,
26
+ RequestBuilderBodyParameter,
27
+ OverloadedRequestBuilder,
28
+ Property,
29
+ RequestBuilderType,
30
+ CombinedType,
31
+ JSONModelType,
32
+ DPGModelType,
33
+ ParameterListType,
34
+ ByteArraySchema,
35
+ )
36
+ from .parameter_serializer import ParameterSerializer, PopKwargType
37
+ from ..models.parameter_list import ParameterType
38
+ from . import utils
39
+ from ...utils import JSON_REGEXP
40
+
41
+ T = TypeVar("T")
42
+ OrderedSet = Dict[T, None]
43
+
44
+ BuilderType = TypeVar(
45
+ "BuilderType",
46
+ bound=Union[
47
+ RequestBuilder,
48
+ Operation,
49
+ PagingOperation,
50
+ LROOperation,
51
+ LROPagingOperation,
52
+ OverloadedRequestBuilder,
53
+ ],
54
+ )
55
+ OperationType = TypeVar(
56
+ "OperationType",
57
+ bound=Union[Operation, PagingOperation, LROOperation, LROPagingOperation],
58
+ )
59
+
60
+
61
+ def _json_serializable(content_type: str) -> bool:
62
+ return bool(JSON_REGEXP.match(content_type.split(";")[0].strip().lower()))
63
+
64
+
65
+ def _need_type_ignore(builder: OperationType) -> bool:
66
+ for excep in builder.non_default_errors:
67
+ for status_code in excep.status_codes:
68
+ if status_code in (401, 404, 409, 304):
69
+ return True
70
+ return False
71
+
72
+
73
+ def _xml_config(send_xml: bool, content_types: List[str]) -> str:
74
+ if not (send_xml and "xml" in str(content_types)):
75
+ return ""
76
+ if len(content_types) == 1:
77
+ return ", is_xml=True"
78
+ return ", is_xml='xml' in str(content_type)"
79
+
80
+
81
+ def _escape_str(input_str: str) -> str:
82
+ replace = input_str.replace("'", "\\'")
83
+ return f'"{replace}"'
84
+
85
+
86
+ def _get_polymorphic_subtype_template(polymorphic_subtype: ModelType) -> List[str]:
87
+ retval: List[str] = []
88
+ retval.append("")
89
+ retval.append(f'# JSON input template for discriminator value "{polymorphic_subtype.discriminator_value}":')
90
+ subtype_template = utils.json_dumps_template(
91
+ polymorphic_subtype.get_json_template_representation(),
92
+ )
93
+
94
+ def _get_polymorphic_parent(
95
+ polymorphic_subtype: Optional[ModelType],
96
+ ) -> Optional[ModelType]:
97
+ if not polymorphic_subtype:
98
+ return None
99
+ try:
100
+ return next(p for p in polymorphic_subtype.parents if p.discriminated_subtypes)
101
+ except StopIteration:
102
+ return None
103
+
104
+ polymorphic_parent = _get_polymorphic_parent(polymorphic_subtype)
105
+ while _get_polymorphic_parent(polymorphic_parent):
106
+ polymorphic_parent = _get_polymorphic_parent(polymorphic_parent)
107
+ retval.extend(f"{cast(ModelType, polymorphic_parent).snake_case_name} = {subtype_template}".splitlines())
108
+ return retval
109
+
110
+
111
+ def _serialize_grouped_body(builder: BuilderType) -> List[str]:
112
+ retval: List[str] = []
113
+ for grouped_parameter in builder.parameters.grouped:
114
+ retval.append(f"{grouped_parameter.client_name} = None")
115
+ groupers = [p for p in builder.parameters if p.grouper]
116
+ for grouper in groupers:
117
+ retval.append(f"if {grouper.client_name} is not None:")
118
+ retval.extend(
119
+ [
120
+ f" {parameter} = {grouper.client_name}.{property}"
121
+ for property, parameter in grouper.property_to_parameter_name.items()
122
+ ]
123
+ )
124
+ return retval
125
+
126
+
127
+ def _serialize_flattened_body(body_parameter: BodyParameter) -> List[str]:
128
+ retval: List[str] = []
129
+ if not body_parameter.property_to_parameter_name:
130
+ raise ValueError("This method can't be called if the operation doesn't need parameter flattening")
131
+
132
+ parameter_string = ", ".join(
133
+ f"{property_name}={parameter_name}"
134
+ for property_name, parameter_name in body_parameter.property_to_parameter_name.items()
135
+ )
136
+ model_type = cast(ModelType, body_parameter.type)
137
+ retval.append(f"{body_parameter.client_name} = _models.{model_type.name}({parameter_string})")
138
+ return retval
139
+
140
+
141
+ def _serialize_json_model_body(body_parameter: BodyParameter, parameters: List[ParameterType]) -> List[str]:
142
+ retval: List[str] = []
143
+ if not body_parameter.property_to_parameter_name:
144
+ raise ValueError("This method can't be called if the operation doesn't need parameter flattening")
145
+
146
+ retval.append(f"if {body_parameter.client_name} is _Unset:")
147
+ for p in parameters:
148
+ if p.client_default_value is None and not p.optional and p.default_to_unset_sentinel:
149
+ retval.append(f" if {p.client_name} is _Unset:")
150
+ retval.append(f" raise TypeError('missing required argument: {p.client_name}')")
151
+ parameter_string = ", \n".join(
152
+ f'"{property_name}": {parameter_name}'
153
+ for property_name, parameter_name in body_parameter.property_to_parameter_name.items()
154
+ )
155
+ model_type = cast(ModelType, body_parameter.type)
156
+ if isinstance(model_type, CombinedType) and model_type.target_model_subtype((JSONModelType,)):
157
+ model_type = model_type.target_model_subtype((JSONModelType,))
158
+ retval.append(f" {body_parameter.client_name} = {{{parameter_string}}}")
159
+ retval.append(f" {body_parameter.client_name} = {{")
160
+ retval.append(f" k: v for k, v in {body_parameter.client_name}.items() if v is not None")
161
+ retval.append(" }")
162
+ return retval
163
+
164
+
165
+ def _serialize_multipart_body(builder: BuilderType) -> List[str]:
166
+ retval: List[str] = []
167
+ body_param = builder.parameters.body_parameter
168
+ # we have to construct our form data before passing to the request as well
169
+ retval.append("# Construct form data")
170
+ retval.append(f"_{body_param.client_name} = {{")
171
+ for param in body_param.entries:
172
+ retval.append(f' "{param.wire_name}": {param.client_name},')
173
+ retval.append("}")
174
+ return retval
175
+
176
+
177
+ def _get_json_response_template_to_status_codes(
178
+ builder: OperationType,
179
+ ) -> Dict[str, List[str]]:
180
+ retval = defaultdict(list)
181
+ for response in builder.responses:
182
+ json_template = response.get_json_template_representation()
183
+ if not json_template:
184
+ continue
185
+ status_codes = [str(status_code) for status_code in response.status_codes]
186
+ response_json = utils.json_dumps_template(json_template)
187
+ retval[response_json].extend(status_codes)
188
+ return retval
189
+
190
+
191
+ def _api_version_validation(builder: OperationType) -> str:
192
+ if builder.is_overload:
193
+ return ""
194
+ retval: List[str] = []
195
+ if builder.added_on:
196
+ retval.append(f' method_added_on="{builder.added_on}",')
197
+ params_added_on = defaultdict(list)
198
+ for parameter in builder.parameters:
199
+ if parameter.added_on:
200
+ params_added_on[parameter.added_on].append(parameter.client_name)
201
+ if params_added_on:
202
+ retval.append(f" params_added_on={dict(params_added_on)},")
203
+ if retval:
204
+ retval_str = "\n".join(retval)
205
+ return f"@api_version_validation(\n{retval_str}\n){builder.pylint_disable}"
206
+ return ""
207
+
208
+
209
+ def is_json_model_type(parameters: ParameterListType) -> bool:
210
+ return (
211
+ parameters.has_body
212
+ and parameters.body_parameter.has_json_model_type
213
+ and any(p.in_flattened_body for p in parameters.parameters)
214
+ )
215
+
216
+
217
+ class _BuilderBaseSerializer(Generic[BuilderType]): # pylint: disable=abstract-method
218
+ def __init__(self, code_model: CodeModel, async_mode: bool) -> None:
219
+ self.code_model = code_model
220
+ self.async_mode = async_mode
221
+ self.parameter_serializer = ParameterSerializer()
222
+
223
+ @property
224
+ @abstractmethod
225
+ def _need_self_param(self) -> bool: ...
226
+
227
+ @property
228
+ @abstractmethod
229
+ def _function_def(self) -> str:
230
+ """The def keyword for the builder we're serializing, i.e. 'def' or 'async def'"""
231
+
232
+ @property
233
+ @abstractmethod
234
+ def _call_method(self) -> str:
235
+ """How to call network calls. Await if we have to await network calls"""
236
+
237
+ @property
238
+ @abstractmethod
239
+ def serializer_name(self) -> str:
240
+ """Name of serializer"""
241
+
242
+ @abstractmethod
243
+ def response_docstring(self, builder: BuilderType) -> List[str]:
244
+ """Response portion of the docstring"""
245
+
246
+ def decorators(self, builder: BuilderType) -> List[str]:
247
+ """Decorators for the method"""
248
+ retval: List[str] = []
249
+ if builder.is_overload:
250
+ return ["@overload"]
251
+ if self.code_model.options["tracing"] and builder.want_tracing:
252
+ retval.append(f"@distributed_trace{'_async' if self.async_mode else ''}")
253
+ return retval
254
+
255
+ def _method_signature(self, builder: BuilderType) -> str:
256
+ return self.parameter_serializer.serialize_method(
257
+ function_def=self._function_def,
258
+ method_name=builder.name,
259
+ need_self_param=self._need_self_param,
260
+ method_param_signatures=builder.method_signature(self.async_mode),
261
+ pylint_disable=builder.pylint_disable,
262
+ )
263
+
264
+ def method_signature_and_response_type_annotation(
265
+ self, builder: BuilderType, *, want_decorators: Optional[bool] = True
266
+ ) -> str:
267
+ response_type_annotation = builder.response_type_annotation(async_mode=self.async_mode)
268
+ method_signature = self._method_signature(builder)
269
+ decorators = self.decorators(builder)
270
+ decorators_str = ""
271
+ if decorators and want_decorators:
272
+ decorators_str = "\n".join(decorators) + "\n"
273
+ return decorators_str + utils.method_signature_and_response_type_annotation_template(
274
+ method_signature=method_signature,
275
+ response_type_annotation=response_type_annotation,
276
+ )
277
+
278
+ def description_and_summary(self, builder: BuilderType) -> List[str]:
279
+ description_list: List[str] = []
280
+ description_list.append(f"{builder.summary.strip() if builder.summary else builder.description.strip()}")
281
+ if builder.summary and builder.description:
282
+ description_list.append("")
283
+ description_list.append(builder.description.strip())
284
+ description_list.append("")
285
+ return description_list
286
+
287
+ @staticmethod
288
+ def line_too_long(docs: List[str]) -> bool:
289
+ return any(len(line) > 120 for line in docs)
290
+
291
+ def example_template(self, builder: BuilderType) -> List[str]:
292
+ template = []
293
+ if builder.abstract:
294
+ return []
295
+ if self._json_input_example_template(builder):
296
+ template.append("")
297
+ template += self._json_input_example_template(builder)
298
+ return template
299
+
300
+ def param_description(self, builder: BuilderType) -> List[str]:
301
+ description_list: List[str] = []
302
+ for param in builder.parameters.method:
303
+ if (
304
+ not param.in_docstring
305
+ or param.hide_in_operation_signature
306
+ or param.method_location == ParameterMethodLocation.KWARG
307
+ ):
308
+ continue
309
+ description_list.extend(
310
+ f":{param.description_keyword} {param.client_name}: {param.description}".replace("\n", "\n ").split(
311
+ "\n"
312
+ )
313
+ )
314
+ docstring_type = param.docstring_type(
315
+ async_mode=self.async_mode,
316
+ )
317
+ description_list.append(f":{param.docstring_type_keyword} {param.client_name}: {docstring_type}")
318
+ return description_list
319
+
320
+ def param_description_and_response_docstring(self, builder: BuilderType) -> List[str]:
321
+ if builder.abstract:
322
+ return []
323
+ return self.param_description(builder) + self.response_docstring(builder)
324
+
325
+ @property
326
+ @abstractmethod
327
+ def _json_response_template_name(self) -> str: ...
328
+
329
+ def _json_input_example_template(self, builder: BuilderType) -> List[str]:
330
+ template: List[str] = []
331
+ if not builder.parameters.has_body or builder.parameters.body_parameter.flattened:
332
+ # No input template if now body parameter
333
+ return template
334
+
335
+ body_param = builder.parameters.body_parameter
336
+ if not isinstance(body_param.type, (ListType, DictionaryType, ModelType, CombinedType)):
337
+ return template
338
+
339
+ if (
340
+ isinstance(body_param.type, (ListType, DictionaryType))
341
+ and self.code_model.options["models_mode"] == "msrest"
342
+ ):
343
+ return template
344
+
345
+ if isinstance(body_param.type, ModelType) and body_param.type.base == "msrest":
346
+ return template
347
+
348
+ json_type = body_param.type
349
+ if isinstance(body_param.type, CombinedType):
350
+ target_model_type = body_param.type.target_model_subtype((JSONModelType, DPGModelType))
351
+ if target_model_type is None:
352
+ return template
353
+ json_type = target_model_type
354
+
355
+ polymorphic_subtypes: List[ModelType] = []
356
+ json_type.get_polymorphic_subtypes(polymorphic_subtypes)
357
+ if polymorphic_subtypes:
358
+ # we just assume one kind of polymorphic body for input
359
+ discriminator_name = cast(Property, polymorphic_subtypes[0].discriminator).wire_name
360
+ template.append(
361
+ "# The input is polymorphic. The following are possible polymorphic "
362
+ f'inputs based off discriminator "{discriminator_name}":'
363
+ )
364
+ for idx in range(
365
+ min(
366
+ self.code_model.options["polymorphic_examples"],
367
+ len(polymorphic_subtypes),
368
+ )
369
+ ):
370
+ template.extend(_get_polymorphic_subtype_template(polymorphic_subtypes[idx]))
371
+ template.append("")
372
+ template.append("# JSON input template you can fill out and use as your body input.")
373
+ json_template = utils.json_dumps_template(
374
+ json_type.get_json_template_representation(),
375
+ )
376
+ template.extend(f"{builder.parameters.body_parameter.client_name} = {json_template}".splitlines())
377
+ return template
378
+
379
+ def serialize_path(self, builder: BuilderType) -> List[str]:
380
+ return self.parameter_serializer.serialize_path(builder.parameters.path, self.serializer_name)
381
+
382
+ @property
383
+ def pipeline_name(self) -> str:
384
+ return f"{'_' if self.code_model.is_azure_flavor else ''}pipeline"
385
+
386
+
387
+ ############################## REQUEST BUILDERS ##############################
388
+
389
+
390
+ class RequestBuilderSerializer(_BuilderBaseSerializer[RequestBuilderType]): # pylint: disable=abstract-method
391
+ def description_and_summary(self, builder: RequestBuilderType) -> List[str]:
392
+ retval = super().description_and_summary(builder)
393
+ retval += [
394
+ "See https://aka.ms/azsdk/dpcodegen/python/send_request for how to incorporate this "
395
+ "request builder into your code flow.",
396
+ "",
397
+ ]
398
+ return retval
399
+
400
+ @property
401
+ def _call_method(self) -> str:
402
+ return ""
403
+
404
+ @property
405
+ def serializer_name(self) -> str:
406
+ return "_SERIALIZER"
407
+
408
+ @property
409
+ def _json_response_template_name(self) -> str:
410
+ return "response.json()"
411
+
412
+ @staticmethod
413
+ def declare_non_inputtable_headers_queries(builder: RequestBuilderType) -> List[str]:
414
+ def _get_value(param):
415
+ declaration = param.get_declaration() if param.constant else None
416
+ if param.location in [ParameterLocation.HEADER, ParameterLocation.QUERY]:
417
+ kwarg_dict = "headers" if param.location == ParameterLocation.HEADER else "params"
418
+ return f"_{kwarg_dict}.pop('{param.wire_name}', {declaration})"
419
+ return declaration
420
+
421
+ return [
422
+ f"{p.client_name} = {_get_value(p)}"
423
+ for p in (builder.parameters.headers + builder.parameters.query)
424
+ if not p.in_method_signature
425
+ ]
426
+
427
+ @property
428
+ def _function_def(self) -> str:
429
+ return "def"
430
+
431
+ @property
432
+ def _need_self_param(self) -> bool:
433
+ return False
434
+
435
+ def response_docstring(self, builder: RequestBuilderType) -> List[str]:
436
+ request_full_path = f"{self.code_model.core_library}.rest.HttpRequest"
437
+ response_str = (
438
+ f":return: Returns an :class:`~{request_full_path}` that you will pass to the client's "
439
+ + "`send_request` method. See https://aka.ms/azsdk/dpcodegen/python/send_request for how to "
440
+ + "incorporate this response into your code flow."
441
+ )
442
+ rtype_str = f":rtype: ~{request_full_path}"
443
+ return [response_str, rtype_str]
444
+
445
+ def pop_kwargs_from_signature(self, builder: RequestBuilderType) -> List[str]:
446
+ return self.parameter_serializer.pop_kwargs_from_signature(
447
+ builder.parameters.kwargs_to_pop,
448
+ check_kwarg_dict=True,
449
+ pop_headers_kwarg=(PopKwargType.CASE_INSENSITIVE if bool(builder.parameters.headers) else PopKwargType.NO),
450
+ pop_params_kwarg=(PopKwargType.CASE_INSENSITIVE if bool(builder.parameters.query) else PopKwargType.NO),
451
+ )
452
+
453
+ @staticmethod
454
+ def create_http_request(builder: RequestBuilderType) -> List[str]:
455
+ retval = ["return HttpRequest("]
456
+ retval.append(f' method="{builder.method}",')
457
+ retval.append(" url=_url,")
458
+ if builder.parameters.query:
459
+ retval.append(" params=_params,")
460
+ if builder.parameters.headers:
461
+ retval.append(" headers=_headers,")
462
+ if builder.parameters.has_body and builder.parameters.body_parameter.in_method_signature:
463
+ body_param = builder.parameters.body_parameter
464
+ if body_param.constant or body_param.method_location != ParameterMethodLocation.KWARG:
465
+ # we only need to pass it through if it's not a kwarg or it's a popped kwarg
466
+ retval.append(
467
+ f" {builder.parameters.body_parameter.client_name}="
468
+ f"{builder.parameters.body_parameter.client_name},"
469
+ )
470
+ retval.append(" **kwargs")
471
+ retval.append(")")
472
+ return retval
473
+
474
+ def serialize_headers(self, builder: RequestBuilderType) -> List[str]:
475
+ headers = [
476
+ h
477
+ for h in builder.parameters.headers
478
+ if not builder.has_form_data_body or h.wire_name.lower() != "content-type"
479
+ ]
480
+ retval = ["# Construct headers"] if headers else []
481
+ for header in headers:
482
+ retval.extend(
483
+ self.parameter_serializer.serialize_query_header(
484
+ header,
485
+ "headers",
486
+ self.serializer_name,
487
+ self.code_model.is_legacy,
488
+ )
489
+ )
490
+ return retval
491
+
492
+ def serialize_query(self, builder: RequestBuilderType) -> List[str]:
493
+ retval = ["# Construct parameters"]
494
+ for parameter in builder.parameters.query:
495
+ retval.extend(
496
+ self.parameter_serializer.serialize_query_header(
497
+ parameter,
498
+ "params",
499
+ self.serializer_name,
500
+ self.code_model.is_legacy,
501
+ )
502
+ )
503
+ return retval
504
+
505
+ def construct_url(self, builder: RequestBuilderType) -> str:
506
+ if any(o for o in ["low_level_client", "version_tolerant"] if self.code_model.options.get(o)):
507
+ url_value = _escape_str(builder.url)
508
+ else:
509
+ url_value = f'kwargs.pop("template_url", {_escape_str(builder.url)})'
510
+ return f"_url = {url_value}{' # pylint: disable=line-too-long' if len(url_value) > 114 else ''}"
511
+
512
+
513
+ ############################## NORMAL OPERATIONS ##############################
514
+
515
+
516
+ class _OperationSerializer(_BuilderBaseSerializer[OperationType]): # pylint: disable=abstract-method
517
+ def description_and_summary(self, builder: OperationType) -> List[str]:
518
+ retval = super().description_and_summary(builder)
519
+ if builder.deprecated:
520
+ retval.append(".. warning::")
521
+ retval.append(" This method is deprecated")
522
+ retval.append("")
523
+ if builder.external_docs and builder.external_docs.get("url"):
524
+ retval.append(".. seealso::")
525
+ retval.append(f" - {builder.external_docs['url']}")
526
+ retval.append("")
527
+ return retval
528
+
529
+ @property
530
+ def _json_response_template_name(self) -> str:
531
+ return "response"
532
+
533
+ def example_template(self, builder: OperationType) -> List[str]:
534
+ retval = super().example_template(builder)
535
+ if self.code_model.options["models_mode"] == "msrest":
536
+ return retval
537
+ for response in builder.responses:
538
+ polymorphic_subtypes: List[ModelType] = []
539
+ if not response.type:
540
+ continue
541
+ response.get_polymorphic_subtypes(polymorphic_subtypes)
542
+ if polymorphic_subtypes:
543
+ # we just assume one kind of polymorphic body for input
544
+ discriminator_name = cast(Property, polymorphic_subtypes[0].discriminator).wire_name
545
+ retval.append("")
546
+ retval.append(
547
+ "# The response is polymorphic. The following are possible polymorphic "
548
+ f'responses based off discriminator "{discriminator_name}":'
549
+ )
550
+ for idx in range(
551
+ min(
552
+ self.code_model.options["polymorphic_examples"],
553
+ len(polymorphic_subtypes),
554
+ )
555
+ ):
556
+ retval.extend(_get_polymorphic_subtype_template(polymorphic_subtypes[idx]))
557
+
558
+ if _get_json_response_template_to_status_codes(builder):
559
+ retval.append("")
560
+ for (
561
+ response_body,
562
+ status_codes,
563
+ ) in _get_json_response_template_to_status_codes(builder).items():
564
+ retval.append("# response body for status code(s): {}".format(", ".join(status_codes)))
565
+ retval.extend(f"{self._json_response_template_name} == {response_body}".splitlines())
566
+ return retval
567
+
568
+ def make_pipeline_call(self, builder: OperationType) -> List[str]:
569
+ retval = []
570
+ type_ignore = self.async_mode and builder.group_name == "" # is in a mixin
571
+ if builder.stream_value is True and not self.code_model.options["version_tolerant"]:
572
+ retval.append("_decompress = kwargs.pop('decompress', True)")
573
+ retval.extend(
574
+ [
575
+ f"_stream = {builder.stream_value}",
576
+ f"pipeline_response: PipelineResponse = {self._call_method}self._client.{self.pipeline_name}.run( "
577
+ + f"{'# type: ignore' if type_ignore else ''} # pylint: disable=protected-access",
578
+ " _request,",
579
+ " stream=_stream,",
580
+ " **kwargs",
581
+ ")",
582
+ ]
583
+ )
584
+ return retval
585
+
586
+ @property
587
+ def _function_def(self) -> str:
588
+ return "async def" if self.async_mode else "def"
589
+
590
+ @property
591
+ def _need_self_param(self) -> bool:
592
+ return True
593
+
594
+ @property
595
+ def serializer_name(self) -> str:
596
+ return "self._serialize"
597
+
598
+ def decorators(self, builder: OperationType) -> List[str]:
599
+ """Decorators for the method"""
600
+ retval = super().decorators(builder)
601
+ if _api_version_validation(builder):
602
+ retval.append(_api_version_validation(builder))
603
+ return retval
604
+
605
+ def pop_kwargs_from_signature(self, builder: OperationType) -> List[str]:
606
+ kwargs_to_pop = builder.parameters.kwargs_to_pop
607
+ kwargs = self.parameter_serializer.pop_kwargs_from_signature(
608
+ kwargs_to_pop,
609
+ check_kwarg_dict=True,
610
+ pop_headers_kwarg=(
611
+ PopKwargType.CASE_INSENSITIVE
612
+ if builder.has_kwargs_to_pop_with_default(kwargs_to_pop, ParameterLocation.HEADER) # type: ignore
613
+ else PopKwargType.SIMPLE
614
+ ),
615
+ pop_params_kwarg=(
616
+ PopKwargType.CASE_INSENSITIVE
617
+ if builder.has_kwargs_to_pop_with_default(kwargs_to_pop, ParameterLocation.QUERY) # type: ignore
618
+ else PopKwargType.SIMPLE
619
+ ),
620
+ check_client_input=not self.code_model.options["multiapi"],
621
+ operation_name=f"('{builder.name}')" if builder.group_name == "" else "",
622
+ )
623
+ for p in builder.parameters.parameters:
624
+ if p.hide_in_operation_signature:
625
+ kwargs.append(f'{p.client_name} = kwargs.pop("{p.client_name}", None)')
626
+ cls_annotation = builder.cls_type_annotation(async_mode=self.async_mode)
627
+ pylint_disable = ""
628
+ if any(x.startswith("_") for x in cls_annotation.split(".")):
629
+ pylint_disable = " # pylint: disable=protected-access"
630
+ kwargs.append(f"cls: {cls_annotation} = kwargs.pop({pylint_disable}\n 'cls', None\n)")
631
+ return kwargs
632
+
633
+ def response_docstring(self, builder: OperationType) -> List[str]:
634
+ response_str = f":return: {builder.response_docstring_text(async_mode=self.async_mode)}"
635
+ rtype_str = f":rtype: {builder.response_docstring_type(async_mode=self.async_mode)}"
636
+ return [
637
+ response_str,
638
+ rtype_str,
639
+ f":raises ~{self.code_model.core_library}.exceptions.HttpResponseError:",
640
+ ]
641
+
642
+ def _serialize_body_parameter(self, builder: OperationType) -> List[str]:
643
+ """We need to serialize params if they're not meant to be streamed in.
644
+
645
+ This function serializes the body params that need to be serialized.
646
+ """
647
+ retval: List[str] = []
648
+ body_param = builder.parameters.body_parameter
649
+ if body_param.is_form_data:
650
+ model_type = cast(
651
+ ModelType,
652
+ (
653
+ body_param.type.target_model_subtype((JSONModelType, DPGModelType))
654
+ if isinstance(body_param.type, CombinedType)
655
+ else body_param.type
656
+ ),
657
+ )
658
+ file_fields = [p.wire_name for p in model_type.properties if p.is_multipart_file_input]
659
+ data_fields = [p.wire_name for p in model_type.properties if not p.is_multipart_file_input]
660
+ retval.extend(
661
+ [
662
+ "_body = (",
663
+ f" {body_param.client_name}.as_dict()",
664
+ f" if isinstance({body_param.client_name}, _model_base.Model) else",
665
+ f" {body_param.client_name}",
666
+ ")",
667
+ f"_file_fields: List[str] = {file_fields}",
668
+ f"_data_fields: List[str] = {data_fields}",
669
+ "_files, _data = prepare_multipart_form_data(_body, _file_fields, _data_fields)",
670
+ ]
671
+ )
672
+ return retval
673
+
674
+ body_kwarg_name = builder.request_builder.parameters.body_parameter.client_name
675
+ send_xml = builder.parameters.body_parameter.type.is_xml
676
+ xml_serialization_ctxt = body_param.type.xml_serialization_ctxt if send_xml else None
677
+ ser_ctxt_name = "serialization_ctxt"
678
+ if xml_serialization_ctxt and self.code_model.options["models_mode"]:
679
+ retval.append(f'{ser_ctxt_name} = {{"xml": {{{xml_serialization_ctxt}}}}}')
680
+ if self.code_model.options["models_mode"] == "msrest":
681
+ is_xml_cmd = _xml_config(send_xml, builder.parameters.body_parameter.content_types)
682
+ serialization_ctxt_cmd = f", {ser_ctxt_name}={ser_ctxt_name}" if xml_serialization_ctxt else ""
683
+ create_body_call = (
684
+ f"_{body_kwarg_name} = self._serialize.body({body_param.client_name}, "
685
+ f"'{body_param.type.serialization_type}'{is_xml_cmd}{serialization_ctxt_cmd})"
686
+ )
687
+ elif self.code_model.options["models_mode"] == "dpg":
688
+ if _json_serializable(body_param.default_content_type):
689
+ if hasattr(body_param.type, "encode") and body_param.type.encode: # type: ignore
690
+ create_body_call = (
691
+ f"_{body_kwarg_name} = json.dumps({body_param.client_name}, "
692
+ "cls=SdkJSONEncoder, exclude_readonly=True, "
693
+ f"format='{body_param.type.encode}') # type: ignore" # type: ignore
694
+ )
695
+ else:
696
+ create_body_call = (
697
+ f"_{body_kwarg_name} = json.dumps({body_param.client_name}, "
698
+ "cls=SdkJSONEncoder, exclude_readonly=True) # type: ignore"
699
+ )
700
+ else:
701
+ create_body_call = f"_{body_kwarg_name} = {body_param.client_name}"
702
+ else:
703
+ create_body_call = f"_{body_kwarg_name} = {body_param.client_name}"
704
+ if body_param.optional:
705
+ retval.append(f"if {body_param.client_name} is not None:")
706
+ retval.append(" " + create_body_call)
707
+ retval.append("else:")
708
+ retval.append(f" _{body_kwarg_name} = None")
709
+ else:
710
+ retval.append(create_body_call)
711
+ return retval
712
+
713
+ def _create_body_parameter(
714
+ self,
715
+ builder: OperationType,
716
+ ) -> List[str]:
717
+ """Create the body parameter before we pass it as either json or content to the request builder"""
718
+ retval = []
719
+ body_param = builder.parameters.body_parameter
720
+ if body_param.entries:
721
+ return _serialize_multipart_body(builder)
722
+ body_kwarg_name = builder.request_builder.parameters.body_parameter.client_name
723
+ body_param_type = body_param.type
724
+ if isinstance(body_param_type, BinaryType) or (
725
+ isinstance(body_param.type, ByteArraySchema) and body_param.default_content_type != "application/json"
726
+ ):
727
+ retval.append(f"_{body_kwarg_name} = {body_param.client_name}")
728
+ if (
729
+ not body_param.default_content_type
730
+ and not next(p for p in builder.parameters if p.wire_name.lower() == "content-type").optional
731
+ ):
732
+ content_types = "'" + "', '".join(body_param.content_types) + "'"
733
+ retval.extend(
734
+ [
735
+ "if not content_type:",
736
+ f' raise TypeError("Missing required keyword-only argument: content_type. '
737
+ f'Known values are:" + "{content_types}")',
738
+ ]
739
+ )
740
+ else:
741
+ retval.extend(self._serialize_body_parameter(builder))
742
+ return retval
743
+
744
+ def _initialize_overloads(self, builder: OperationType, is_paging: bool = False) -> List[str]:
745
+ retval: List[str] = []
746
+ # For paging, we put body parameter in local place outside `prepare_request`
747
+ if is_paging:
748
+ return retval
749
+ same_content_type = len(set(o.parameters.body_parameter.default_content_type for o in builder.overloads)) == 1
750
+ if same_content_type:
751
+ default_content_type = builder.overloads[0].parameters.body_parameter.default_content_type
752
+ retval.append(f'content_type = content_type or "{default_content_type}"')
753
+ client_names = [
754
+ overload.request_builder.parameters.body_parameter.client_name for overload in builder.overloads
755
+ ]
756
+ for v in sorted(set(client_names), key=client_names.index):
757
+ retval.append(f"_{v} = None")
758
+ try:
759
+ # if there is a binary overload, we do a binary check first.
760
+ binary_overload = cast(
761
+ OperationType,
762
+ next((o for o in builder.overloads if isinstance(o.parameters.body_parameter.type, BinaryType))),
763
+ )
764
+ binary_body_param = binary_overload.parameters.body_parameter
765
+ retval.append(f"if {binary_body_param.type.instance_check_template.format(binary_body_param.client_name)}:")
766
+ if binary_body_param.default_content_type and not same_content_type:
767
+ retval.append(f' content_type = content_type or "{binary_body_param.default_content_type}"')
768
+ retval.extend(f" {l}" for l in self._create_body_parameter(binary_overload))
769
+ retval.append("else:")
770
+ other_overload = cast(
771
+ OperationType,
772
+ next((o for o in builder.overloads if not isinstance(o.parameters.body_parameter.type, BinaryType))),
773
+ )
774
+ retval.extend(f" {l}" for l in self._create_body_parameter(other_overload))
775
+ if other_overload.parameters.body_parameter.default_content_type and not same_content_type:
776
+ retval.append(
777
+ " content_type = content_type or "
778
+ f'"{other_overload.parameters.body_parameter.default_content_type}"'
779
+ )
780
+ except StopIteration:
781
+ for idx, overload in enumerate(builder.overloads):
782
+ if_statement = "if" if idx == 0 else "elif"
783
+ body_param = overload.parameters.body_parameter
784
+ retval.append(
785
+ f"{if_statement} {body_param.type.instance_check_template.format(body_param.client_name)}:"
786
+ )
787
+ if body_param.default_content_type and not same_content_type:
788
+ retval.append(f' content_type = content_type or "{body_param.default_content_type}"')
789
+ retval.extend(f" {l}" for l in self._create_body_parameter(cast(OperationType, overload)))
790
+ return retval
791
+
792
+ def _create_request_builder_call(
793
+ self,
794
+ builder: OperationType,
795
+ request_builder: RequestBuilderType,
796
+ is_next_request: bool = False,
797
+ ) -> List[str]:
798
+ retval: List[str] = []
799
+ if self.code_model.options["builders_visibility"] == "embedded":
800
+ request_path_name = request_builder.name
801
+ else:
802
+ group_name = request_builder.group_name
803
+ request_path_name = "rest{}.{}".format(
804
+ ("_" + group_name) if group_name else "",
805
+ request_builder.name,
806
+ )
807
+ retval.append(f"_request = {request_path_name}(")
808
+ for parameter in request_builder.parameters.method:
809
+ if parameter.location == ParameterLocation.BODY:
810
+ # going to pass in body later based off of overloads
811
+ continue
812
+ if (
813
+ is_next_request
814
+ and builder.operation_type == "paging"
815
+ and not bool(builder.next_request_builder) # type: ignore
816
+ and parameter.location == ParameterLocation.QUERY
817
+ ):
818
+ # if we don't want to reformat query parameters for next link calls
819
+ # in paging operations with a single swagger operation defintion,
820
+ # we skip passing query params when building the next request
821
+ continue
822
+ type_ignore = (
823
+ parameter.grouped_by
824
+ and parameter.client_default_value is not None
825
+ and next(p for p in builder.parameters if p.grouper and p.client_name == parameter.grouped_by).optional
826
+ )
827
+ retval.append(
828
+ f" {parameter.client_name}={parameter.name_in_high_level_operation},"
829
+ f"{' # type: ignore' if type_ignore else ''}"
830
+ )
831
+ if builder.parameters.has_body and builder.parameters.body_parameter.entries:
832
+ # this is for legacy
833
+ client_name = builder.parameters.body_parameter.client_name
834
+ retval.append(f" {client_name}=_{client_name},")
835
+ elif request_builder.has_form_data_body:
836
+ retval.append(" files=_files,")
837
+ retval.append(" data=_data,")
838
+ elif request_builder.overloads:
839
+ seen_body_params = set()
840
+ for overload in request_builder.overloads:
841
+ body_param = cast(RequestBuilderBodyParameter, overload.parameters.body_parameter)
842
+ if body_param.client_name in seen_body_params:
843
+ continue
844
+ seen_body_params.add(body_param.client_name)
845
+
846
+ retval.append(f" {body_param.client_name}={body_param.name_in_high_level_operation},")
847
+ elif request_builder.parameters.has_body:
848
+ body_param = cast(RequestBuilderBodyParameter, request_builder.parameters.body_parameter)
849
+ retval.append(f" {body_param.client_name}={body_param.name_in_high_level_operation},")
850
+ retval.append(" headers=_headers,")
851
+ retval.append(" params=_params,")
852
+ retval.append(")")
853
+ return retval
854
+
855
+ def _postprocess_http_request(self, builder: OperationType, template_url: Optional[str] = None) -> List[str]:
856
+ retval: List[str] = []
857
+ if builder.parameters.path:
858
+ retval.extend(self.serialize_path(builder))
859
+ url_to_format = "_request.url"
860
+ if self.code_model.options["version_tolerant"] and template_url:
861
+ url_to_format = template_url
862
+ retval.append(
863
+ "_request.url = self._client.format_url({}{})".format(
864
+ url_to_format,
865
+ ", **path_format_arguments" if builder.parameters.path else "",
866
+ )
867
+ )
868
+ return retval
869
+
870
+ def _call_request_builder_helper( # pylint: disable=too-many-statements
871
+ self,
872
+ builder: OperationType,
873
+ request_builder: RequestBuilderType,
874
+ template_url: Optional[str] = None,
875
+ is_next_request: bool = False,
876
+ is_paging: bool = False,
877
+ ) -> List[str]:
878
+ retval = []
879
+ if builder.parameters.grouped:
880
+ # request builders don't allow grouped parameters, so we group them before making the call
881
+ retval.extend(_serialize_grouped_body(builder))
882
+ if builder.parameters.has_body and builder.parameters.body_parameter.flattened:
883
+ # unflatten before passing to request builder as well
884
+ retval.extend(_serialize_flattened_body(builder.parameters.body_parameter))
885
+ if is_json_model_type(builder.parameters):
886
+ retval.extend(_serialize_json_model_body(builder.parameters.body_parameter, builder.parameters.parameters))
887
+ if builder.has_form_data_body:
888
+ retval.extend(self._create_body_parameter(builder))
889
+ elif builder.overloads:
890
+ # we are only dealing with two overloads. If there are three, we generate an abstract operation
891
+ retval.extend(self._initialize_overloads(builder, is_paging=is_paging))
892
+ elif builder.parameters.has_body:
893
+ # non-overloaded body
894
+ retval.extend(self._create_body_parameter(builder))
895
+ retval.append("")
896
+ retval.extend(self._create_request_builder_call(builder, request_builder, is_next_request))
897
+ retval.extend(self._postprocess_http_request(builder, template_url))
898
+ return retval
899
+
900
+ def call_request_builder(self, builder: OperationType, is_paging: bool = False) -> List[str]:
901
+ return self._call_request_builder_helper(builder, builder.request_builder, is_paging=is_paging)
902
+
903
+ def response_headers_and_deserialization(
904
+ self,
905
+ builder: OperationType,
906
+ response: Response,
907
+ ) -> List[str]:
908
+ retval: List[str] = [
909
+ (
910
+ f"response_headers['{response_header.wire_name}']=self._deserialize("
911
+ f"'{response_header.serialization_type}', response.headers.get('{response_header.wire_name}'))"
912
+ )
913
+ for response_header in response.headers
914
+ ]
915
+ if response.headers:
916
+ retval.append("")
917
+ deserialize_code: List[str] = []
918
+ stream_logic = True
919
+ if builder.has_stream_response:
920
+ if isinstance(response.type, ByteArraySchema):
921
+ deserialized = f"{'await ' if self.async_mode else ''}response.read()"
922
+ else:
923
+ stream_logic = False
924
+ if self.code_model.options["version_tolerant"]:
925
+ deserialized = "response.iter_bytes()"
926
+ else:
927
+ deserialized = (
928
+ f"response.stream_download(self._client.{self.pipeline_name}, decompress=_decompress)"
929
+ )
930
+ deserialize_code.append(f"deserialized = {deserialized}")
931
+ elif response.type:
932
+ pylint_disable = ""
933
+ if isinstance(response.type, ModelType) and response.type.internal:
934
+ pylint_disable = " # pylint: disable=protected-access"
935
+ if self.code_model.options["models_mode"] == "msrest":
936
+ deserialize_code.append("deserialized = self._deserialize(")
937
+ deserialize_code.append(f" '{response.serialization_type}',{pylint_disable}")
938
+ deserialize_code.append(" pipeline_response.http_response")
939
+ deserialize_code.append(")")
940
+ elif self.code_model.options["models_mode"] == "dpg":
941
+ if builder.has_stream_response:
942
+ deserialize_code.append("deserialized = response.content")
943
+ else:
944
+ format_filed = (
945
+ f', format="{response.type.encode}"'
946
+ if isinstance(response.type, ByteArraySchema)
947
+ and response.default_content_type == "application/json"
948
+ else ""
949
+ )
950
+ response_attr = "json" if _json_serializable(str(response.default_content_type)) else "text"
951
+ deserialize_code.append("deserialized = _deserialize(")
952
+ deserialize_code.append(
953
+ f" {response.type.type_annotation(is_operation_file=True)},{pylint_disable}"
954
+ )
955
+ deserialize_code.append(f" response.{response_attr}(){response.result_property}{format_filed}")
956
+ deserialize_code.append(")")
957
+
958
+ else:
959
+ deserialized_value = "ET.fromstring(response.text())" if response.type.is_xml else "response.json()"
960
+ deserialize_code.append("if response.content:")
961
+ deserialize_code.append(f" deserialized = {deserialized_value}")
962
+ deserialize_code.append("else:")
963
+ deserialize_code.append(" deserialized = None")
964
+ if len(deserialize_code) > 0:
965
+ if builder.expose_stream_keyword and stream_logic:
966
+ retval.append("if _stream:")
967
+ retval.append(" deserialized = response.iter_bytes()")
968
+ retval.append("else:")
969
+ retval.extend([f" {dc}" for dc in deserialize_code])
970
+ else:
971
+ retval.extend(deserialize_code)
972
+ return retval
973
+
974
+ def handle_error_response(self, builder: OperationType) -> List[str]:
975
+ async_await = "await " if self.async_mode else ""
976
+ retval = [f"if response.status_code not in {str(builder.success_status_codes)}:"]
977
+ response_read = [
978
+ " try:",
979
+ f" {async_await}response.read() # Load the body in memory and close the socket",
980
+ " except (StreamConsumedError, StreamClosedError):",
981
+ " pass",
982
+ ]
983
+ if builder.stream_value is True: # _stream is True so no need to judge it
984
+ retval.extend(response_read)
985
+ elif isinstance(builder.stream_value, str): # _stream is not sure, so we need to judge it
986
+ retval.append(" if _stream:")
987
+ retval.extend([f" {l}" for l in response_read])
988
+ type_ignore = " # type: ignore" if _need_type_ignore(builder) else ""
989
+ retval.append(
990
+ f" map_error(status_code=response.status_code, response=response, error_map=error_map){type_ignore}"
991
+ )
992
+ error_model = ""
993
+ if builder.default_error_deserialization and self.code_model.options["models_mode"]:
994
+ if self.code_model.options["models_mode"] == "dpg":
995
+ retval.append(f" error = _deserialize({builder.default_error_deserialization}, response.json())")
996
+ else:
997
+ retval.append(
998
+ f" error = self._deserialize.failsafe_deserialize({builder.default_error_deserialization}, "
999
+ "pipeline_response)"
1000
+ )
1001
+ error_model = ", model=error"
1002
+ retval.append(
1003
+ " raise HttpResponseError(response=response{}{})".format(
1004
+ error_model,
1005
+ (", error_format=ARMErrorFormat" if self.code_model.options["azure_arm"] else ""),
1006
+ )
1007
+ )
1008
+ return retval
1009
+
1010
+ def handle_response(self, builder: OperationType) -> List[str]:
1011
+ retval: List[str] = ["response = pipeline_response.http_response"]
1012
+ retval.append("")
1013
+ retval.extend(self.handle_error_response(builder))
1014
+ retval.append("")
1015
+ if builder.has_optional_return_type:
1016
+ retval.append("deserialized = None")
1017
+ if builder.any_response_has_headers:
1018
+ retval.append("response_headers = {}")
1019
+ if builder.has_response_body or builder.any_response_has_headers:
1020
+ if len(builder.responses) > 1:
1021
+ for status_code in builder.success_status_codes:
1022
+ response = builder.get_response_from_status(status_code)
1023
+ if response.headers or response.type:
1024
+ retval.append(f"if response.status_code == {status_code}:")
1025
+ retval.extend(
1026
+ [f" {line}" for line in self.response_headers_and_deserialization(builder, response)]
1027
+ )
1028
+ retval.append("")
1029
+ else:
1030
+ retval.extend(self.response_headers_and_deserialization(builder, builder.responses[0]))
1031
+ retval.append("")
1032
+ if builder.has_optional_return_type or self.code_model.options["models_mode"]:
1033
+ deserialized = "deserialized"
1034
+ else:
1035
+ deserialized = f"cast({builder.response_type_annotation(async_mode=self.async_mode)}, deserialized)"
1036
+ retval.append("if cls:")
1037
+ retval.append(
1038
+ " return cls(pipeline_response, {}, {}){}".format(
1039
+ deserialized if builder.has_response_body else "None",
1040
+ "response_headers" if builder.any_response_has_headers else "{}",
1041
+ " # type: ignore",
1042
+ )
1043
+ )
1044
+ if builder.has_response_body and any(
1045
+ response.is_stream_response or response.type for response in builder.responses
1046
+ ):
1047
+ retval.append("")
1048
+ retval.append(f"return {deserialized} # type: ignore")
1049
+ if builder.request_builder.method == "HEAD" and self.code_model.options["head_as_boolean"]:
1050
+ retval.append("return 200 <= response.status_code <= 299")
1051
+ return retval
1052
+
1053
+ def error_map(self, builder: OperationType) -> List[str]:
1054
+ retval = ["error_map: MutableMapping[int, Type[HttpResponseError]] = {"]
1055
+ if builder.non_default_errors:
1056
+ if not 401 in builder.non_default_error_status_codes:
1057
+ retval.append(" 401: ClientAuthenticationError,")
1058
+ if not 404 in builder.non_default_error_status_codes:
1059
+ retval.append(" 404: ResourceNotFoundError,")
1060
+ if not 409 in builder.non_default_error_status_codes:
1061
+ retval.append(" 409: ResourceExistsError,")
1062
+ if not 304 in builder.non_default_error_status_codes:
1063
+ retval.append(" 304: ResourceNotModifiedError,")
1064
+ for excep in builder.non_default_errors:
1065
+ error_model_str = ""
1066
+ if isinstance(excep.type, ModelType):
1067
+ if self.code_model.options["models_mode"] == "msrest":
1068
+ error_model_str = (
1069
+ f", model=self._deserialize(" f"_models.{excep.type.serialization_type}, response)"
1070
+ )
1071
+ elif self.code_model.options["models_mode"] == "dpg":
1072
+ error_model_str = f", model=_deserialize(_models.{excep.type.name}, response.json())"
1073
+ error_format_str = ", error_format=ARMErrorFormat" if self.code_model.options["azure_arm"] else ""
1074
+ for status_code in excep.status_codes:
1075
+ if status_code == 401:
1076
+ retval.append(
1077
+ " 401: cast(Type[HttpResponseError], "
1078
+ "lambda response: ClientAuthenticationError(response=response"
1079
+ f"{error_model_str}{error_format_str})),"
1080
+ )
1081
+ elif status_code == 404:
1082
+ retval.append(
1083
+ " 404: cast(Type[HttpResponseError], "
1084
+ "lambda response: ResourceNotFoundError(response=response"
1085
+ f"{error_model_str}{error_format_str})),"
1086
+ )
1087
+ elif status_code == 409:
1088
+ retval.append(
1089
+ " 409: cast(Type[HttpResponseError], "
1090
+ "lambda response: ResourceExistsError(response=response"
1091
+ f"{error_model_str}{error_format_str})),"
1092
+ )
1093
+ elif status_code == 304:
1094
+ retval.append(
1095
+ " 304: cast(Type[HttpResponseError], "
1096
+ "lambda response: ResourceNotModifiedError(response=response"
1097
+ f"{error_model_str}{error_format_str})),"
1098
+ )
1099
+ elif not error_model_str and not error_format_str:
1100
+ retval.append(f" {status_code}: HttpResponseError,")
1101
+ else:
1102
+ retval.append(
1103
+ f" {status_code}: cast(Type[HttpResponseError], "
1104
+ "lambda response: HttpResponseError(response=response"
1105
+ f"{error_model_str}{error_format_str})),"
1106
+ )
1107
+ else:
1108
+ retval.append(
1109
+ " 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError, "
1110
+ "304: ResourceNotModifiedError"
1111
+ )
1112
+ retval.append("}")
1113
+ if builder.has_etag:
1114
+ retval.extend(
1115
+ [
1116
+ "if match_condition == MatchConditions.IfNotModified:",
1117
+ " error_map[412] = ResourceModifiedError",
1118
+ "elif match_condition == MatchConditions.IfPresent:",
1119
+ " error_map[412] = ResourceNotFoundError",
1120
+ "elif match_condition == MatchConditions.IfMissing:",
1121
+ " error_map[412] = ResourceExistsError",
1122
+ ]
1123
+ )
1124
+ retval.append("error_map.update(kwargs.pop('error_map', {}) or {})")
1125
+ return retval
1126
+
1127
+ @property
1128
+ def _call_method(self) -> str:
1129
+ return "await " if self.async_mode else ""
1130
+
1131
+
1132
+ class OperationSerializer(_OperationSerializer[Operation]): ...
1133
+
1134
+
1135
+ ############################## PAGING OPERATIONS ##############################
1136
+
1137
+ PagingOperationType = TypeVar("PagingOperationType", bound=Union[PagingOperation, LROPagingOperation])
1138
+
1139
+
1140
+ class _PagingOperationSerializer(_OperationSerializer[PagingOperationType]): # pylint: disable=abstract-method
1141
+ def __init__(self, code_model: CodeModel, async_mode: bool) -> None:
1142
+ # for pylint reasons need to redefine init
1143
+ # probably because inheritance is going too deep
1144
+ super().__init__(code_model, async_mode)
1145
+ self.code_model = code_model
1146
+ self.async_mode = async_mode
1147
+ self.parameter_serializer = ParameterSerializer()
1148
+
1149
+ def serialize_path(self, builder: PagingOperationType) -> List[str]:
1150
+ return self.parameter_serializer.serialize_path(builder.parameters.path, self.serializer_name)
1151
+
1152
+ def decorators(self, builder: PagingOperationType) -> List[str]:
1153
+ """Decorators for the method"""
1154
+ retval: List[str] = []
1155
+ if builder.is_overload:
1156
+ return ["@overload"]
1157
+ if self.code_model.options["tracing"] and builder.want_tracing:
1158
+ retval.append("@distributed_trace")
1159
+ if _api_version_validation(builder):
1160
+ retval.append(_api_version_validation(builder))
1161
+ return retval
1162
+
1163
+ def call_next_link_request_builder(self, builder: PagingOperationType) -> List[str]:
1164
+ if builder.next_request_builder:
1165
+ request_builder = builder.next_request_builder
1166
+ template_url = None
1167
+ else:
1168
+ request_builder = builder.request_builder
1169
+ template_url = "next_link"
1170
+
1171
+ request_builder = builder.next_request_builder or builder.request_builder
1172
+ if builder.next_request_builder:
1173
+ return self._call_request_builder_helper(
1174
+ builder,
1175
+ request_builder,
1176
+ template_url=template_url,
1177
+ is_next_request=True,
1178
+ )
1179
+ retval: List[str] = []
1180
+ query_str = ""
1181
+ next_link_str = "next_link"
1182
+ try:
1183
+ api_version_param = next(
1184
+ p for p in builder.client.parameters if p.is_api_version and p.location == ParameterLocation.QUERY
1185
+ )
1186
+ retval.append("# make call to next link with the client's api-version")
1187
+ retval.append("_parsed_next_link = urllib.parse.urlparse(next_link)")
1188
+ retval.extend(
1189
+ [
1190
+ "_next_request_params = case_insensitive_dict({",
1191
+ " key: [urllib.parse.quote(v) for v in value]"
1192
+ " for key, value in urllib.parse.parse_qs(_parsed_next_link.query).items()"
1193
+ "})",
1194
+ ]
1195
+ )
1196
+ api_version = (
1197
+ "self._api_version"
1198
+ if self.code_model.options["multiapi"] and builder.group_name
1199
+ else api_version_param.full_client_name
1200
+ )
1201
+ retval.append(f'_next_request_params["api-version"] = {api_version}')
1202
+ query_str = ", params=_next_request_params"
1203
+ next_link_str = "urllib.parse.urljoin(next_link, _parsed_next_link.path)"
1204
+ except StopIteration:
1205
+ pass
1206
+
1207
+ retval.append(f'_request = HttpRequest("GET", {next_link_str}{query_str})')
1208
+ retval.extend(self._postprocess_http_request(builder, "_request.url"))
1209
+
1210
+ return retval
1211
+
1212
+ def _prepare_request_callback(self, builder: PagingOperationType) -> List[str]:
1213
+ retval = self._initialize_overloads(builder)
1214
+ retval.append("def prepare_request(next_link=None):")
1215
+ retval.append(" if not next_link:")
1216
+ retval.extend([f" {line}" for line in self.call_request_builder(builder, is_paging=True)])
1217
+ retval.append("")
1218
+ retval.append(" else:")
1219
+ retval.extend([f" {line}" for line in self.call_next_link_request_builder(builder)])
1220
+ if not builder.next_request_builder and self.code_model.is_legacy:
1221
+ retval.append(' _request.method = "GET"')
1222
+ else:
1223
+ retval.append("")
1224
+ retval.append(" return _request")
1225
+ return retval
1226
+
1227
+ @property
1228
+ def _function_def(self) -> str:
1229
+ return "def"
1230
+
1231
+ def _extract_data_callback(self, builder: PagingOperationType) -> List[str]:
1232
+ retval = [f"{'async ' if self.async_mode else ''}def extract_data(pipeline_response):"]
1233
+ response = builder.responses[0]
1234
+ deserialized = "pipeline_response.http_response.json()"
1235
+ if self.code_model.options["models_mode"] == "msrest":
1236
+ suffix = ".http_response" if hasattr(builder, "initial_operation") else ""
1237
+ deserialize_type = response.serialization_type
1238
+ pylint_disable = " # pylint: disable=protected-access"
1239
+ if isinstance(response.type, ModelType) and not response.type.internal:
1240
+ deserialize_type = f'"{response.serialization_type}"'
1241
+ pylint_disable = ""
1242
+ deserialized = (
1243
+ f"self._deserialize(\n {deserialize_type},{pylint_disable}\n pipeline_response{suffix}\n)"
1244
+ )
1245
+ retval.append(f" deserialized = {deserialized}")
1246
+ elif self.code_model.options["models_mode"] == "dpg":
1247
+ # we don't want to generate paging models for DPG
1248
+ retval.append(f" deserialized = {deserialized}")
1249
+ else:
1250
+ retval.append(f" deserialized = {deserialized}")
1251
+ item_name = builder.item_name
1252
+ access = f".{item_name}" if self.code_model.options["models_mode"] == "msrest" else f'["{item_name}"]'
1253
+ list_of_elem_deserialized = ""
1254
+ if self.code_model.options["models_mode"] == "dpg":
1255
+ item_type = builder.item_type.type_annotation(is_operation_file=True)
1256
+ list_of_elem_deserialized = f"_deserialize({item_type}, deserialized{access})"
1257
+ else:
1258
+ list_of_elem_deserialized = f"deserialized{access}"
1259
+ retval.append(f" list_of_elem = {list_of_elem_deserialized}")
1260
+ retval.append(" if cls:")
1261
+ retval.append(" list_of_elem = cls(list_of_elem) # type: ignore")
1262
+
1263
+ continuation_token_name = builder.continuation_token_name
1264
+ if not continuation_token_name:
1265
+ cont_token_property = "None"
1266
+ elif self.code_model.options["models_mode"] == "msrest":
1267
+ cont_token_property = f"deserialized.{continuation_token_name} or None"
1268
+ else:
1269
+ cont_token_property = f'deserialized.get("{continuation_token_name}") or None'
1270
+ list_type = "AsyncList" if self.async_mode else "iter"
1271
+ retval.append(f" return {cont_token_property}, {list_type}(list_of_elem)")
1272
+ return retval
1273
+
1274
+ def _get_next_callback(self, builder: PagingOperationType) -> List[str]:
1275
+ retval = [f"{'async ' if self.async_mode else ''}def get_next(next_link=None):"]
1276
+ retval.append(" _request = prepare_request(next_link)")
1277
+ retval.append("")
1278
+ retval.extend([f" {l}" for l in self.make_pipeline_call(builder)])
1279
+ retval.append(" response = pipeline_response.http_response")
1280
+ retval.append("")
1281
+ retval.extend([f" {line}" for line in self.handle_error_response(builder)])
1282
+ retval.append("")
1283
+ retval.append(" return pipeline_response")
1284
+ return retval
1285
+
1286
+ def set_up_params_for_pager(self, builder: PagingOperationType) -> List[str]:
1287
+ retval = []
1288
+ retval.extend(self.error_map(builder))
1289
+ retval.extend(self._prepare_request_callback(builder))
1290
+ retval.append("")
1291
+ retval.extend(self._extract_data_callback(builder))
1292
+ retval.append("")
1293
+ retval.extend(self._get_next_callback(builder))
1294
+ return retval
1295
+
1296
+
1297
+ class PagingOperationSerializer(_PagingOperationSerializer[PagingOperation]): ...
1298
+
1299
+
1300
+ ############################## LRO OPERATIONS ##############################
1301
+
1302
+ LROOperationType = TypeVar("LROOperationType", bound=Union[LROOperation, LROPagingOperation])
1303
+
1304
+
1305
+ class _LROOperationSerializer(_OperationSerializer[LROOperationType]):
1306
+ def __init__(self, code_model: CodeModel, async_mode: bool) -> None:
1307
+ # for pylint reasons need to redefine init
1308
+ # probably because inheritance is going too deep
1309
+ super().__init__(code_model, async_mode)
1310
+ self.code_model = code_model
1311
+ self.async_mode = async_mode
1312
+ self.parameter_serializer = ParameterSerializer()
1313
+
1314
+ def serialize_path(self, builder: LROOperationType) -> List[str]:
1315
+ return self.parameter_serializer.serialize_path(builder.parameters.path, self.serializer_name)
1316
+
1317
+ def initial_call(self, builder: LROOperationType) -> List[str]:
1318
+ retval = [
1319
+ f"polling: Union[bool, {builder.get_base_polling_method(self.async_mode)}] = kwargs.pop('polling', True)",
1320
+ ]
1321
+ retval.append("lro_delay = kwargs.pop(")
1322
+ retval.append(" 'polling_interval',")
1323
+ retval.append(" self._config.polling_interval")
1324
+ retval.append(")")
1325
+ retval.append("cont_token: Optional[str] = kwargs.pop('continuation_token', None)")
1326
+ retval.append("if cont_token is None:")
1327
+ retval.append(
1328
+ f" raw_result = {self._call_method}self.{builder.initial_operation.name}("
1329
+ f"{'' if any(rsp.type for rsp in builder.initial_operation.responses) else ' # type: ignore'}"
1330
+ )
1331
+ retval.extend(
1332
+ [f" {parameter.client_name}={parameter.client_name}," for parameter in builder.parameters.method]
1333
+ )
1334
+ retval.append(" cls=lambda x,y,z: x,")
1335
+ retval.append(" headers=_headers,")
1336
+ retval.append(" params=_params,")
1337
+ retval.append(" **kwargs")
1338
+ retval.append(" )")
1339
+ retval.append(f" {'await ' if self.async_mode else ''}raw_result.http_response.read() # type: ignore")
1340
+
1341
+ retval.append("kwargs.pop('error_map', None)")
1342
+ return retval
1343
+
1344
+ def return_lro_poller(self, builder: LROOperationType) -> List[str]:
1345
+ retval = []
1346
+ lro_options_str = (
1347
+ "lro_options={'final-state-via': '" + builder.lro_options["final-state-via"] + "'},"
1348
+ if builder.lro_options
1349
+ else ""
1350
+ )
1351
+ path_format_arguments_str = ""
1352
+ if builder.parameters.path:
1353
+ path_format_arguments_str = "path_format_arguments=path_format_arguments,"
1354
+ retval.extend(self.serialize_path(builder))
1355
+ retval.append("")
1356
+ retval.extend(
1357
+ [
1358
+ "if polling is True:",
1359
+ f" polling_method: {builder.get_base_polling_method(self.async_mode)} "
1360
+ + f"= cast({builder.get_base_polling_method(self.async_mode)}, "
1361
+ f"{builder.get_polling_method(self.async_mode)}(",
1362
+ " lro_delay,",
1363
+ f" {lro_options_str}",
1364
+ f" {path_format_arguments_str}",
1365
+ " **kwargs",
1366
+ "))",
1367
+ ]
1368
+ )
1369
+ retval.append(
1370
+ f"elif polling is False: polling_method = cast({builder.get_base_polling_method(self.async_mode)}, "
1371
+ f"{builder.get_no_polling_method(self.async_mode)}())"
1372
+ )
1373
+ retval.append("else: polling_method = polling")
1374
+ retval.append("if cont_token:")
1375
+ retval.append(f" return {builder.get_poller_with_response_type(self.async_mode)}.from_continuation_token(")
1376
+ retval.append(" polling_method=polling_method,")
1377
+ retval.append(" continuation_token=cont_token,")
1378
+ retval.append(" client=self._client,")
1379
+ retval.append(" deserialization_callback=get_long_running_output")
1380
+ retval.append(" )")
1381
+ retval.append(f"return {builder.get_poller_with_response_type(self.async_mode)}(")
1382
+ retval.append(" self._client, raw_result, get_long_running_output, polling_method # type: ignore")
1383
+ retval.append(" )")
1384
+ return retval
1385
+
1386
+ def get_long_running_output(self, builder: LROOperationType) -> List[str]:
1387
+ pylint_disable = ""
1388
+ if not builder.lro_response:
1389
+ pylint_disable = " # pylint: disable=inconsistent-return-statements"
1390
+ retval = [f"def get_long_running_output(pipeline_response):{pylint_disable}"]
1391
+ if builder.lro_response:
1392
+ if builder.lro_response.headers:
1393
+ retval.append(" response_headers = {}")
1394
+ if (
1395
+ not self.code_model.options["models_mode"]
1396
+ or self.code_model.options["models_mode"] == "dpg"
1397
+ or builder.lro_response.headers
1398
+ ):
1399
+ retval.append(" response = pipeline_response.http_response")
1400
+ retval.extend(
1401
+ [f" {line}" for line in self.response_headers_and_deserialization(builder, builder.lro_response)]
1402
+ )
1403
+ retval.append(" if cls:")
1404
+ retval.append(
1405
+ " return cls(pipeline_response, {}, {}){}".format(
1406
+ ("deserialized" if builder.lro_response and builder.lro_response.type else "None"),
1407
+ ("response_headers" if builder.lro_response and builder.lro_response.headers else "{}"),
1408
+ " # type: ignore",
1409
+ )
1410
+ )
1411
+ if builder.lro_response and builder.lro_response.type:
1412
+ retval.append(" return deserialized")
1413
+ return retval
1414
+
1415
+
1416
+ class LROOperationSerializer(_LROOperationSerializer[LROOperation]): ...
1417
+
1418
+
1419
+ ############################## LRO PAGING OPERATIONS ##############################
1420
+
1421
+
1422
+ class LROPagingOperationSerializer(
1423
+ _LROOperationSerializer[LROPagingOperation],
1424
+ _PagingOperationSerializer[LROPagingOperation],
1425
+ ): # pylint: disable=abstract-method
1426
+ @property
1427
+ def _call_method(self) -> str:
1428
+ return "await " if self.async_mode else ""
1429
+
1430
+ @property
1431
+ def _function_def(self) -> str:
1432
+ return "async def" if self.async_mode else "def"
1433
+
1434
+ def get_long_running_output(self, builder: LROPagingOperation) -> List[str]:
1435
+ retval = ["def get_long_running_output(pipeline_response):"]
1436
+ retval.append(f" {self._function_def} internal_get_next(next_link=None):")
1437
+ retval.append(" if next_link is None:")
1438
+ retval.append(" return pipeline_response")
1439
+ retval.append(f" return {self._call_method}get_next(next_link)")
1440
+ retval.append("")
1441
+ retval.append(f" return {builder.get_pager(self.async_mode)}(")
1442
+ retval.append(" internal_get_next, extract_data")
1443
+ retval.append(" )")
1444
+ return retval
1445
+
1446
+ def decorators(self, builder: LROPagingOperation) -> List[str]:
1447
+ """Decorators for the method"""
1448
+ return _LROOperationSerializer.decorators(self, builder) # type: ignore
1449
+
1450
+
1451
+ def get_operation_serializer(
1452
+ builder: Operation,
1453
+ code_model,
1454
+ async_mode: bool,
1455
+ ) -> Union[
1456
+ OperationSerializer,
1457
+ PagingOperationSerializer,
1458
+ LROOperationSerializer,
1459
+ LROPagingOperationSerializer,
1460
+ ]:
1461
+ retcls: Union[
1462
+ Type[OperationSerializer],
1463
+ Type[PagingOperationSerializer],
1464
+ Type[LROOperationSerializer],
1465
+ Type[LROPagingOperationSerializer],
1466
+ ] = OperationSerializer
1467
+ if builder.operation_type == "lropaging":
1468
+ retcls = LROPagingOperationSerializer
1469
+ elif builder.operation_type == "lro":
1470
+ retcls = LROOperationSerializer
1471
+ elif builder.operation_type == "paging":
1472
+ retcls = PagingOperationSerializer
1473
+ return retcls(code_model, async_mode)