@typespec/http-client-python 0.4.4 → 0.5.1

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