@typespec/http-client-python 0.4.4 → 0.5.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/emitter/emitter.d.ts.map +1 -1
  2. package/dist/emitter/emitter.js +85 -24
  3. package/dist/emitter/emitter.js.map +1 -1
  4. package/dist/emitter/lib.d.ts +1 -0
  5. package/dist/emitter/lib.d.ts.map +1 -1
  6. package/dist/emitter/lib.js +1 -0
  7. package/dist/emitter/lib.js.map +1 -1
  8. package/dist/emitter/run-python3.d.ts +2 -0
  9. package/dist/emitter/run-python3.d.ts.map +1 -0
  10. package/dist/emitter/run-python3.js +19 -0
  11. package/dist/emitter/run-python3.js.map +1 -0
  12. package/dist/emitter/system-requirements.d.ts +17 -0
  13. package/dist/emitter/system-requirements.d.ts.map +1 -0
  14. package/dist/emitter/system-requirements.js +167 -0
  15. package/dist/emitter/system-requirements.js.map +1 -0
  16. package/emitter/src/emitter.ts +88 -23
  17. package/emitter/src/lib.ts +2 -0
  18. package/emitter/src/run-python3.ts +20 -0
  19. package/emitter/src/system-requirements.ts +261 -0
  20. package/emitter/temp/tsconfig.tsbuildinfo +1 -1
  21. package/eng/scripts/ci/regenerate.ts +16 -4
  22. package/eng/scripts/setup/__pycache__/venvtools.cpython-38.pyc +0 -0
  23. package/eng/scripts/setup/build.ts +16 -0
  24. package/eng/scripts/setup/build_pygen_wheel.py +40 -0
  25. package/eng/scripts/setup/install.py +9 -3
  26. package/eng/scripts/setup/install.ts +32 -0
  27. package/eng/scripts/setup/prepare.py +3 -1
  28. package/eng/scripts/setup/prepare.ts +11 -0
  29. package/eng/scripts/setup/run-python3.ts +1 -6
  30. package/generator/build/lib/pygen/__init__.py +107 -0
  31. package/generator/build/lib/pygen/_version.py +7 -0
  32. package/generator/build/lib/pygen/black.py +71 -0
  33. package/generator/build/lib/pygen/codegen/__init__.py +357 -0
  34. package/generator/build/lib/pygen/codegen/_utils.py +17 -0
  35. package/generator/build/lib/pygen/codegen/models/__init__.py +204 -0
  36. package/generator/build/lib/pygen/codegen/models/base.py +186 -0
  37. package/generator/build/lib/pygen/codegen/models/base_builder.py +118 -0
  38. package/generator/build/lib/pygen/codegen/models/client.py +435 -0
  39. package/generator/build/lib/pygen/codegen/models/code_model.py +237 -0
  40. package/generator/build/lib/pygen/codegen/models/combined_type.py +149 -0
  41. package/generator/build/lib/pygen/codegen/models/constant_type.py +129 -0
  42. package/generator/build/lib/pygen/codegen/models/credential_types.py +214 -0
  43. package/generator/build/lib/pygen/codegen/models/dictionary_type.py +127 -0
  44. package/generator/build/lib/pygen/codegen/models/enum_type.py +238 -0
  45. package/generator/build/lib/pygen/codegen/models/imports.py +291 -0
  46. package/generator/build/lib/pygen/codegen/models/list_type.py +143 -0
  47. package/generator/build/lib/pygen/codegen/models/lro_operation.py +142 -0
  48. package/generator/build/lib/pygen/codegen/models/lro_paging_operation.py +32 -0
  49. package/generator/build/lib/pygen/codegen/models/model_type.py +357 -0
  50. package/generator/build/lib/pygen/codegen/models/operation.py +509 -0
  51. package/generator/build/lib/pygen/codegen/models/operation_group.py +184 -0
  52. package/generator/build/lib/pygen/codegen/models/paging_operation.py +155 -0
  53. package/generator/build/lib/pygen/codegen/models/parameter.py +412 -0
  54. package/generator/build/lib/pygen/codegen/models/parameter_list.py +387 -0
  55. package/generator/build/lib/pygen/codegen/models/primitive_types.py +659 -0
  56. package/generator/build/lib/pygen/codegen/models/property.py +170 -0
  57. package/generator/build/lib/pygen/codegen/models/request_builder.py +189 -0
  58. package/generator/build/lib/pygen/codegen/models/request_builder_parameter.py +115 -0
  59. package/generator/build/lib/pygen/codegen/models/response.py +348 -0
  60. package/generator/build/lib/pygen/codegen/models/utils.py +21 -0
  61. package/generator/build/lib/pygen/codegen/serializers/__init__.py +574 -0
  62. package/generator/build/lib/pygen/codegen/serializers/base_serializer.py +21 -0
  63. package/generator/build/lib/pygen/codegen/serializers/builder_serializer.py +1533 -0
  64. package/generator/build/lib/pygen/codegen/serializers/client_serializer.py +294 -0
  65. package/generator/build/lib/pygen/codegen/serializers/enum_serializer.py +15 -0
  66. package/generator/build/lib/pygen/codegen/serializers/general_serializer.py +213 -0
  67. package/generator/build/lib/pygen/codegen/serializers/import_serializer.py +126 -0
  68. package/generator/build/lib/pygen/codegen/serializers/metadata_serializer.py +198 -0
  69. package/generator/build/lib/pygen/codegen/serializers/model_init_serializer.py +33 -0
  70. package/generator/build/lib/pygen/codegen/serializers/model_serializer.py +335 -0
  71. package/generator/build/lib/pygen/codegen/serializers/operation_groups_serializer.py +89 -0
  72. package/generator/build/lib/pygen/codegen/serializers/operations_init_serializer.py +44 -0
  73. package/generator/build/lib/pygen/codegen/serializers/parameter_serializer.py +221 -0
  74. package/generator/build/lib/pygen/codegen/serializers/patch_serializer.py +19 -0
  75. package/generator/build/lib/pygen/codegen/serializers/request_builders_serializer.py +52 -0
  76. package/generator/build/lib/pygen/codegen/serializers/sample_serializer.py +168 -0
  77. package/generator/build/lib/pygen/codegen/serializers/test_serializer.py +292 -0
  78. package/generator/build/lib/pygen/codegen/serializers/types_serializer.py +31 -0
  79. package/generator/build/lib/pygen/codegen/serializers/utils.py +68 -0
  80. package/generator/build/lib/pygen/codegen/templates/client.py.jinja2 +37 -0
  81. package/generator/build/lib/pygen/codegen/templates/client_container.py.jinja2 +12 -0
  82. package/generator/build/lib/pygen/codegen/templates/config.py.jinja2 +73 -0
  83. package/generator/build/lib/pygen/codegen/templates/config_container.py.jinja2 +16 -0
  84. package/generator/build/lib/pygen/codegen/templates/conftest.py.jinja2 +28 -0
  85. package/generator/build/lib/pygen/codegen/templates/enum.py.jinja2 +13 -0
  86. package/generator/build/lib/pygen/codegen/templates/enum_container.py.jinja2 +10 -0
  87. package/generator/build/lib/pygen/codegen/templates/init.py.jinja2 +24 -0
  88. package/generator/build/lib/pygen/codegen/templates/keywords.jinja2 +27 -0
  89. package/generator/build/lib/pygen/codegen/templates/lro_operation.py.jinja2 +16 -0
  90. package/generator/build/lib/pygen/codegen/templates/lro_paging_operation.py.jinja2 +18 -0
  91. package/generator/build/lib/pygen/codegen/templates/macros.jinja2 +12 -0
  92. package/generator/build/lib/pygen/codegen/templates/metadata.json.jinja2 +167 -0
  93. package/generator/build/lib/pygen/codegen/templates/model_base.py.jinja2 +1174 -0
  94. package/generator/build/lib/pygen/codegen/templates/model_container.py.jinja2 +15 -0
  95. package/generator/build/lib/pygen/codegen/templates/model_dpg.py.jinja2 +97 -0
  96. package/generator/build/lib/pygen/codegen/templates/model_init.py.jinja2 +33 -0
  97. package/generator/build/lib/pygen/codegen/templates/model_msrest.py.jinja2 +92 -0
  98. package/generator/build/lib/pygen/codegen/templates/operation.py.jinja2 +21 -0
  99. package/generator/build/lib/pygen/codegen/templates/operation_group.py.jinja2 +75 -0
  100. package/generator/build/lib/pygen/codegen/templates/operation_groups_container.py.jinja2 +19 -0
  101. package/generator/build/lib/pygen/codegen/templates/operation_tools.jinja2 +81 -0
  102. package/generator/build/lib/pygen/codegen/templates/operations_folder_init.py.jinja2 +17 -0
  103. package/generator/build/lib/pygen/codegen/templates/packaging_templates/CHANGELOG.md.jinja2 +6 -0
  104. package/generator/build/lib/pygen/codegen/templates/packaging_templates/LICENSE.jinja2 +21 -0
  105. package/generator/build/lib/pygen/codegen/templates/packaging_templates/MANIFEST.in.jinja2 +8 -0
  106. package/generator/build/lib/pygen/codegen/templates/packaging_templates/README.md.jinja2 +107 -0
  107. package/generator/build/lib/pygen/codegen/templates/packaging_templates/dev_requirements.txt.jinja2 +9 -0
  108. package/generator/build/lib/pygen/codegen/templates/packaging_templates/setup.py.jinja2 +108 -0
  109. package/generator/build/lib/pygen/codegen/templates/paging_operation.py.jinja2 +21 -0
  110. package/generator/build/lib/pygen/codegen/templates/patch.py.jinja2 +19 -0
  111. package/generator/build/lib/pygen/codegen/templates/pkgutil_init.py.jinja2 +1 -0
  112. package/generator/build/lib/pygen/codegen/templates/request_builder.py.jinja2 +28 -0
  113. package/generator/build/lib/pygen/codegen/templates/request_builders.py.jinja2 +10 -0
  114. package/generator/build/lib/pygen/codegen/templates/rest_init.py.jinja2 +12 -0
  115. package/generator/build/lib/pygen/codegen/templates/sample.py.jinja2 +44 -0
  116. package/generator/build/lib/pygen/codegen/templates/serialization.py.jinja2 +2117 -0
  117. package/generator/build/lib/pygen/codegen/templates/test.py.jinja2 +50 -0
  118. package/generator/build/lib/pygen/codegen/templates/testpreparer.py.jinja2 +26 -0
  119. package/generator/build/lib/pygen/codegen/templates/types.py.jinja2 +7 -0
  120. package/generator/build/lib/pygen/codegen/templates/validation.py.jinja2 +38 -0
  121. package/generator/build/lib/pygen/codegen/templates/vendor.py.jinja2 +96 -0
  122. package/generator/build/lib/pygen/codegen/templates/version.py.jinja2 +4 -0
  123. package/generator/build/lib/pygen/m2r.py +65 -0
  124. package/generator/build/lib/pygen/preprocess/__init__.py +515 -0
  125. package/generator/build/lib/pygen/preprocess/helpers.py +27 -0
  126. package/generator/build/lib/pygen/preprocess/python_mappings.py +226 -0
  127. package/generator/build/lib/pygen/utils.py +163 -0
  128. package/generator/component-detection-pip-report.json +134 -0
  129. package/generator/dev_requirements.txt +0 -1
  130. package/generator/dist/pygen-0.1.0-py3-none-any.whl +0 -0
  131. package/generator/pygen.egg-info/PKG-INFO +7 -4
  132. package/generator/pygen.egg-info/requires.txt +7 -4
  133. package/generator/requirements.txt +5 -10
  134. package/generator/setup.py +7 -4
  135. package/generator/test/azure/requirements.txt +1 -1
  136. package/generator/test/unbranded/requirements.txt +1 -1
  137. package/package.json +6 -5
