@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.
- package/dist/emitter/emitter.d.ts.map +1 -1
- package/dist/emitter/emitter.js +85 -24
- package/dist/emitter/emitter.js.map +1 -1
- package/dist/emitter/lib.d.ts +1 -0
- package/dist/emitter/lib.d.ts.map +1 -1
- package/dist/emitter/lib.js +1 -0
- package/dist/emitter/lib.js.map +1 -1
- package/dist/emitter/run-python3.d.ts +2 -0
- package/dist/emitter/run-python3.d.ts.map +1 -0
- package/dist/emitter/run-python3.js +19 -0
- package/dist/emitter/run-python3.js.map +1 -0
- package/dist/emitter/system-requirements.d.ts +17 -0
- package/dist/emitter/system-requirements.d.ts.map +1 -0
- package/dist/emitter/system-requirements.js +167 -0
- package/dist/emitter/system-requirements.js.map +1 -0
- package/emitter/src/emitter.ts +88 -23
- package/emitter/src/lib.ts +2 -0
- package/emitter/src/run-python3.ts +20 -0
- package/emitter/src/system-requirements.ts +261 -0
- package/emitter/temp/tsconfig.tsbuildinfo +1 -1
- package/eng/scripts/ci/regenerate.ts +16 -4
- package/eng/scripts/setup/__pycache__/venvtools.cpython-38.pyc +0 -0
- package/eng/scripts/setup/build.ts +16 -0
- package/eng/scripts/setup/build_pygen_wheel.py +40 -0
- package/eng/scripts/setup/install.py +9 -3
- package/eng/scripts/setup/install.ts +32 -0
- package/eng/scripts/setup/prepare.py +3 -1
- package/eng/scripts/setup/prepare.ts +11 -0
- package/eng/scripts/setup/run-python3.ts +1 -6
- package/generator/build/lib/pygen/__init__.py +107 -0
- package/generator/build/lib/pygen/_version.py +7 -0
- package/generator/build/lib/pygen/black.py +71 -0
- package/generator/build/lib/pygen/codegen/__init__.py +357 -0
- package/generator/build/lib/pygen/codegen/_utils.py +17 -0
- package/generator/build/lib/pygen/codegen/models/__init__.py +204 -0
- package/generator/build/lib/pygen/codegen/models/base.py +186 -0
- package/generator/build/lib/pygen/codegen/models/base_builder.py +118 -0
- package/generator/build/lib/pygen/codegen/models/client.py +435 -0
- package/generator/build/lib/pygen/codegen/models/code_model.py +237 -0
- package/generator/build/lib/pygen/codegen/models/combined_type.py +149 -0
- package/generator/build/lib/pygen/codegen/models/constant_type.py +129 -0
- package/generator/build/lib/pygen/codegen/models/credential_types.py +214 -0
- package/generator/build/lib/pygen/codegen/models/dictionary_type.py +127 -0
- package/generator/build/lib/pygen/codegen/models/enum_type.py +238 -0
- package/generator/build/lib/pygen/codegen/models/imports.py +291 -0
- package/generator/build/lib/pygen/codegen/models/list_type.py +143 -0
- package/generator/build/lib/pygen/codegen/models/lro_operation.py +142 -0
- package/generator/build/lib/pygen/codegen/models/lro_paging_operation.py +32 -0
- package/generator/build/lib/pygen/codegen/models/model_type.py +357 -0
- package/generator/build/lib/pygen/codegen/models/operation.py +509 -0
- package/generator/build/lib/pygen/codegen/models/operation_group.py +184 -0
- package/generator/build/lib/pygen/codegen/models/paging_operation.py +155 -0
- package/generator/build/lib/pygen/codegen/models/parameter.py +412 -0
- package/generator/build/lib/pygen/codegen/models/parameter_list.py +387 -0
- package/generator/build/lib/pygen/codegen/models/primitive_types.py +659 -0
- package/generator/build/lib/pygen/codegen/models/property.py +170 -0
- package/generator/build/lib/pygen/codegen/models/request_builder.py +189 -0
- package/generator/build/lib/pygen/codegen/models/request_builder_parameter.py +115 -0
- package/generator/build/lib/pygen/codegen/models/response.py +348 -0
- package/generator/build/lib/pygen/codegen/models/utils.py +21 -0
- package/generator/build/lib/pygen/codegen/serializers/__init__.py +574 -0
- package/generator/build/lib/pygen/codegen/serializers/base_serializer.py +21 -0
- package/generator/build/lib/pygen/codegen/serializers/builder_serializer.py +1533 -0
- package/generator/build/lib/pygen/codegen/serializers/client_serializer.py +294 -0
- package/generator/build/lib/pygen/codegen/serializers/enum_serializer.py +15 -0
- package/generator/build/lib/pygen/codegen/serializers/general_serializer.py +213 -0
- package/generator/build/lib/pygen/codegen/serializers/import_serializer.py +126 -0
- package/generator/build/lib/pygen/codegen/serializers/metadata_serializer.py +198 -0
- package/generator/build/lib/pygen/codegen/serializers/model_init_serializer.py +33 -0
- package/generator/build/lib/pygen/codegen/serializers/model_serializer.py +335 -0
- package/generator/build/lib/pygen/codegen/serializers/operation_groups_serializer.py +89 -0
- package/generator/build/lib/pygen/codegen/serializers/operations_init_serializer.py +44 -0
- package/generator/build/lib/pygen/codegen/serializers/parameter_serializer.py +221 -0
- package/generator/build/lib/pygen/codegen/serializers/patch_serializer.py +19 -0
- package/generator/build/lib/pygen/codegen/serializers/request_builders_serializer.py +52 -0
- package/generator/build/lib/pygen/codegen/serializers/sample_serializer.py +168 -0
- package/generator/build/lib/pygen/codegen/serializers/test_serializer.py +292 -0
- package/generator/build/lib/pygen/codegen/serializers/types_serializer.py +31 -0
- package/generator/build/lib/pygen/codegen/serializers/utils.py +68 -0
- package/generator/build/lib/pygen/codegen/templates/client.py.jinja2 +37 -0
- package/generator/build/lib/pygen/codegen/templates/client_container.py.jinja2 +12 -0
- package/generator/build/lib/pygen/codegen/templates/config.py.jinja2 +73 -0
- package/generator/build/lib/pygen/codegen/templates/config_container.py.jinja2 +16 -0
- package/generator/build/lib/pygen/codegen/templates/conftest.py.jinja2 +28 -0
- package/generator/build/lib/pygen/codegen/templates/enum.py.jinja2 +13 -0
- package/generator/build/lib/pygen/codegen/templates/enum_container.py.jinja2 +10 -0
- package/generator/build/lib/pygen/codegen/templates/init.py.jinja2 +24 -0
- package/generator/build/lib/pygen/codegen/templates/keywords.jinja2 +27 -0
- package/generator/build/lib/pygen/codegen/templates/lro_operation.py.jinja2 +16 -0
- package/generator/build/lib/pygen/codegen/templates/lro_paging_operation.py.jinja2 +18 -0
- package/generator/build/lib/pygen/codegen/templates/macros.jinja2 +12 -0
- package/generator/build/lib/pygen/codegen/templates/metadata.json.jinja2 +167 -0
- package/generator/build/lib/pygen/codegen/templates/model_base.py.jinja2 +1174 -0
- package/generator/build/lib/pygen/codegen/templates/model_container.py.jinja2 +15 -0
- package/generator/build/lib/pygen/codegen/templates/model_dpg.py.jinja2 +97 -0
- package/generator/build/lib/pygen/codegen/templates/model_init.py.jinja2 +33 -0
- package/generator/build/lib/pygen/codegen/templates/model_msrest.py.jinja2 +92 -0
- package/generator/build/lib/pygen/codegen/templates/operation.py.jinja2 +21 -0
- package/generator/build/lib/pygen/codegen/templates/operation_group.py.jinja2 +75 -0
- package/generator/build/lib/pygen/codegen/templates/operation_groups_container.py.jinja2 +19 -0
- package/generator/build/lib/pygen/codegen/templates/operation_tools.jinja2 +81 -0
- package/generator/build/lib/pygen/codegen/templates/operations_folder_init.py.jinja2 +17 -0
- package/generator/build/lib/pygen/codegen/templates/packaging_templates/CHANGELOG.md.jinja2 +6 -0
- package/generator/build/lib/pygen/codegen/templates/packaging_templates/LICENSE.jinja2 +21 -0
- package/generator/build/lib/pygen/codegen/templates/packaging_templates/MANIFEST.in.jinja2 +8 -0
- package/generator/build/lib/pygen/codegen/templates/packaging_templates/README.md.jinja2 +107 -0
- package/generator/build/lib/pygen/codegen/templates/packaging_templates/dev_requirements.txt.jinja2 +9 -0
- package/generator/build/lib/pygen/codegen/templates/packaging_templates/setup.py.jinja2 +108 -0
- package/generator/build/lib/pygen/codegen/templates/paging_operation.py.jinja2 +21 -0
- package/generator/build/lib/pygen/codegen/templates/patch.py.jinja2 +19 -0
- package/generator/build/lib/pygen/codegen/templates/pkgutil_init.py.jinja2 +1 -0
- package/generator/build/lib/pygen/codegen/templates/request_builder.py.jinja2 +28 -0
- package/generator/build/lib/pygen/codegen/templates/request_builders.py.jinja2 +10 -0
- package/generator/build/lib/pygen/codegen/templates/rest_init.py.jinja2 +12 -0
- package/generator/build/lib/pygen/codegen/templates/sample.py.jinja2 +44 -0
- package/generator/build/lib/pygen/codegen/templates/serialization.py.jinja2 +2117 -0
- package/generator/build/lib/pygen/codegen/templates/test.py.jinja2 +50 -0
- package/generator/build/lib/pygen/codegen/templates/testpreparer.py.jinja2 +26 -0
- package/generator/build/lib/pygen/codegen/templates/types.py.jinja2 +7 -0
- package/generator/build/lib/pygen/codegen/templates/validation.py.jinja2 +38 -0
- package/generator/build/lib/pygen/codegen/templates/vendor.py.jinja2 +96 -0
- package/generator/build/lib/pygen/codegen/templates/version.py.jinja2 +4 -0
- package/generator/build/lib/pygen/m2r.py +65 -0
- package/generator/build/lib/pygen/preprocess/__init__.py +515 -0
- package/generator/build/lib/pygen/preprocess/helpers.py +27 -0
- package/generator/build/lib/pygen/preprocess/python_mappings.py +226 -0
- package/generator/build/lib/pygen/utils.py +163 -0
- package/generator/component-detection-pip-report.json +134 -0
- package/generator/dev_requirements.txt +0 -1
- package/generator/dist/pygen-0.1.0-py3-none-any.whl +0 -0
- package/generator/pygen.egg-info/PKG-INFO +7 -4
- package/generator/pygen.egg-info/requires.txt +7 -4
- package/generator/requirements.txt +5 -10
- package/generator/setup.py +7 -4
- package/generator/test/azure/requirements.txt +1 -1
- package/generator/test/unbranded/requirements.txt +1 -1
- 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)
|