@typespec/http-client-python 0.33.0 → 0.34.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/types.d.ts.map +1 -1
- package/dist/emitter/types.js +2 -0
- package/dist/emitter/types.js.map +1 -1
- package/emitter/src/types.ts +2 -0
- package/emitter/temp/tsconfig.tsbuildinfo +1 -1
- package/eng/scripts/ci/regenerate-common.ts +40 -15
- package/eng/scripts/setup/__pycache__/package_manager.cpython-311.pyc +0 -0
- package/eng/scripts/setup/__pycache__/venvtools.cpython-311.pyc +0 -0
- package/generator/build/lib/pygen/__init__.py +3 -3
- package/generator/build/lib/pygen/codegen/models/__init__.py +4 -2
- package/generator/build/lib/pygen/codegen/models/code_model.py +27 -5
- package/generator/build/lib/pygen/codegen/models/combined_type.py +3 -3
- package/generator/build/lib/pygen/codegen/models/enum_type.py +75 -25
- package/generator/build/lib/pygen/codegen/models/list_type.py +10 -4
- package/generator/build/lib/pygen/codegen/models/model_type.py +145 -4
- package/generator/build/lib/pygen/codegen/models/operation.py +1 -0
- package/generator/build/lib/pygen/codegen/models/paging_operation.py +5 -1
- package/generator/build/lib/pygen/codegen/models/parameter.py +2 -2
- package/generator/build/lib/pygen/codegen/models/primitive_types.py +30 -6
- package/generator/build/lib/pygen/codegen/models/property.py +21 -8
- package/generator/build/lib/pygen/codegen/models/response.py +16 -3
- package/generator/build/lib/pygen/codegen/models/utils.py +3 -6
- package/generator/build/lib/pygen/codegen/serializers/__init__.py +46 -11
- package/generator/build/lib/pygen/codegen/serializers/builder_serializer.py +48 -15
- package/generator/build/lib/pygen/codegen/serializers/model_init_serializer.py +1 -1
- package/generator/build/lib/pygen/codegen/serializers/model_serializer.py +127 -3
- package/generator/build/lib/pygen/codegen/serializers/types_serializer.py +263 -12
- package/generator/build/lib/pygen/codegen/serializers/unions_serializer.py +44 -0
- package/generator/build/lib/pygen/codegen/templates/model_container.py.jinja2 +1 -1
- package/generator/build/lib/pygen/codegen/templates/types.py.jinja2 +51 -2
- package/generator/build/lib/pygen/codegen/templates/unions.py.jinja2 +9 -0
- package/generator/build/lib/pygen/preprocess/__init__.py +137 -162
- package/generator/build/lib/pygen/utils.py +6 -24
- package/generator/dist/pygen-0.1.0-py3-none-any.whl +0 -0
- package/generator/pygen/__init__.py +3 -3
- package/generator/pygen/codegen/models/__init__.py +4 -2
- package/generator/pygen/codegen/models/code_model.py +27 -5
- package/generator/pygen/codegen/models/combined_type.py +3 -3
- package/generator/pygen/codegen/models/enum_type.py +75 -25
- package/generator/pygen/codegen/models/list_type.py +10 -4
- package/generator/pygen/codegen/models/model_type.py +145 -4
- package/generator/pygen/codegen/models/operation.py +1 -0
- package/generator/pygen/codegen/models/paging_operation.py +5 -1
- package/generator/pygen/codegen/models/parameter.py +2 -2
- package/generator/pygen/codegen/models/primitive_types.py +30 -6
- package/generator/pygen/codegen/models/property.py +21 -8
- package/generator/pygen/codegen/models/response.py +16 -3
- package/generator/pygen/codegen/models/utils.py +3 -6
- package/generator/pygen/codegen/serializers/__init__.py +46 -11
- package/generator/pygen/codegen/serializers/builder_serializer.py +48 -15
- package/generator/pygen/codegen/serializers/model_init_serializer.py +1 -1
- package/generator/pygen/codegen/serializers/model_serializer.py +127 -3
- package/generator/pygen/codegen/serializers/types_serializer.py +263 -12
- package/generator/pygen/codegen/serializers/unions_serializer.py +44 -0
- package/generator/pygen/codegen/templates/model_container.py.jinja2 +1 -1
- package/generator/pygen/codegen/templates/types.py.jinja2 +51 -2
- package/generator/pygen/codegen/templates/unions.py.jinja2 +9 -0
- package/generator/pygen/preprocess/__init__.py +137 -162
- package/generator/pygen/utils.py +6 -24
- package/generator/pygen.egg-info/SOURCES.txt +2 -0
- package/package.json +5 -5
|
@@ -36,18 +36,14 @@ def update_overload_section(
|
|
|
36
36
|
if overload_s.get("type"):
|
|
37
37
|
overload_s["type"] = original_s["type"]
|
|
38
38
|
if overload_s.get("headers"):
|
|
39
|
-
for overload_h, original_h in zip(
|
|
40
|
-
overload_s["headers"], original_s["headers"]
|
|
41
|
-
):
|
|
39
|
+
for overload_h, original_h in zip(overload_s["headers"], original_s["headers"]):
|
|
42
40
|
if overload_h.get("type"):
|
|
43
41
|
overload_h["type"] = original_h["type"]
|
|
44
42
|
except KeyError as exc:
|
|
45
43
|
raise ValueError(overload["name"]) from exc
|
|
46
44
|
|
|
47
45
|
|
|
48
|
-
def add_overload(
|
|
49
|
-
yaml_data: dict[str, Any], body_type: dict[str, Any], for_flatten_params=False
|
|
50
|
-
):
|
|
46
|
+
def add_overload(yaml_data: dict[str, Any], body_type: dict[str, Any], for_flatten_params=False):
|
|
51
47
|
overload = copy.deepcopy(yaml_data)
|
|
52
48
|
overload["isOverload"] = True
|
|
53
49
|
overload["bodyParameter"]["type"] = body_type
|
|
@@ -59,9 +55,7 @@ def add_overload(
|
|
|
59
55
|
if for_flatten_params:
|
|
60
56
|
overload["bodyParameter"]["flattened"] = True
|
|
61
57
|
else:
|
|
62
|
-
overload["parameters"] = [
|
|
63
|
-
p for p in overload["parameters"] if not p.get("inFlattenedBody")
|
|
64
|
-
]
|
|
58
|
+
overload["parameters"] = [p for p in overload["parameters"] if not p.get("inFlattenedBody")]
|
|
65
59
|
# for yaml sync, we need to make sure all of the responses, parameters, and exceptions' types have the same yaml id
|
|
66
60
|
for overload_p, original_p in zip(overload["parameters"], yaml_data["parameters"]):
|
|
67
61
|
overload_p["type"] = original_p["type"]
|
|
@@ -69,9 +63,7 @@ def add_overload(
|
|
|
69
63
|
update_overload_section(overload, yaml_data, "exceptions")
|
|
70
64
|
|
|
71
65
|
# update content type to be an overloads content type
|
|
72
|
-
content_type_param = next(
|
|
73
|
-
p for p in overload["parameters"] if p["wireName"].lower() == "content-type"
|
|
74
|
-
)
|
|
66
|
+
content_type_param = next(p for p in overload["parameters"] if p["wireName"].lower() == "content-type")
|
|
75
67
|
content_type_param["inOverload"] = True
|
|
76
68
|
content_type_param["inDocstring"] = True
|
|
77
69
|
body_type_description = get_body_type_for_description(overload["bodyParameter"])
|
|
@@ -94,25 +86,18 @@ def add_overloads_for_body_param(yaml_data: dict[str, Any]) -> None:
|
|
|
94
86
|
body_parameter = yaml_data["bodyParameter"]
|
|
95
87
|
if not (
|
|
96
88
|
body_parameter["type"]["type"] == "combined"
|
|
97
|
-
and len(yaml_data["bodyParameter"]["type"]["types"])
|
|
98
|
-
> len(yaml_data["overloads"])
|
|
89
|
+
and len(yaml_data["bodyParameter"]["type"]["types"]) > len(yaml_data["overloads"])
|
|
99
90
|
):
|
|
100
91
|
return
|
|
101
92
|
for body_type in body_parameter["type"]["types"]:
|
|
102
|
-
if any(
|
|
103
|
-
o
|
|
104
|
-
for o in yaml_data["overloads"]
|
|
105
|
-
if id(o["bodyParameter"]["type"]) == id(body_type)
|
|
106
|
-
):
|
|
93
|
+
if any(o for o in yaml_data["overloads"] if id(o["bodyParameter"]["type"]) == id(body_type)):
|
|
107
94
|
continue
|
|
108
95
|
if body_type.get("type") == "model" and body_type.get("base") == "json":
|
|
109
|
-
yaml_data["overloads"].append(
|
|
110
|
-
|
|
111
|
-
|
|
96
|
+
yaml_data["overloads"].append(add_overload(yaml_data, body_type, for_flatten_params=True))
|
|
97
|
+
# Skip single-body JSON overload; the TypedDict overload replaces it
|
|
98
|
+
continue
|
|
112
99
|
yaml_data["overloads"].append(add_overload(yaml_data, body_type))
|
|
113
|
-
content_type_param = next(
|
|
114
|
-
p for p in yaml_data["parameters"] if p["wireName"].lower() == "content-type"
|
|
115
|
-
)
|
|
100
|
+
content_type_param = next(p for p in yaml_data["parameters"] if p["wireName"].lower() == "content-type")
|
|
116
101
|
content_type_param["inOverload"] = False
|
|
117
102
|
content_type_param["inOverridden"] = True
|
|
118
103
|
content_type_param["inDocstring"] = True
|
|
@@ -122,19 +107,13 @@ def add_overloads_for_body_param(yaml_data: dict[str, Any]) -> None:
|
|
|
122
107
|
content_type_param["optional"] = True
|
|
123
108
|
|
|
124
109
|
|
|
125
|
-
def update_description(
|
|
126
|
-
description: Optional[str], default_description: str = ""
|
|
127
|
-
) -> str:
|
|
110
|
+
def update_description(description: Optional[str], default_description: str = "") -> str:
|
|
128
111
|
if not description:
|
|
129
112
|
description = default_description
|
|
130
113
|
description.rstrip(" ")
|
|
131
114
|
# Don't append a trailing period when the description ends with a code block: the
|
|
132
115
|
# period would land inside the rendered literal block (e.g. "]." ) and break Sphinx.
|
|
133
|
-
if (
|
|
134
|
-
description
|
|
135
|
-
and description[-1] != "."
|
|
136
|
-
and not description_ends_with_code_block(description)
|
|
137
|
-
):
|
|
116
|
+
if description and description[-1] != "." and not description_ends_with_code_block(description):
|
|
138
117
|
description += "."
|
|
139
118
|
return description
|
|
140
119
|
|
|
@@ -197,9 +176,7 @@ def _get_etag_role(parameter: dict[str, Any]) -> Optional[str]:
|
|
|
197
176
|
return parameter.get("etagRole")
|
|
198
177
|
|
|
199
178
|
|
|
200
|
-
def _pick_etag_slot(
|
|
201
|
-
candidates: list[dict[str, Any]], standard_wire_name: str
|
|
202
|
-
) -> Optional[dict[str, Any]]:
|
|
179
|
+
def _pick_etag_slot(candidates: list[dict[str, Any]], standard_wire_name: str) -> Optional[dict[str, Any]]:
|
|
203
180
|
"""Choose which etag-typed header should be promoted to the etag/match_condition slot.
|
|
204
181
|
|
|
205
182
|
When more than one etag-typed header is present in an operation, prefer the
|
|
@@ -227,25 +204,16 @@ def _resolve_etag_pair(
|
|
|
227
204
|
Returns (property_if_match, property_if_none_match) — both None when
|
|
228
205
|
there are no etag candidates.
|
|
229
206
|
"""
|
|
230
|
-
property_if_match = _pick_etag_slot(
|
|
231
|
-
|
|
232
|
-
)
|
|
233
|
-
property_if_none_match = _pick_etag_slot(
|
|
234
|
-
if_none_match_candidates, STANDARD_IF_NONE_MATCH_WIRE_NAME
|
|
235
|
-
)
|
|
207
|
+
property_if_match = _pick_etag_slot(if_match_candidates, STANDARD_IF_MATCH_WIRE_NAME)
|
|
208
|
+
property_if_none_match = _pick_etag_slot(if_none_match_candidates, STANDARD_IF_NONE_MATCH_WIRE_NAME)
|
|
236
209
|
|
|
237
210
|
# Ensure the promoted pair come from the same family. When one slot is
|
|
238
211
|
# standard and the other custom (cross-family), replace the custom slot
|
|
239
212
|
# with a synthetic standard partner. Also synthesize the missing partner
|
|
240
213
|
# when only one side is present.
|
|
241
214
|
if property_if_match and property_if_none_match:
|
|
242
|
-
match_is_std = (
|
|
243
|
-
|
|
244
|
-
)
|
|
245
|
-
none_match_is_std = (
|
|
246
|
-
get_wire_name_lower(property_if_none_match)
|
|
247
|
-
== STANDARD_IF_NONE_MATCH_WIRE_NAME
|
|
248
|
-
)
|
|
215
|
+
match_is_std = get_wire_name_lower(property_if_match) == STANDARD_IF_MATCH_WIRE_NAME
|
|
216
|
+
none_match_is_std = get_wire_name_lower(property_if_none_match) == STANDARD_IF_NONE_MATCH_WIRE_NAME
|
|
249
217
|
if match_is_std and not none_match_is_std:
|
|
250
218
|
property_if_none_match = property_if_match.copy()
|
|
251
219
|
property_if_none_match["wireName"] = STANDARD_IF_NONE_MATCH_WIRE_NAME
|
|
@@ -293,15 +261,11 @@ def _process_operation_etag_headers(
|
|
|
293
261
|
elif role == "ifNoneMatch":
|
|
294
262
|
if_none_match_candidates.append(p)
|
|
295
263
|
|
|
296
|
-
property_if_match, property_if_none_match = _resolve_etag_pair(
|
|
297
|
-
if_match_candidates, if_none_match_candidates
|
|
298
|
-
)
|
|
264
|
+
property_if_match, property_if_none_match = _resolve_etag_pair(if_match_candidates, if_none_match_candidates)
|
|
299
265
|
|
|
300
266
|
if property_if_match and property_if_none_match:
|
|
301
267
|
etag_params = {id(property_if_match), id(property_if_none_match)}
|
|
302
|
-
operation["parameters"] = [
|
|
303
|
-
item for item in operation["parameters"] if id(item) not in etag_params
|
|
304
|
-
] + [
|
|
268
|
+
operation["parameters"] = [item for item in operation["parameters"] if id(item) not in etag_params] + [
|
|
305
269
|
property_if_match,
|
|
306
270
|
property_if_none_match,
|
|
307
271
|
]
|
|
@@ -320,9 +284,7 @@ def has_json_content_type(yaml_data: dict[str, Any]) -> bool:
|
|
|
320
284
|
|
|
321
285
|
|
|
322
286
|
def has_multi_part_content_type(yaml_data: dict[str, Any]) -> bool:
|
|
323
|
-
return any(
|
|
324
|
-
ct for ct in yaml_data.get("contentTypes", []) if ct == "multipart/form-data"
|
|
325
|
-
)
|
|
287
|
+
return any(ct for ct in yaml_data.get("contentTypes", []) if ct == "multipart/form-data")
|
|
326
288
|
|
|
327
289
|
|
|
328
290
|
class PreProcessPlugin(YamlUpdatePlugin):
|
|
@@ -344,6 +306,44 @@ class PreProcessPlugin(YamlUpdatePlugin):
|
|
|
344
306
|
def is_tsp(self) -> bool:
|
|
345
307
|
return self.options.get("tsp_file", False)
|
|
346
308
|
|
|
309
|
+
@staticmethod
|
|
310
|
+
def _find_existing_typeddict(code_model: dict[str, Any], cross_lang_id: Optional[str]) -> Optional[dict[str, Any]]:
|
|
311
|
+
"""Find an existing typeddict copy with the given crossLanguageDefinitionId."""
|
|
312
|
+
if not cross_lang_id:
|
|
313
|
+
return None
|
|
314
|
+
return next(
|
|
315
|
+
(
|
|
316
|
+
t
|
|
317
|
+
for t in code_model["types"]
|
|
318
|
+
if t.get("type") == "model"
|
|
319
|
+
and t.get("base") == "typeddict"
|
|
320
|
+
and t.get("crossLanguageDefinitionId") == cross_lang_id
|
|
321
|
+
),
|
|
322
|
+
None,
|
|
323
|
+
)
|
|
324
|
+
|
|
325
|
+
@staticmethod
|
|
326
|
+
def _insert_typeddict_overload(
|
|
327
|
+
code_model: dict[str, Any],
|
|
328
|
+
body_parameter: dict[str, Any],
|
|
329
|
+
source: dict[str, Any],
|
|
330
|
+
origin_type: str,
|
|
331
|
+
existing_td: Optional[dict[str, Any]],
|
|
332
|
+
) -> None:
|
|
333
|
+
"""Insert a typeddict type into the body parameter's combined types."""
|
|
334
|
+
if origin_type == "model":
|
|
335
|
+
td_type = existing_td or {**source, "base": "typeddict"}
|
|
336
|
+
body_parameter["type"]["types"].insert(1, td_type)
|
|
337
|
+
if not existing_td:
|
|
338
|
+
code_model["types"].append(td_type)
|
|
339
|
+
else:
|
|
340
|
+
td_list_or_dict = copy.deepcopy(body_parameter["type"]["types"][0])
|
|
341
|
+
td_elem = existing_td or {**source, "base": "typeddict"}
|
|
342
|
+
td_list_or_dict["elementType"] = td_elem
|
|
343
|
+
body_parameter["type"]["types"].insert(1, td_list_or_dict)
|
|
344
|
+
if not existing_td:
|
|
345
|
+
code_model["types"].append(td_elem)
|
|
346
|
+
|
|
347
347
|
def add_body_param_type(
|
|
348
348
|
self,
|
|
349
349
|
code_model: dict[str, Any],
|
|
@@ -353,54 +353,82 @@ class PreProcessPlugin(YamlUpdatePlugin):
|
|
|
353
353
|
if ( # pylint: disable=too-many-boolean-expressions
|
|
354
354
|
body_parameter
|
|
355
355
|
and body_parameter["type"]["type"] in ("model", "dict", "list")
|
|
356
|
-
and (
|
|
357
|
-
has_json_content_type(body_parameter)
|
|
358
|
-
or (self.is_tsp and has_multi_part_content_type(body_parameter))
|
|
359
|
-
)
|
|
356
|
+
and (has_json_content_type(body_parameter) or (self.is_tsp and has_multi_part_content_type(body_parameter)))
|
|
360
357
|
and not body_parameter["type"].get("xmlMetadata")
|
|
361
358
|
and not any(t for t in ["flattened", "groupedBy"] if body_parameter.get(t))
|
|
362
359
|
):
|
|
363
360
|
origin_type = body_parameter["type"]["type"]
|
|
364
361
|
model_type = (
|
|
365
|
-
body_parameter["type"]
|
|
366
|
-
if origin_type == "model"
|
|
367
|
-
else body_parameter["type"].get("elementType", {})
|
|
362
|
+
body_parameter["type"] if origin_type == "model" else body_parameter["type"].get("elementType", {})
|
|
368
363
|
)
|
|
369
364
|
is_dpg_model = model_type.get("base") == "dpg"
|
|
365
|
+
is_json_model = model_type.get("base") == "json"
|
|
366
|
+
is_typeddict_only = self.options["models-mode"] == "typeddict"
|
|
367
|
+
|
|
370
368
|
body_parameter["type"] = {
|
|
371
369
|
"type": "combined",
|
|
372
370
|
"types": [body_parameter["type"]],
|
|
373
371
|
}
|
|
374
|
-
# don't add binary overload for multipart content type
|
|
375
|
-
if not (self.is_tsp and has_multi_part_content_type(body_parameter)):
|
|
372
|
+
# don't add binary overload for multipart content type or typeddict-only mode
|
|
373
|
+
if not (self.is_tsp and has_multi_part_content_type(body_parameter)) and not is_typeddict_only:
|
|
376
374
|
body_parameter["type"]["types"].append(KNOWN_TYPES["binary"])
|
|
377
375
|
|
|
376
|
+
# Add typeddict overload for non-spread dpg models
|
|
378
377
|
if self.options["models-mode"] == "dpg" and is_dpg_model:
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
378
|
+
cross_lang_id = model_type.get("crossLanguageDefinitionId")
|
|
379
|
+
existing_td = self._find_existing_typeddict(code_model, cross_lang_id)
|
|
380
|
+
self._insert_typeddict_overload(code_model, body_parameter, model_type, origin_type, existing_td)
|
|
381
|
+
|
|
382
|
+
# For spread bodies (json base), add a typeddict overload that references
|
|
383
|
+
# the original model. This replaces the JSON single-body overload.
|
|
384
|
+
if is_json_model:
|
|
385
|
+
cross_lang_id = model_type.get("crossLanguageDefinitionId")
|
|
386
|
+
original = None
|
|
387
|
+
if cross_lang_id:
|
|
388
|
+
original = next(
|
|
389
|
+
(
|
|
390
|
+
t
|
|
391
|
+
for t in code_model["types"]
|
|
392
|
+
if t.get("type") == "model"
|
|
393
|
+
and t.get("crossLanguageDefinitionId") == cross_lang_id
|
|
394
|
+
and t is not model_type
|
|
395
|
+
),
|
|
396
|
+
None,
|
|
386
397
|
)
|
|
387
|
-
|
|
388
|
-
|
|
398
|
+
|
|
399
|
+
if is_typeddict_only and original:
|
|
400
|
+
# In typeddict-only mode, the original dpg model already renders
|
|
401
|
+
# as a TypedDict — reference it directly, no copy needed.
|
|
402
|
+
if origin_type == "model":
|
|
403
|
+
body_parameter["type"]["types"].insert(1, original)
|
|
404
|
+
else:
|
|
405
|
+
td_list_or_dict = copy.deepcopy(body_parameter["type"]["types"][0])
|
|
406
|
+
td_list_or_dict["elementType"] = original
|
|
407
|
+
body_parameter["type"]["types"].insert(1, td_list_or_dict)
|
|
408
|
+
else:
|
|
409
|
+
source = original or model_type
|
|
410
|
+
existing_td = self._find_existing_typeddict(code_model, cross_lang_id)
|
|
411
|
+
self._insert_typeddict_overload(code_model, body_parameter, source, origin_type, existing_td)
|
|
412
|
+
|
|
413
|
+
if len(body_parameter["type"]["types"]) == 1:
|
|
414
|
+
# Only one body variant remains (e.g. typeddict-only mode where the
|
|
415
|
+
# binary and JSON overloads are omitted). Collapse the combined
|
|
416
|
+
# wrapper back to the single type so we don't emit a lone
|
|
417
|
+
# ``@overload`` (mypy rejects a single overload definition).
|
|
418
|
+
body_parameter["type"] = body_parameter["type"]["types"][0]
|
|
419
|
+
return
|
|
420
|
+
|
|
389
421
|
code_model["types"].append(body_parameter["type"])
|
|
390
422
|
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
) -> str:
|
|
423
|
+
|
|
424
|
+
def pad_reserved_words(self, name: str, pad_type: PadType, yaml_type: dict[str, Any]) -> str:
|
|
394
425
|
# we want to pad hidden variables as well
|
|
395
426
|
if not name:
|
|
396
427
|
# we'll pass in empty operation groups sometime etc.
|
|
397
428
|
return name
|
|
398
429
|
|
|
399
430
|
if self.is_tsp:
|
|
400
|
-
reserved_words = {
|
|
401
|
-
k: (v + TSP_RESERVED_WORDS.get(k, []))
|
|
402
|
-
for k, v in RESERVED_WORDS.items()
|
|
403
|
-
}
|
|
431
|
+
reserved_words = {k: (v + TSP_RESERVED_WORDS.get(k, [])) for k, v in RESERVED_WORDS.items()}
|
|
404
432
|
else:
|
|
405
433
|
reserved_words = RESERVED_WORDS
|
|
406
434
|
name = pad_special_chars(name)
|
|
@@ -417,24 +445,18 @@ class PreProcessPlugin(YamlUpdatePlugin):
|
|
|
417
445
|
def update_types(self, yaml_data: list[dict[str, Any]]) -> None:
|
|
418
446
|
for type in yaml_data:
|
|
419
447
|
for property in type.get("properties", []):
|
|
420
|
-
property["description"] = update_description(
|
|
421
|
-
property.get("description", "")
|
|
422
|
-
)
|
|
448
|
+
property["description"] = update_description(property.get("description", ""))
|
|
423
449
|
if not property.get("isExactName", False):
|
|
424
450
|
property["clientName"] = self.pad_reserved_words(
|
|
425
451
|
property["clientName"].lower(), PadType.PROPERTY, property
|
|
426
452
|
)
|
|
427
453
|
add_redefined_builtin_info(property["clientName"], property)
|
|
428
454
|
if type.get("name"):
|
|
429
|
-
pad_type =
|
|
430
|
-
PadType.MODEL if type["type"] == "model" else PadType.ENUM_CLASS
|
|
431
|
-
)
|
|
455
|
+
pad_type = PadType.MODEL if type["type"] == "model" else PadType.ENUM_CLASS
|
|
432
456
|
if type["type"] != "enumvalue":
|
|
433
457
|
name = self.pad_reserved_words(type["name"], pad_type, type)
|
|
434
458
|
type["name"] = name[0].upper() + name[1:]
|
|
435
|
-
type["description"] = update_description(
|
|
436
|
-
type.get("description", ""), type["name"]
|
|
437
|
-
)
|
|
459
|
+
type["description"] = update_description(type.get("description", ""), type["name"])
|
|
438
460
|
type["snakeCaseName"] = to_snake_case(type["name"])
|
|
439
461
|
if type.get("values"):
|
|
440
462
|
# we're enums - enum values are UPPER_CASE so no padding needed for reserved words
|
|
@@ -452,24 +474,16 @@ class PreProcessPlugin(YamlUpdatePlugin):
|
|
|
452
474
|
yaml_data.append(CLOUD_SETTING["type"]) # type: ignore
|
|
453
475
|
|
|
454
476
|
def update_client(self, yaml_data: dict[str, Any]) -> None:
|
|
455
|
-
yaml_data["description"] = update_description(
|
|
456
|
-
yaml_data["description"], default_description=yaml_data["name"]
|
|
457
|
-
)
|
|
477
|
+
yaml_data["description"] = update_description(yaml_data["description"], default_description=yaml_data["name"])
|
|
458
478
|
yaml_data["legacyFilename"] = to_snake_case(yaml_data["name"].replace(" ", "_"))
|
|
459
479
|
parameters = yaml_data["parameters"]
|
|
460
480
|
for parameter in parameters:
|
|
461
481
|
self.update_parameter(parameter)
|
|
462
482
|
if parameter["clientName"] == "credential":
|
|
463
483
|
policy = parameter["type"].get("policy")
|
|
464
|
-
if
|
|
465
|
-
policy
|
|
466
|
-
and policy["type"] == "BearerTokenCredentialPolicy"
|
|
467
|
-
and self.azure_arm
|
|
468
|
-
):
|
|
484
|
+
if policy and policy["type"] == "BearerTokenCredentialPolicy" and self.azure_arm:
|
|
469
485
|
policy["type"] = "ARMChallengeAuthenticationPolicy"
|
|
470
|
-
policy["credentialScopes"] = [
|
|
471
|
-
"https://management.azure.com/.default"
|
|
472
|
-
]
|
|
486
|
+
policy["credentialScopes"] = ["https://management.azure.com/.default"]
|
|
473
487
|
if (
|
|
474
488
|
(not self.version_tolerant or self.azure_arm)
|
|
475
489
|
and parameters
|
|
@@ -489,9 +503,7 @@ class PreProcessPlugin(YamlUpdatePlugin):
|
|
|
489
503
|
if self.azure_arm and yaml_data["parameters"]:
|
|
490
504
|
yaml_data["parameters"].append(CLOUD_SETTING)
|
|
491
505
|
|
|
492
|
-
def get_operation_updater(
|
|
493
|
-
self, yaml_data: dict[str, Any]
|
|
494
|
-
) -> Callable[[dict[str, Any], dict[str, Any]], None]:
|
|
506
|
+
def get_operation_updater(self, yaml_data: dict[str, Any]) -> Callable[[dict[str, Any], dict[str, Any]], None]:
|
|
495
507
|
if yaml_data["discriminator"] == "lropaging":
|
|
496
508
|
return self.update_lro_paging_operation
|
|
497
509
|
if yaml_data["discriminator"] == "lro":
|
|
@@ -503,8 +515,7 @@ class PreProcessPlugin(YamlUpdatePlugin):
|
|
|
503
515
|
def update_parameter(self, yaml_data: dict[str, Any]) -> None:
|
|
504
516
|
yaml_data["description"] = update_description(yaml_data.get("description", ""))
|
|
505
517
|
if not yaml_data.get("isExactName", False) and not (
|
|
506
|
-
yaml_data["location"] == "header"
|
|
507
|
-
and yaml_data["clientName"] in ("content_type", "accept")
|
|
518
|
+
yaml_data["location"] == "header" and yaml_data["clientName"] in ("content_type", "accept")
|
|
508
519
|
):
|
|
509
520
|
yaml_data["clientName"] = self.pad_reserved_words(
|
|
510
521
|
yaml_data["clientName"].lower(), PadType.PARAMETER, yaml_data
|
|
@@ -520,16 +531,13 @@ class PreProcessPlugin(YamlUpdatePlugin):
|
|
|
520
531
|
prop: (
|
|
521
532
|
param_name
|
|
522
533
|
if prop in exact_name_props
|
|
523
|
-
else self.pad_reserved_words(
|
|
524
|
-
param_name, PadType.PARAMETER, yaml_data
|
|
525
|
-
).lower()
|
|
534
|
+
else self.pad_reserved_words(param_name, PadType.PARAMETER, yaml_data).lower()
|
|
526
535
|
)
|
|
527
536
|
for prop, param_name in yaml_data["propertyToParameterName"].items()
|
|
528
537
|
}
|
|
529
538
|
wire_name_lower = (yaml_data.get("wireName") or "").lower()
|
|
530
539
|
if yaml_data["location"] == "header" and (
|
|
531
|
-
wire_name_lower in HEADERS_HIDE_IN_METHOD
|
|
532
|
-
or yaml_data.get("clientDefaultValue") == "multipart/form-data"
|
|
540
|
+
wire_name_lower in HEADERS_HIDE_IN_METHOD or yaml_data.get("clientDefaultValue") == "multipart/form-data"
|
|
533
541
|
):
|
|
534
542
|
yaml_data["hideInMethod"] = True
|
|
535
543
|
if self.version_tolerant and yaml_data["location"] == "header":
|
|
@@ -538,10 +546,7 @@ class PreProcessPlugin(YamlUpdatePlugin):
|
|
|
538
546
|
headers_convert(yaml_data, ETAG_MATCH_DATA)
|
|
539
547
|
elif role == "ifNoneMatch":
|
|
540
548
|
headers_convert(yaml_data, ETAG_NONE_MATCH_DATA)
|
|
541
|
-
if
|
|
542
|
-
wire_name_lower in ["$host", "content-type", "accept"]
|
|
543
|
-
and yaml_data["type"]["type"] == "constant"
|
|
544
|
-
):
|
|
549
|
+
if wire_name_lower in ["$host", "content-type", "accept"] and yaml_data["type"]["type"] == "constant":
|
|
545
550
|
yaml_data["clientDefaultValue"] = yaml_data["type"]["value"]
|
|
546
551
|
|
|
547
552
|
def update_operation(
|
|
@@ -551,17 +556,13 @@ class PreProcessPlugin(YamlUpdatePlugin):
|
|
|
551
556
|
*,
|
|
552
557
|
is_overload: bool = False,
|
|
553
558
|
) -> None:
|
|
554
|
-
yaml_data["groupName"] = self.pad_reserved_words(
|
|
555
|
-
yaml_data["groupName"], PadType.OPERATION_GROUP, yaml_data
|
|
556
|
-
)
|
|
559
|
+
yaml_data["groupName"] = self.pad_reserved_words(yaml_data["groupName"], PadType.OPERATION_GROUP, yaml_data)
|
|
557
560
|
yaml_data["groupName"] = to_snake_case(yaml_data["groupName"])
|
|
558
561
|
if yaml_data.get("isExactName", False):
|
|
559
562
|
# exact() client name: keep the operation name as-is without lowercasing,
|
|
560
563
|
# snake-casing, or padding reserved words.
|
|
561
564
|
if yaml_data.get("isLroInitialOperation") is True:
|
|
562
|
-
yaml_data["name"] = (
|
|
563
|
-
"_" + extract_original_name(yaml_data["name"]) + "_initial"
|
|
564
|
-
)
|
|
565
|
+
yaml_data["name"] = "_" + extract_original_name(yaml_data["name"]) + "_initial"
|
|
565
566
|
else:
|
|
566
567
|
yaml_data["name"] = yaml_data["name"].lower()
|
|
567
568
|
if yaml_data.get("isLroInitialOperation") is True:
|
|
@@ -575,12 +576,8 @@ class PreProcessPlugin(YamlUpdatePlugin):
|
|
|
575
576
|
+ "_initial"
|
|
576
577
|
)
|
|
577
578
|
else:
|
|
578
|
-
yaml_data["name"] = self.pad_reserved_words(
|
|
579
|
-
|
|
580
|
-
)
|
|
581
|
-
yaml_data["description"] = update_description(
|
|
582
|
-
yaml_data["description"], yaml_data["name"]
|
|
583
|
-
)
|
|
579
|
+
yaml_data["name"] = self.pad_reserved_words(yaml_data["name"], PadType.METHOD, yaml_data)
|
|
580
|
+
yaml_data["description"] = update_description(yaml_data["description"], yaml_data["name"])
|
|
584
581
|
yaml_data["summary"] = update_description(yaml_data.get("summary", ""))
|
|
585
582
|
body_parameter = yaml_data.get("bodyParameter")
|
|
586
583
|
for parameter in yaml_data["parameters"]:
|
|
@@ -601,12 +598,8 @@ class PreProcessPlugin(YamlUpdatePlugin):
|
|
|
601
598
|
def _update_lro_operation_helper(self, yaml_data: dict[str, Any]) -> None:
|
|
602
599
|
for response in yaml_data.get("responses", []):
|
|
603
600
|
response["discriminator"] = "lro"
|
|
604
|
-
response["pollerSync"] = (
|
|
605
|
-
|
|
606
|
-
)
|
|
607
|
-
response["pollerAsync"] = (
|
|
608
|
-
response.get("pollerAsync") or "azure.core.polling.AsyncLROPoller"
|
|
609
|
-
)
|
|
601
|
+
response["pollerSync"] = response.get("pollerSync") or "azure.core.polling.LROPoller"
|
|
602
|
+
response["pollerAsync"] = response.get("pollerAsync") or "azure.core.polling.AsyncLROPoller"
|
|
610
603
|
if not response.get("pollingMethodSync"):
|
|
611
604
|
response["pollingMethodSync"] = (
|
|
612
605
|
"azure.mgmt.core.polling.arm_polling.ARMPolling"
|
|
@@ -628,9 +621,7 @@ class PreProcessPlugin(YamlUpdatePlugin):
|
|
|
628
621
|
item_type: Optional[dict[str, Any]] = None,
|
|
629
622
|
) -> None:
|
|
630
623
|
self.update_lro_operation(code_model, yaml_data, is_overload=is_overload)
|
|
631
|
-
self.update_paging_operation(
|
|
632
|
-
code_model, yaml_data, is_overload=is_overload, item_type=item_type
|
|
633
|
-
)
|
|
624
|
+
self.update_paging_operation(code_model, yaml_data, is_overload=is_overload, item_type=item_type)
|
|
634
625
|
yaml_data["discriminator"] = "lropaging"
|
|
635
626
|
for response in yaml_data.get("responses", []):
|
|
636
627
|
response["discriminator"] = "lropaging"
|
|
@@ -653,16 +644,12 @@ class PreProcessPlugin(YamlUpdatePlugin):
|
|
|
653
644
|
response["type"] = KNOWN_TYPES["binary"]
|
|
654
645
|
|
|
655
646
|
self.update_operation(code_model, yaml_data, is_overload=is_overload)
|
|
656
|
-
self.update_operation(
|
|
657
|
-
code_model, yaml_data["initialOperation"], is_overload=is_overload
|
|
658
|
-
)
|
|
647
|
+
self.update_operation(code_model, yaml_data["initialOperation"], is_overload=is_overload)
|
|
659
648
|
convert_initial_operation_response_type(yaml_data["initialOperation"])
|
|
660
649
|
self._update_lro_operation_helper(yaml_data)
|
|
661
650
|
for overload in yaml_data.get("overloads", []):
|
|
662
651
|
self._update_lro_operation_helper(overload)
|
|
663
|
-
self.update_operation(
|
|
664
|
-
code_model, overload["initialOperation"], is_overload=True
|
|
665
|
-
)
|
|
652
|
+
self.update_operation(code_model, overload["initialOperation"], is_overload=True)
|
|
666
653
|
convert_initial_operation_response_type(overload["initialOperation"])
|
|
667
654
|
|
|
668
655
|
def update_paging_operation(
|
|
@@ -680,9 +667,7 @@ class PreProcessPlugin(YamlUpdatePlugin):
|
|
|
680
667
|
PadType.OPERATION_GROUP,
|
|
681
668
|
yaml_data["nextOperation"],
|
|
682
669
|
)
|
|
683
|
-
yaml_data["nextOperation"]["groupName"] = to_snake_case(
|
|
684
|
-
yaml_data["nextOperation"]["groupName"]
|
|
685
|
-
)
|
|
670
|
+
yaml_data["nextOperation"]["groupName"] = to_snake_case(yaml_data["nextOperation"]["groupName"])
|
|
686
671
|
for response in yaml_data["nextOperation"].get("responses", []):
|
|
687
672
|
update_paging_response(response)
|
|
688
673
|
response["itemType"] = item_type
|
|
@@ -690,13 +675,9 @@ class PreProcessPlugin(YamlUpdatePlugin):
|
|
|
690
675
|
update_paging_response(response)
|
|
691
676
|
response["itemType"] = item_type
|
|
692
677
|
for overload in yaml_data.get("overloads", []):
|
|
693
|
-
self.update_paging_operation(
|
|
694
|
-
code_model, overload, is_overload=True, item_type=item_type
|
|
695
|
-
)
|
|
678
|
+
self.update_paging_operation(code_model, overload, is_overload=True, item_type=item_type)
|
|
696
679
|
|
|
697
|
-
def update_operation_groups(
|
|
698
|
-
self, code_model: dict[str, Any], client: dict[str, Any]
|
|
699
|
-
) -> None:
|
|
680
|
+
def update_operation_groups(self, code_model: dict[str, Any], client: dict[str, Any]) -> None:
|
|
700
681
|
operation_groups_yaml_data = client.get("operationGroups", [])
|
|
701
682
|
for operation_group in operation_groups_yaml_data:
|
|
702
683
|
operation_group["identifyName"] = self.pad_reserved_words(
|
|
@@ -704,17 +685,13 @@ class PreProcessPlugin(YamlUpdatePlugin):
|
|
|
704
685
|
PadType.OPERATION_GROUP,
|
|
705
686
|
operation_group,
|
|
706
687
|
)
|
|
707
|
-
operation_group["identifyName"] = to_snake_case(
|
|
708
|
-
operation_group["identifyName"]
|
|
709
|
-
)
|
|
688
|
+
operation_group["identifyName"] = to_snake_case(operation_group["identifyName"])
|
|
710
689
|
operation_group["propertyName"] = self.pad_reserved_words(
|
|
711
690
|
operation_group["propertyName"],
|
|
712
691
|
PadType.OPERATION_GROUP,
|
|
713
692
|
operation_group,
|
|
714
693
|
)
|
|
715
|
-
operation_group["propertyName"] = to_snake_case(
|
|
716
|
-
operation_group["propertyName"]
|
|
717
|
-
)
|
|
694
|
+
operation_group["propertyName"] = to_snake_case(operation_group["propertyName"])
|
|
718
695
|
operation_group["className"] = update_operation_group_class_name(
|
|
719
696
|
client["name"], operation_group["className"]
|
|
720
697
|
)
|
|
@@ -738,6 +715,4 @@ class PreProcessPlugin(YamlUpdatePlugin):
|
|
|
738
715
|
if __name__ == "__main__":
|
|
739
716
|
# TSP pipeline will call this
|
|
740
717
|
args, unknown_args = parse_args()
|
|
741
|
-
PreProcessPlugin(
|
|
742
|
-
output_folder=args.output_folder, tsp_file=args.tsp_file, **unknown_args
|
|
743
|
-
).process()
|
|
718
|
+
PreProcessPlugin(output_folder=args.output_folder, tsp_file=args.tsp_file, **unknown_args).process()
|
|
@@ -22,20 +22,13 @@ def description_ends_with_code_block(description: str) -> bool:
|
|
|
22
22
|
block runs to the end of the description.
|
|
23
23
|
"""
|
|
24
24
|
lines = description.rstrip().splitlines()
|
|
25
|
-
directives = [
|
|
26
|
-
i for i, line in enumerate(lines) if line.lstrip().startswith(CODE_BLOCK_MARKER)
|
|
27
|
-
]
|
|
25
|
+
directives = [i for i, line in enumerate(lines) if line.lstrip().startswith(CODE_BLOCK_MARKER)]
|
|
28
26
|
if not directives:
|
|
29
27
|
return False
|
|
30
|
-
return all(
|
|
31
|
-
not line.strip() or line.startswith((" ", "\t"))
|
|
32
|
-
for line in lines[directives[-1] + 1 :]
|
|
33
|
-
)
|
|
28
|
+
return all(not line.strip() or line.startswith((" ", "\t")) for line in lines[directives[-1] + 1 :])
|
|
34
29
|
|
|
35
30
|
|
|
36
|
-
def update_enum_value(
|
|
37
|
-
name: str, value: Any, description: str, enum_type: dict[str, Any]
|
|
38
|
-
) -> dict[str, Any]:
|
|
31
|
+
def update_enum_value(name: str, value: Any, description: str, enum_type: dict[str, Any]) -> dict[str, Any]:
|
|
39
32
|
return {
|
|
40
33
|
"name": name,
|
|
41
34
|
"type": "enumvalue",
|
|
@@ -62,12 +55,7 @@ def to_snake_case(name: str) -> str:
|
|
|
62
55
|
and len(name) - next_non_upper_case_char_location > 1
|
|
63
56
|
and name[next_non_upper_case_char_location].isalpha()
|
|
64
57
|
):
|
|
65
|
-
return (
|
|
66
|
-
prefix
|
|
67
|
-
+ match_str[: len(match_str) - 1]
|
|
68
|
-
+ "_"
|
|
69
|
-
+ match_str[len(match_str) - 1]
|
|
70
|
-
)
|
|
58
|
+
return prefix + match_str[: len(match_str) - 1] + "_" + match_str[len(match_str) - 1]
|
|
71
59
|
|
|
72
60
|
return prefix + match_str
|
|
73
61
|
|
|
@@ -114,9 +102,7 @@ def parse_args(
|
|
|
114
102
|
return value
|
|
115
103
|
|
|
116
104
|
unknown_args_ret = {
|
|
117
|
-
ua.strip("--").split("=", maxsplit=1)[0]: _get_value(
|
|
118
|
-
ua.strip("--").split("=", maxsplit=1)[1]
|
|
119
|
-
)
|
|
105
|
+
ua.strip("--").split("=", maxsplit=1)[0]: _get_value(ua.strip("--").split("=", maxsplit=1)[1])
|
|
120
106
|
for ua in unknown_args
|
|
121
107
|
}
|
|
122
108
|
return args, unknown_args_ret
|
|
@@ -158,11 +144,7 @@ def build_policies(
|
|
|
158
144
|
"self._config.user_agent_policy",
|
|
159
145
|
"self._config.proxy_policy",
|
|
160
146
|
"policies.ContentDecodePolicy(**kwargs)",
|
|
161
|
-
(
|
|
162
|
-
f"{async_prefix}ARMAutoResourceProviderRegistrationPolicy()"
|
|
163
|
-
if is_arm
|
|
164
|
-
else None
|
|
165
|
-
),
|
|
147
|
+
(f"{async_prefix}ARMAutoResourceProviderRegistrationPolicy()" if is_arm else None),
|
|
166
148
|
"self._config.redirect_policy",
|
|
167
149
|
"self._config.retry_policy",
|
|
168
150
|
"self._config.authentication_policy",
|
|
Binary file
|
|
@@ -168,10 +168,10 @@ class OptionsDict(MutableMapping):
|
|
|
168
168
|
if key == "models-mode" and value == "none":
|
|
169
169
|
value = False # switch to falsy value for easier code writing
|
|
170
170
|
|
|
171
|
-
if key == "models-mode" and value not in ["msrest", "dpg", False]:
|
|
171
|
+
if key == "models-mode" and value not in ["msrest", "dpg", "typeddict", False]:
|
|
172
172
|
raise ValueError(
|
|
173
|
-
"--models-mode can only be 'msrest', 'dpg' or 'none'. "
|
|
174
|
-
"Pass in 'msrest' if you want msrest models, or "
|
|
173
|
+
"--models-mode can only be 'msrest', 'dpg', 'typeddict', or 'none'. "
|
|
174
|
+
"Pass in 'msrest' if you want msrest models, 'typeddict' for TypedDict models, or "
|
|
175
175
|
"'none' if you don't want any."
|
|
176
176
|
)
|
|
177
177
|
if key == "package-mode":
|
|
@@ -9,7 +9,7 @@ from .base import BaseModel
|
|
|
9
9
|
from .base_builder import BaseBuilder, ParameterListType
|
|
10
10
|
from .code_model import CodeModel
|
|
11
11
|
from .client import Client
|
|
12
|
-
from .model_type import ModelType, JSONModelType, DPGModelType, MsrestModelType
|
|
12
|
+
from .model_type import ModelType, JSONModelType, DPGModelType, MsrestModelType, TypedDictModelType
|
|
13
13
|
from .dictionary_type import DictionaryType
|
|
14
14
|
from .list_type import ListType
|
|
15
15
|
from .combined_type import CombinedType
|
|
@@ -167,7 +167,9 @@ def build_type(yaml_data: dict[str, Any], code_model: CodeModel) -> BaseType:
|
|
|
167
167
|
response: Optional[BaseType] = None
|
|
168
168
|
if yaml_data["type"] == "model":
|
|
169
169
|
# need to special case model to avoid recursion
|
|
170
|
-
if yaml_data["base"] == "
|
|
170
|
+
if yaml_data["base"] == "typeddict":
|
|
171
|
+
model_type = TypedDictModelType # type: ignore
|
|
172
|
+
elif yaml_data["base"] == "json" or not code_model.options["models-mode"]:
|
|
171
173
|
model_type = JSONModelType
|
|
172
174
|
elif yaml_data["base"] == "dpg":
|
|
173
175
|
model_type = DPGModelType # type: ignore
|