@@ -0,0 +1,515 @@
1
+ # -------------------------------------------------------------------------
2
+ # Copyright (c) Microsoft Corporation. All rights reserved.
3
+ # Licensed under the MIT License. See License.txt in the project root for
4
+ # license information.
5
+ # --------------------------------------------------------------------------
6
+ """The preprocessing autorest plugin.
7
+ """
8
+ import copy
9
+ from typing import Callable, Dict, Any, List, Optional
10
+
11
+ from ..utils import to_snake_case, extract_original_name
12
+ from .helpers import (
13
+ add_redefined_builtin_info,
14
+ pad_builtin_namespaces,
15
+ pad_special_chars,
16
+ )
17
+ from .python_mappings import CADL_RESERVED_WORDS, RESERVED_WORDS, PadType
18
+
19
+ from .. import YamlUpdatePlugin
20
+ from ..utils import (
21
+ parse_args,
22
+ get_body_type_for_description,
23
+ JSON_REGEXP,
24
+ KNOWN_TYPES,
25
+ update_enum_value,
26
+ )
27
+
28
+
29
+ def update_overload_section(
30
+ overload: Dict[str, Any],
31
+ yaml_data: Dict[str, Any],
32
+ section: str,
33
+ ):
34
+ try:
35
+ for overload_s, original_s in zip(overload[section], yaml_data[section]):
36
+ if overload_s.get("type"):
37
+ overload_s["type"] = original_s["type"]
38
+ if overload_s.get("headers"):
39
+ for overload_h, original_h in zip(overload_s["headers"], original_s["headers"]):
40
+ if overload_h.get("type"):
41
+ overload_h["type"] = original_h["type"]
42
+ except KeyError as exc:
43
+ raise ValueError(overload["name"]) from exc
44
+
45
+
46
+ def add_overload(yaml_data: Dict[str, Any], body_type: Dict[str, Any], for_flatten_params=False):
47
+ overload = copy.deepcopy(yaml_data)
48
+ overload["isOverload"] = True
49
+ overload["bodyParameter"]["type"] = body_type
50
+ overload["bodyParameter"]["defaultToUnsetSentinel"] = False
51
+ overload["overloads"] = []
52
+ if yaml_data.get("initialOperation"):
53
+ overload["initialOperation"] = yaml_data["initialOperation"]
54
+
55
+ if for_flatten_params:
56
+ overload["bodyParameter"]["flattened"] = True
57
+ else:
58
+ overload["parameters"] = [p for p in overload["parameters"] if not p.get("inFlattenedBody")]
59
+ # for yaml sync, we need to make sure all of the responses, parameters, and exceptions' types have the same yaml id
60
+ for overload_p, original_p in zip(overload["parameters"], yaml_data["parameters"]):
61
+ overload_p["type"] = original_p["type"]
62
+ update_overload_section(overload, yaml_data, "responses")
63
+ update_overload_section(overload, yaml_data, "exceptions")
64
+
65
+ # update content type to be an overloads content type
66
+ content_type_param = next(p for p in overload["parameters"] if p["wireName"].lower() == "content-type")
67
+ content_type_param["inOverload"] = True
68
+ content_type_param["inDocstring"] = True
69
+ body_type_description = get_body_type_for_description(overload["bodyParameter"])
70
+ content_type_param["description"] = (
71
+ f"Body Parameter content-type. Content type parameter for {body_type_description} body."
72
+ )
73
+ content_types = yaml_data["bodyParameter"]["contentTypes"]
74
+ if body_type["type"] == "binary" and len(content_types) > 1:
75
+ content_types = "'" + "', '".join(content_types) + "'"
76
+ content_type_param["description"] += f" Known values are: {content_types}."
77
+ overload["bodyParameter"]["inOverload"] = True
78
+ for parameter in overload["parameters"]:
79
+ parameter["inOverload"] = True
80
+ parameter["defaultToUnsetSentinel"] = False
81
+ return overload
82
+
83
+
84
+ def add_overloads_for_body_param(yaml_data: Dict[str, Any]) -> None:
85
+ """If we added a body parameter type, add overloads for that type"""
86
+ body_parameter = yaml_data["bodyParameter"]
87
+ if not (
88
+ body_parameter["type"]["type"] == "combined"
89
+ and len(yaml_data["bodyParameter"]["type"]["types"]) > len(yaml_data["overloads"])
90
+ ):
91
+ return
92
+ for body_type in body_parameter["type"]["types"]:
93
+ if any(o for o in yaml_data["overloads"] if id(o["bodyParameter"]["type"]) == id(body_type)):
94
+ continue
95
+ yaml_data["overloads"].append(add_overload(yaml_data, body_type))
96
+ if body_type.get("type") == "model" and body_type.get("base") == "json":
97
+ yaml_data["overloads"].append(add_overload(yaml_data, body_type, for_flatten_params=True))
98
+ content_type_param = next(p for p in yaml_data["parameters"] if p["wireName"].lower() == "content-type")
99
+ content_type_param["inOverload"] = False
100
+ content_type_param["inOverridden"] = True
101
+ content_type_param["inDocstring"] = True
102
+ content_type_param["clientDefaultValue"] = (
103
+ None # make it none bc it will be overridden, we depend on default of overloads
104
+ )
105
+ content_type_param["optional"] = True
106
+
107
+
108
+ def update_description(description: Optional[str], default_description: str = "") -> str:
109
+ if not description:
110
+ description = default_description
111
+ description.rstrip(" ")
112
+ if description and description[-1] != ".":
113
+ description += "."
114
+ return description
115
+
116
+
117
+ def update_operation_group_class_name(prefix: str, class_name: str) -> str:
118
+ if class_name == "":
119
+ return prefix + "OperationsMixin"
120
+ if class_name == "Operations":
121
+ return "Operations"
122
+ return class_name + "Operations"
123
+
124
+
125
+ def update_paging_response(yaml_data: Dict[str, Any]) -> None:
126
+ yaml_data["discriminator"] = "paging"
127
+
128
+
129
+ HEADERS_HIDE_IN_METHOD = (
130
+ "repeatability-request-id",
131
+ "repeatability-first-sent",
132
+ "x-ms-client-request-id",
133
+ "client-request-id",
134
+ "return-client-request-id",
135
+ )
136
+ HEADERS_CONVERT_IN_METHOD = {
137
+ "if-match": {
138
+ "clientName": "etag",
139
+ "wireName": "etag",
140
+ "description": "check if resource is changed. Set None to skip checking etag.",
141
+ },
142
+ "if-none-match": {
143
+ "clientName": "match_condition",
144
+ "wireName": "match-condition",
145
+ "description": "The match condition to use upon the etag.",
146
+ "type": {
147
+ "type": "sdkcore",
148
+ "name": "MatchConditions",
149
+ },
150
+ },
151
+ }
152
+
153
+
154
+ def get_wire_name_lower(parameter: Dict[str, Any]) -> str:
155
+ return (parameter.get("wireName") or "").lower()
156
+
157
+
158
+ def headers_convert(yaml_data: Dict[str, Any], replace_data: Any) -> None:
159
+ if isinstance(replace_data, dict):
160
+ for k, v in replace_data.items():
161
+ yaml_data[k] = v
162
+
163
+
164
+ def has_json_content_type(yaml_data: Dict[str, Any]) -> bool:
165
+ return any(ct for ct in yaml_data.get("contentTypes", []) if JSON_REGEXP.match(ct))
166
+
167
+
168
+ def has_multi_part_content_type(yaml_data: Dict[str, Any]) -> bool:
169
+ return any(ct for ct in yaml_data.get("contentTypes", []) if ct == "multipart/form-data")
170
+
171
+
172
+ class PreProcessPlugin(YamlUpdatePlugin):
173
+ """Add Python naming information."""
174
+
175
+ @property
176
+ def azure_arm(self) -> bool:
177
+ return self.options.get("azure-arm", False)
178
+
179
+ @property
180
+ def version_tolerant(self) -> bool:
181
+ return self.options.get("version-tolerant", True)
182
+
183
+ @property
184
+ def models_mode(self) -> Optional[str]:
185
+ return self.options.get("models-mode", "dpg" if self.is_cadl else None)
186
+
187
+ @property
188
+ def is_cadl(self) -> bool:
189
+ return self.options.get("cadl_file", False)
190
+
191
+ def add_body_param_type(
192
+ self,
193
+ code_model: Dict[str, Any],
194
+ body_parameter: Dict[str, Any],
195
+ ):
196
+ # only add overload for special content type
197
+ if ( # pylint: disable=too-many-boolean-expressions
198
+ body_parameter
199
+ and body_parameter["type"]["type"] in ("model", "dict", "list")
200
+ and (
201
+ has_json_content_type(body_parameter) or (self.is_cadl and has_multi_part_content_type(body_parameter))
202
+ )
203
+ and not body_parameter["type"].get("xmlMetadata")
204
+ and not any(t for t in ["flattened", "groupedBy"] if body_parameter.get(t))
205
+ ):
206
+ origin_type = body_parameter["type"]["type"]
207
+ is_dpg_model = body_parameter["type"].get("base") == "dpg"
208
+ body_parameter["type"] = {
209
+ "type": "combined",
210
+ "types": [body_parameter["type"]],
211
+ }
212
+ # don't add binary overload for multipart content type
213
+ if not (self.is_cadl and has_multi_part_content_type(body_parameter)):
214
+ body_parameter["type"]["types"].append(KNOWN_TYPES["binary"])
215
+
216
+ if origin_type == "model" and is_dpg_model and self.models_mode == "dpg":
217
+ body_parameter["type"]["types"].insert(1, KNOWN_TYPES["any-object"])
218
+ code_model["types"].append(body_parameter["type"])
219
+
220
+ def pad_reserved_words(self, name: str, pad_type: PadType):
221
+ # we want to pad hidden variables as well
222
+ if not name:
223
+ # we'll pass in empty operation groups sometime etc.
224
+ return name
225
+
226
+ if self.is_cadl:
227
+ reserved_words = {k: (v + CADL_RESERVED_WORDS.get(k, [])) for k, v in RESERVED_WORDS.items()}
228
+ else:
229
+ reserved_words = RESERVED_WORDS
230
+ name = pad_special_chars(name)
231
+ name_prefix = "_" if name[0] == "_" else ""
232
+ name = name[1:] if name[0] == "_" else name
233
+ if name.lower() in reserved_words[pad_type]:
234
+ return name_prefix + name + pad_type
235
+ return name_prefix + name
236
+
237
+ def update_types(self, yaml_data: List[Dict[str, Any]]) -> None:
238
+ for type in yaml_data:
239
+ for property in type.get("properties", []):
240
+ property["description"] = update_description(property.get("description", ""))
241
+ property["clientName"] = self.pad_reserved_words(property["clientName"].lower(), PadType.PROPERTY)
242
+ add_redefined_builtin_info(property["clientName"], property)
243
+ if type.get("name"):
244
+ pad_type = PadType.MODEL if type["type"] == "model" else PadType.ENUM_CLASS
245
+ name = self.pad_reserved_words(type["name"], pad_type)
246
+ type["name"] = name[0].upper() + name[1:]
247
+ type["description"] = update_description(type.get("description", ""), type["name"])
248
+ type["snakeCaseName"] = to_snake_case(type["name"])
249
+ if type.get("values"):
250
+ # we're enums
251
+ values_to_add = []
252
+ for value in type["values"]:
253
+ padded_name = self.pad_reserved_words(value["name"].lower(), PadType.ENUM_VALUE).upper()
254
+ if self.version_tolerant:
255
+ if padded_name[0] in "0123456789":
256
+ padded_name = "ENUM_" + padded_name
257
+ value["name"] = padded_name
258
+ else:
259
+ if value["name"] != padded_name:
260
+ values_to_add.append(
261
+ update_enum_value(
262
+ name=padded_name,
263
+ value=value["value"],
264
+ description=value["description"],
265
+ enum_type=value["enumType"],
266
+ )
267
+ )
268
+ type["values"].extend(values_to_add)
269
+
270
+ # add type for reference
271
+ for v in HEADERS_CONVERT_IN_METHOD.values():
272
+ if isinstance(v, dict) and "type" in v:
273
+ yaml_data.append(v["type"])
274
+
275
+ def update_client(self, yaml_data: Dict[str, Any]) -> None:
276
+ yaml_data["description"] = update_description(yaml_data["description"], default_description=yaml_data["name"])
277
+ yaml_data["legacyFilename"] = to_snake_case(yaml_data["name"].replace(" ", "_"))
278
+ parameters = yaml_data["parameters"]
279
+ for parameter in parameters:
280
+ self.update_parameter(parameter)
281
+ if parameter["clientName"] == "credential":
282
+ policy = parameter["type"].get("policy")
283
+ if policy and policy["type"] == "BearerTokenCredentialPolicy" and self.azure_arm:
284
+ policy["type"] = "ARMChallengeAuthenticationPolicy"
285
+ policy["credentialScopes"] = ["https://management.azure.com/.default"]
286
+ if (
287
+ (not self.version_tolerant or self.azure_arm)
288
+ and parameters
289
+ and parameters[-1]["clientName"] == "credential"
290
+ ):
291
+ # we need to move credential to the front in mgmt mode for backcompat reasons
292
+ yaml_data["parameters"] = [parameters[-1]] + parameters[:-1]
293
+ prop_name = yaml_data["name"]
294
+ if prop_name.endswith("Client"):
295
+ prop_name = prop_name[: len(prop_name) - len("Client")]
296
+ yaml_data["builderPadName"] = to_snake_case(prop_name)
297
+ for og in yaml_data.get("operationGroups", []):
298
+ for o in og["operations"]:
299
+ property_if_match = None
300
+ property_if_none_match = None
301
+ for p in o["parameters"]:
302
+ wire_name_lower = get_wire_name_lower(p)
303
+ if p["location"] == "header" and wire_name_lower == "client-request-id":
304
+ yaml_data["requestIdHeaderName"] = wire_name_lower
305
+ if self.version_tolerant and p["location"] == "header":
306
+ if wire_name_lower == "if-match":
307
+ property_if_match = p
308
+ elif wire_name_lower == "if-none-match":
309
+ property_if_none_match = p
310
+ # pylint: disable=line-too-long
311
+ # some service(e.g. https://github.com/Azure/azure-rest-api-specs/blob/main/specification/cosmos-db/data-plane/Microsoft.Tables/preview/2019-02-02/table.json)
312
+ # only has one, so we need to add "if-none-match" or "if-match" if it's missing
313
+ if not property_if_match and property_if_none_match:
314
+ property_if_match = property_if_none_match.copy()
315
+ property_if_match["wireName"] = "if-match"
316
+ if not property_if_none_match and property_if_match:
317
+ property_if_none_match = property_if_match.copy()
318
+ property_if_none_match["wireName"] = "if-none-match"
319
+
320
+ if property_if_match and property_if_none_match:
321
+ # arrange if-match and if-none-match to the end of parameters
322
+ o["parameters"] = [
323
+ item
324
+ for item in o["parameters"]
325
+ if get_wire_name_lower(item) not in ("if-match", "if-none-match")
326
+ ] + [property_if_match, property_if_none_match]
327
+
328
+ o["hasEtag"] = True
329
+ yaml_data["hasEtag"] = True
330
+
331
+ def get_operation_updater(self, yaml_data: Dict[str, Any]) -> Callable[[Dict[str, Any], Dict[str, Any]], None]:
332
+ if yaml_data["discriminator"] == "lropaging":
333
+ return self.update_lro_paging_operation
334
+ if yaml_data["discriminator"] == "lro":
335
+ return self.update_lro_operation
336
+ if yaml_data["discriminator"] == "paging":
337
+ return self.update_paging_operation
338
+ return self.update_operation
339
+
340
+ def update_parameter(self, yaml_data: Dict[str, Any]) -> None:
341
+ yaml_data["description"] = update_description(yaml_data.get("description", ""))
342
+ if not (yaml_data["location"] == "header" and yaml_data["clientName"] in ("content_type", "accept")):
343
+ yaml_data["clientName"] = self.pad_reserved_words(yaml_data["clientName"].lower(), PadType.PARAMETER)
344
+ if yaml_data.get("propertyToParameterName"):
345
+ # need to create a new one with padded keys and values
346
+ yaml_data["propertyToParameterName"] = {
347
+ self.pad_reserved_words(prop, PadType.PROPERTY): self.pad_reserved_words(
348
+ param_name, PadType.PARAMETER
349
+ ).lower()
350
+ for prop, param_name in yaml_data["propertyToParameterName"].items()
351
+ }
352
+ wire_name_lower = (yaml_data.get("wireName") or "").lower()
353
+ if yaml_data["location"] == "header" and (
354
+ wire_name_lower in HEADERS_HIDE_IN_METHOD or yaml_data.get("clientDefaultValue") == "multipart/form-data"
355
+ ):
356
+ yaml_data["hideInMethod"] = True
357
+ if self.version_tolerant and yaml_data["location"] == "header" and wire_name_lower in HEADERS_CONVERT_IN_METHOD:
358
+ headers_convert(yaml_data, HEADERS_CONVERT_IN_METHOD[wire_name_lower])
359
+ if wire_name_lower in ["$host", "content-type", "accept"] and yaml_data["type"]["type"] == "constant":
360
+ yaml_data["clientDefaultValue"] = yaml_data["type"]["value"]
361
+
362
+ def update_operation(
363
+ self,
364
+ code_model: Dict[str, Any],
365
+ yaml_data: Dict[str, Any],
366
+ *,
367
+ is_overload: bool = False,
368
+ ) -> None:
369
+ yaml_data["groupName"] = self.pad_reserved_words(yaml_data["groupName"], PadType.OPERATION_GROUP)
370
+ yaml_data["groupName"] = to_snake_case(yaml_data["groupName"])
371
+ yaml_data["name"] = yaml_data["name"].lower()
372
+ if yaml_data.get("isLroInitialOperation") is True:
373
+ yaml_data["name"] = (
374
+ "_" + self.pad_reserved_words(extract_original_name(yaml_data["name"]), PadType.METHOD) + "_initial"
375
+ )
376
+ else:
377
+ yaml_data["name"] = self.pad_reserved_words(yaml_data["name"], PadType.METHOD)
378
+ yaml_data["description"] = update_description(yaml_data["description"], yaml_data["name"])
379
+ yaml_data["summary"] = update_description(yaml_data.get("summary", ""))
380
+ body_parameter = yaml_data.get("bodyParameter")
381
+ for parameter in yaml_data["parameters"]:
382
+ self.update_parameter(parameter)
383
+ if yaml_data.get("bodyParameter"):
384
+ self.update_parameter(yaml_data["bodyParameter"])
385
+ for entry in yaml_data["bodyParameter"].get("entries", []):
386
+ self.update_parameter(entry)
387
+ for overload in yaml_data.get("overloads", []):
388
+ self.update_operation(code_model, overload, is_overload=True)
389
+ for response in yaml_data.get("responses", []):
390
+ response["discriminator"] = "operation"
391
+ if body_parameter and not is_overload:
392
+ # if we have a JSON body, we add a binary overload
393
+ self.add_body_param_type(code_model, body_parameter)
394
+ add_overloads_for_body_param(yaml_data)
395
+
396
+ def _update_lro_operation_helper(self, yaml_data: Dict[str, Any]) -> None:
397
+ for response in yaml_data.get("responses", []):
398
+ response["discriminator"] = "lro"
399
+ response["pollerSync"] = response.get("pollerSync") or "azure.core.polling.LROPoller"
400
+ response["pollerAsync"] = response.get("pollerAsync") or "azure.core.polling.AsyncLROPoller"
401
+ if not response.get("pollingMethodSync"):
402
+ response["pollingMethodSync"] = (
403
+ "azure.mgmt.core.polling.arm_polling.ARMPolling"
404
+ if self.azure_arm
405
+ else "azure.core.polling.base_polling.LROBasePolling"
406
+ )
407
+ if not response.get("pollingMethodAsync"):
408
+ response["pollingMethodAsync"] = (
409
+ "azure.mgmt.core.polling.async_arm_polling.AsyncARMPolling"
410
+ if self.azure_arm
411
+ else "azure.core.polling.async_base_polling.AsyncLROBasePolling"
412
+ )
413
+
414
+ def update_lro_paging_operation(
415
+ self,
416
+ code_model: Dict[str, Any],
417
+ yaml_data: Dict[str, Any],
418
+ is_overload: bool = False,
419
+ item_type: Optional[Dict[str, Any]] = None,
420
+ ) -> None:
421
+ self.update_lro_operation(code_model, yaml_data, is_overload=is_overload)
422
+ self.update_paging_operation(code_model, yaml_data, is_overload=is_overload, item_type=item_type)
423
+ yaml_data["discriminator"] = "lropaging"
424
+ for response in yaml_data.get("responses", []):
425
+ response["discriminator"] = "lropaging"
426
+ for overload in yaml_data.get("overloads", []):
427
+ self.update_lro_paging_operation(
428
+ code_model,
429
+ overload,
430
+ is_overload=True,
431
+ item_type=yaml_data["responses"][0]["itemType"],
432
+ )
433
+
434
+ def update_lro_operation(
435
+ self,
436
+ code_model: Dict[str, Any],
437
+ yaml_data: Dict[str, Any],
438
+ is_overload: bool = False,
439
+ ) -> None:
440
+ def convert_initial_operation_response_type(data: Dict[str, Any]) -> None:
441
+ for response in data.get("responses", []):
442
+ response["type"] = KNOWN_TYPES["binary"]
443
+
444
+ self.update_operation(code_model, yaml_data, is_overload=is_overload)
445
+ self.update_operation(code_model, yaml_data["initialOperation"], is_overload=is_overload)
446
+ convert_initial_operation_response_type(yaml_data["initialOperation"])
447
+ self._update_lro_operation_helper(yaml_data)
448
+ for overload in yaml_data.get("overloads", []):
449
+ self._update_lro_operation_helper(overload)
450
+ self.update_operation(code_model, overload["initialOperation"], is_overload=True)
451
+ convert_initial_operation_response_type(overload["initialOperation"])
452
+
453
+ def update_paging_operation(
454
+ self,
455
+ code_model: Dict[str, Any],
456
+ yaml_data: Dict[str, Any],
457
+ is_overload: bool = False,
458
+ item_type: Optional[Dict[str, Any]] = None,
459
+ ) -> None:
460
+ self.update_operation(code_model, yaml_data, is_overload=is_overload)
461
+ item_type = item_type or yaml_data["itemType"]["elementType"]
462
+ if yaml_data.get("nextOperation"):
463
+ yaml_data["nextOperation"]["groupName"] = self.pad_reserved_words(
464
+ yaml_data["nextOperation"]["groupName"], PadType.OPERATION_GROUP
465
+ )
466
+ yaml_data["nextOperation"]["groupName"] = to_snake_case(yaml_data["nextOperation"]["groupName"])
467
+ for response in yaml_data["nextOperation"].get("responses", []):
468
+ update_paging_response(response)
469
+ response["itemType"] = item_type
470
+ for response in yaml_data.get("responses", []):
471
+ update_paging_response(response)
472
+ response["itemType"] = item_type
473
+ for overload in yaml_data.get("overloads", []):
474
+ self.update_paging_operation(code_model, overload, is_overload=True, item_type=item_type)
475
+
476
+ def update_operation_groups(self, code_model: Dict[str, Any], client: Dict[str, Any]) -> None:
477
+ operation_groups_yaml_data = client.get("operationGroups", [])
478
+ for operation_group in operation_groups_yaml_data:
479
+ operation_group["identifyName"] = self.pad_reserved_words(
480
+ operation_group.get("name", operation_group["propertyName"]),
481
+ PadType.OPERATION_GROUP,
482
+ )
483
+ operation_group["identifyName"] = to_snake_case(operation_group["identifyName"])
484
+ operation_group["propertyName"] = self.pad_reserved_words(
485
+ operation_group["propertyName"], PadType.OPERATION_GROUP
486
+ )
487
+ operation_group["propertyName"] = to_snake_case(operation_group["propertyName"])
488
+ operation_group["className"] = update_operation_group_class_name(
489
+ client["name"], operation_group["className"]
490
+ )
491
+ for operation in operation_group["operations"]:
492
+ self.get_operation_updater(operation)(code_model, operation)
493
+
494
+ if operation_group.get("operationGroups"):
495
+ self.update_operation_groups(code_model, operation_group)
496
+
497
+ def update_yaml(self, yaml_data: Dict[str, Any]) -> None:
498
+ """Convert in place the YAML str."""
499
+ self.update_types(yaml_data["types"])
500
+ yaml_data["types"] += KNOWN_TYPES.values()
501
+ for client in yaml_data["clients"]:
502
+ self.update_client(client)
503
+ self.update_operation_groups(yaml_data, client)
504
+ for clients in yaml_data["subnamespaceToClients"].values():
505
+ for client in clients:
506
+ self.update_client(client)
507
+ self.update_operation_groups(yaml_data, client)
508
+ if yaml_data.get("namespace"):
509
+ yaml_data["namespace"] = pad_builtin_namespaces(yaml_data["namespace"])
510
+
511
+
512
+ if __name__ == "__main__":
513
+ # CADL pipeline will call this
514
+ args, unknown_args = parse_args()
515
+ PreProcessPlugin(output_folder=args.output_folder, cadl_file=args.cadl_file, **unknown_args).process()
@@ -0,0 +1,27 @@
1
+ # -------------------------------------------------------------------------
2
+ # Copyright (c) Microsoft Corporation. All rights reserved.
3
+ # Licensed under the MIT License. See License.txt in the project root for
4
+ # license information.
5
+ # --------------------------------------------------------------------------
6
+ import re
7
+ from typing import Any, Dict
8
+ from .python_mappings import (
9
+ REDEFINED_BUILTINS,
10
+ BUILTIN_PACKAGES,
11
+ )
12
+
13
+
14
+ def add_redefined_builtin_info(name: str, yaml_data: Dict[str, Any]) -> None:
15
+ if name in REDEFINED_BUILTINS:
16
+ yaml_data["pylintDisable"] = "redefined-builtin"
17
+
18
+
19
+ def pad_builtin_namespaces(namespace: str) -> str:
20
+ items = namespace.split(".")
21
+ if items[0] in BUILTIN_PACKAGES:
22
+ items[0] = items[0] + "_"
23
+ return ".".join(items)
24
+
25
+
26
+ def pad_special_chars(name: str) -> str:
27
+ return re.sub(r"[^A-z0-9_]", "_", name)