@typespec/http-client-python 0.33.0 → 0.34.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (86) hide show
  1. package/README.md +25 -3
  2. package/dist/emitter/emitter.d.ts.map +1 -1
  3. package/dist/emitter/emitter.js +2 -11
  4. package/dist/emitter/emitter.js.map +1 -1
  5. package/dist/emitter/external-process.d.ts +14 -0
  6. package/dist/emitter/external-process.d.ts.map +1 -1
  7. package/dist/emitter/external-process.js +17 -1
  8. package/dist/emitter/external-process.js.map +1 -1
  9. package/dist/emitter/lib.js +1 -1
  10. package/dist/emitter/lib.js.map +1 -1
  11. package/dist/emitter/node-runner.d.ts.map +1 -1
  12. package/dist/emitter/node-runner.js +2 -1
  13. package/dist/emitter/node-runner.js.map +1 -1
  14. package/dist/emitter/types.d.ts.map +1 -1
  15. package/dist/emitter/types.js +2 -0
  16. package/dist/emitter/types.js.map +1 -1
  17. package/dist/emitter/utils.d.ts +10 -0
  18. package/dist/emitter/utils.d.ts.map +1 -1
  19. package/dist/emitter/utils.js +12 -0
  20. package/dist/emitter/utils.js.map +1 -1
  21. package/emitter/src/emitter.ts +2 -14
  22. package/emitter/src/external-process.ts +18 -1
  23. package/emitter/src/lib.ts +1 -1
  24. package/emitter/src/node-runner.ts +2 -1
  25. package/emitter/src/types.ts +2 -0
  26. package/emitter/src/utils.ts +13 -0
  27. package/emitter/temp/tsconfig.tsbuildinfo +1 -1
  28. package/emitter/test/external-process.test.ts +28 -0
  29. package/emitter/test/utils.test.ts +12 -1
  30. package/eng/scripts/ci/regenerate-common.ts +40 -15
  31. package/eng/scripts/setup/__pycache__/package_manager.cpython-311.pyc +0 -0
  32. package/eng/scripts/setup/__pycache__/venvtools.cpython-311.pyc +0 -0
  33. package/generator/build/lib/pygen/__init__.py +3 -3
  34. package/generator/build/lib/pygen/codegen/models/__init__.py +4 -2
  35. package/generator/build/lib/pygen/codegen/models/code_model.py +27 -5
  36. package/generator/build/lib/pygen/codegen/models/combined_type.py +3 -3
  37. package/generator/build/lib/pygen/codegen/models/enum_type.py +75 -25
  38. package/generator/build/lib/pygen/codegen/models/list_type.py +10 -4
  39. package/generator/build/lib/pygen/codegen/models/model_type.py +149 -4
  40. package/generator/build/lib/pygen/codegen/models/operation.py +1 -0
  41. package/generator/build/lib/pygen/codegen/models/paging_operation.py +5 -1
  42. package/generator/build/lib/pygen/codegen/models/parameter.py +2 -2
  43. package/generator/build/lib/pygen/codegen/models/primitive_types.py +30 -6
  44. package/generator/build/lib/pygen/codegen/models/property.py +21 -8
  45. package/generator/build/lib/pygen/codegen/models/response.py +16 -3
  46. package/generator/build/lib/pygen/codegen/models/utils.py +3 -6
  47. package/generator/build/lib/pygen/codegen/serializers/__init__.py +46 -11
  48. package/generator/build/lib/pygen/codegen/serializers/builder_serializer.py +48 -15
  49. package/generator/build/lib/pygen/codegen/serializers/model_init_serializer.py +1 -1
  50. package/generator/build/lib/pygen/codegen/serializers/model_serializer.py +127 -3
  51. package/generator/build/lib/pygen/codegen/serializers/types_serializer.py +356 -12
  52. package/generator/build/lib/pygen/codegen/serializers/unions_serializer.py +44 -0
  53. package/generator/build/lib/pygen/codegen/templates/model_container.py.jinja2 +1 -1
  54. package/generator/build/lib/pygen/codegen/templates/types.py.jinja2 +51 -2
  55. package/generator/build/lib/pygen/codegen/templates/unions.py.jinja2 +9 -0
  56. package/generator/build/lib/pygen/preprocess/__init__.py +175 -162
  57. package/generator/build/lib/pygen/utils.py +6 -24
  58. package/generator/component-detection-pip-report.json +9 -9
  59. package/generator/dist/pygen-0.1.0-py3-none-any.whl +0 -0
  60. package/generator/pygen/__init__.py +3 -3
  61. package/generator/pygen/codegen/models/__init__.py +4 -2
  62. package/generator/pygen/codegen/models/code_model.py +27 -5
  63. package/generator/pygen/codegen/models/combined_type.py +3 -3
  64. package/generator/pygen/codegen/models/enum_type.py +75 -25
  65. package/generator/pygen/codegen/models/list_type.py +10 -4
  66. package/generator/pygen/codegen/models/model_type.py +149 -4
  67. package/generator/pygen/codegen/models/operation.py +1 -0
  68. package/generator/pygen/codegen/models/paging_operation.py +5 -1
  69. package/generator/pygen/codegen/models/parameter.py +2 -2
  70. package/generator/pygen/codegen/models/primitive_types.py +30 -6
  71. package/generator/pygen/codegen/models/property.py +21 -8
  72. package/generator/pygen/codegen/models/response.py +16 -3
  73. package/generator/pygen/codegen/models/utils.py +3 -6
  74. package/generator/pygen/codegen/serializers/__init__.py +46 -11
  75. package/generator/pygen/codegen/serializers/builder_serializer.py +48 -15
  76. package/generator/pygen/codegen/serializers/model_init_serializer.py +1 -1
  77. package/generator/pygen/codegen/serializers/model_serializer.py +127 -3
  78. package/generator/pygen/codegen/serializers/types_serializer.py +356 -12
  79. package/generator/pygen/codegen/serializers/unions_serializer.py +44 -0
  80. package/generator/pygen/codegen/templates/model_container.py.jinja2 +1 -1
  81. package/generator/pygen/codegen/templates/types.py.jinja2 +51 -2
  82. package/generator/pygen/codegen/templates/unions.py.jinja2 +9 -0
  83. package/generator/pygen/preprocess/__init__.py +175 -162
  84. package/generator/pygen/utils.py +6 -24
  85. package/generator/pygen.egg-info/SOURCES.txt +2 -0
  86. 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
- add_overload(yaml_data, body_type, for_flatten_params=True)
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
- if_match_candidates, STANDARD_IF_MATCH_WIRE_NAME
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
- get_wire_name_lower(property_if_match) == STANDARD_IF_MATCH_WIRE_NAME
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,94 @@ 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(
311
+ code_model: dict[str, Any],
312
+ cross_lang_id: Optional[str],
313
+ name: Optional[str] = None,
314
+ ) -> Optional[dict[str, Any]]:
315
+ """Find an existing typeddict copy for the given model.
316
+
317
+ Matches on both ``crossLanguageDefinitionId`` and ``name``. The name is required because
318
+ template-instantiated models (e.g. ``ResourceUpdateModel<Foo, FooProperties>``) all share
319
+ the template's cross-language id, so matching on the id alone would reuse one model's copy
320
+ (e.g. ``CacheUpdate``) for a different model (e.g. ``VolumeUpdate``).
321
+ """
322
+ if not cross_lang_id:
323
+ return None
324
+ return next(
325
+ (
326
+ t
327
+ for t in code_model["types"]
328
+ if t.get("type") == "model"
329
+ and t.get("base") == "typeddict"
330
+ and t.get("crossLanguageDefinitionId") == cross_lang_id
331
+ and (name is None or t.get("name") == name)
332
+ ),
333
+ None,
334
+ )
335
+
336
+ @staticmethod
337
+ def _find_spread_original(code_model: dict[str, Any], json_model: dict[str, Any]) -> Optional[dict[str, Any]]:
338
+ """Recover the dpg model that a spread (json) body was cloned from.
339
+
340
+ When a spread body type is also used elsewhere, the emitter clones it, renames the clone to
341
+ ``<Method>Request`` and sets ``base = "json"`` while keeping the original
342
+ ``crossLanguageDefinitionId``. To reference the real model's TypedDict we look the clone up
343
+ by that id.
344
+
345
+ Distinct template-instantiated models share a single ``crossLanguageDefinitionId``, so an id
346
+ match alone is ambiguous. We only reuse an original when the choice is unambiguous:
347
+
348
+ * a dpg candidate whose ``name`` equals the json model's name (the body was not renamed), or
349
+ * exactly one dpg candidate carries the id.
350
+
351
+ Otherwise we return ``None`` so the caller falls back to the json model itself, avoiding a
352
+ reference to the wrong model's TypedDict.
353
+ """
354
+ cross_lang_id = json_model.get("crossLanguageDefinitionId")
355
+ if not cross_lang_id:
356
+ return None
357
+ candidates = [
358
+ t
359
+ for t in code_model["types"]
360
+ if t.get("type") == "model"
361
+ and t.get("base") == "dpg"
362
+ and t.get("crossLanguageDefinitionId") == cross_lang_id
363
+ and t is not json_model
364
+ ]
365
+ if not candidates:
366
+ return None
367
+ name = json_model.get("name")
368
+ for candidate in candidates:
369
+ if candidate.get("name") == name:
370
+ return candidate
371
+ if len(candidates) == 1:
372
+ return candidates[0]
373
+ return None
374
+
375
+ @staticmethod
376
+ def _insert_typeddict_overload(
377
+ code_model: dict[str, Any],
378
+ body_parameter: dict[str, Any],
379
+ source: dict[str, Any],
380
+ origin_type: str,
381
+ existing_td: Optional[dict[str, Any]],
382
+ ) -> None:
383
+ """Insert a typeddict type into the body parameter's combined types."""
384
+ if origin_type == "model":
385
+ td_type = existing_td or {**source, "base": "typeddict"}
386
+ body_parameter["type"]["types"].insert(1, td_type)
387
+ if not existing_td:
388
+ code_model["types"].append(td_type)
389
+ else:
390
+ td_list_or_dict = copy.deepcopy(body_parameter["type"]["types"][0])
391
+ td_elem = existing_td or {**source, "base": "typeddict"}
392
+ td_list_or_dict["elementType"] = td_elem
393
+ body_parameter["type"]["types"].insert(1, td_list_or_dict)
394
+ if not existing_td:
395
+ code_model["types"].append(td_elem)
396
+
347
397
  def add_body_param_type(
348
398
  self,
349
399
  code_model: dict[str, Any],
@@ -353,54 +403,70 @@ class PreProcessPlugin(YamlUpdatePlugin):
353
403
  if ( # pylint: disable=too-many-boolean-expressions
354
404
  body_parameter
355
405
  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
- )
406
+ and (has_json_content_type(body_parameter) or (self.is_tsp and has_multi_part_content_type(body_parameter)))
360
407
  and not body_parameter["type"].get("xmlMetadata")
361
408
  and not any(t for t in ["flattened", "groupedBy"] if body_parameter.get(t))
362
409
  ):
363
410
  origin_type = body_parameter["type"]["type"]
364
411
  model_type = (
365
- body_parameter["type"]
366
- if origin_type == "model"
367
- else body_parameter["type"].get("elementType", {})
412
+ body_parameter["type"] if origin_type == "model" else body_parameter["type"].get("elementType", {})
368
413
  )
369
414
  is_dpg_model = model_type.get("base") == "dpg"
415
+ is_json_model = model_type.get("base") == "json"
416
+ is_typeddict_only = self.options["models-mode"] == "typeddict"
417
+
370
418
  body_parameter["type"] = {
371
419
  "type": "combined",
372
420
  "types": [body_parameter["type"]],
373
421
  }
374
- # don't add binary overload for multipart content type
375
- if not (self.is_tsp and has_multi_part_content_type(body_parameter)):
422
+ # don't add binary overload for multipart content type or typeddict-only mode
423
+ if not (self.is_tsp and has_multi_part_content_type(body_parameter)) and not is_typeddict_only:
376
424
  body_parameter["type"]["types"].append(KNOWN_TYPES["binary"])
377
425
 
426
+ # Add typeddict overload for non-spread dpg models
378
427
  if self.options["models-mode"] == "dpg" and is_dpg_model:
379
- if origin_type == "model":
380
- body_parameter["type"]["types"].insert(1, KNOWN_TYPES["any-object"])
428
+ cross_lang_id = model_type.get("crossLanguageDefinitionId")
429
+ existing_td = self._find_existing_typeddict(code_model, cross_lang_id, model_type.get("name"))
430
+ self._insert_typeddict_overload(code_model, body_parameter, model_type, origin_type, existing_td)
431
+
432
+ # For spread bodies (json base), add a typeddict overload that references
433
+ # the original model. This replaces the JSON single-body overload.
434
+ if is_json_model:
435
+ cross_lang_id = model_type.get("crossLanguageDefinitionId")
436
+ original = self._find_spread_original(code_model, model_type)
437
+
438
+ if is_typeddict_only and original:
439
+ # In typeddict-only mode, the original dpg model already renders
440
+ # as a TypedDict — reference it directly, no copy needed.
441
+ if origin_type == "model":
442
+ body_parameter["type"]["types"].insert(1, original)
443
+ else:
444
+ td_list_or_dict = copy.deepcopy(body_parameter["type"]["types"][0])
445
+ td_list_or_dict["elementType"] = original
446
+ body_parameter["type"]["types"].insert(1, td_list_or_dict)
381
447
  else:
382
- # dict or list
383
- # copy the original dict / list type
384
- any_obj_list_or_dict = copy.deepcopy(
385
- body_parameter["type"]["types"][0]
386
- )
387
- any_obj_list_or_dict["elementType"] = KNOWN_TYPES["any-object"]
388
- body_parameter["type"]["types"].insert(1, any_obj_list_or_dict)
448
+ source = original or model_type
449
+ existing_td = self._find_existing_typeddict(code_model, cross_lang_id, source.get("name"))
450
+ self._insert_typeddict_overload(code_model, body_parameter, source, origin_type, existing_td)
451
+
452
+ if len(body_parameter["type"]["types"]) == 1:
453
+ # Only one body variant remains (e.g. typeddict-only mode where the
454
+ # binary and JSON overloads are omitted). Collapse the combined
455
+ # wrapper back to the single type so we don't emit a lone
456
+ # ``@overload`` (mypy rejects a single overload definition).
457
+ body_parameter["type"] = body_parameter["type"]["types"][0]
458
+ return
459
+
389
460
  code_model["types"].append(body_parameter["type"])
390
461
 
391
- def pad_reserved_words(
392
- self, name: str, pad_type: PadType, yaml_type: dict[str, Any]
393
- ) -> str:
462
+ def pad_reserved_words(self, name: str, pad_type: PadType, yaml_type: dict[str, Any]) -> str:
394
463
  # we want to pad hidden variables as well
395
464
  if not name:
396
465
  # we'll pass in empty operation groups sometime etc.
397
466
  return name
398
467
 
399
468
  if self.is_tsp:
400
- reserved_words = {
401
- k: (v + TSP_RESERVED_WORDS.get(k, []))
402
- for k, v in RESERVED_WORDS.items()
403
- }
469
+ reserved_words = {k: (v + TSP_RESERVED_WORDS.get(k, [])) for k, v in RESERVED_WORDS.items()}
404
470
  else:
405
471
  reserved_words = RESERVED_WORDS
406
472
  name = pad_special_chars(name)
@@ -417,24 +483,18 @@ class PreProcessPlugin(YamlUpdatePlugin):
417
483
  def update_types(self, yaml_data: list[dict[str, Any]]) -> None:
418
484
  for type in yaml_data:
419
485
  for property in type.get("properties", []):
420
- property["description"] = update_description(
421
- property.get("description", "")
422
- )
486
+ property["description"] = update_description(property.get("description", ""))
423
487
  if not property.get("isExactName", False):
424
488
  property["clientName"] = self.pad_reserved_words(
425
489
  property["clientName"].lower(), PadType.PROPERTY, property
426
490
  )
427
491
  add_redefined_builtin_info(property["clientName"], property)
428
492
  if type.get("name"):
429
- pad_type = (
430
- PadType.MODEL if type["type"] == "model" else PadType.ENUM_CLASS
431
- )
493
+ pad_type = PadType.MODEL if type["type"] == "model" else PadType.ENUM_CLASS
432
494
  if type["type"] != "enumvalue":
433
495
  name = self.pad_reserved_words(type["name"], pad_type, type)
434
496
  type["name"] = name[0].upper() + name[1:]
435
- type["description"] = update_description(
436
- type.get("description", ""), type["name"]
437
- )
497
+ type["description"] = update_description(type.get("description", ""), type["name"])
438
498
  type["snakeCaseName"] = to_snake_case(type["name"])
439
499
  if type.get("values"):
440
500
  # we're enums - enum values are UPPER_CASE so no padding needed for reserved words
@@ -452,24 +512,16 @@ class PreProcessPlugin(YamlUpdatePlugin):
452
512
  yaml_data.append(CLOUD_SETTING["type"]) # type: ignore
453
513
 
454
514
  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
- )
515
+ yaml_data["description"] = update_description(yaml_data["description"], default_description=yaml_data["name"])
458
516
  yaml_data["legacyFilename"] = to_snake_case(yaml_data["name"].replace(" ", "_"))
459
517
  parameters = yaml_data["parameters"]
460
518
  for parameter in parameters:
461
519
  self.update_parameter(parameter)
462
520
  if parameter["clientName"] == "credential":
463
521
  policy = parameter["type"].get("policy")
464
- if (
465
- policy
466
- and policy["type"] == "BearerTokenCredentialPolicy"
467
- and self.azure_arm
468
- ):
522
+ if policy and policy["type"] == "BearerTokenCredentialPolicy" and self.azure_arm:
469
523
  policy["type"] = "ARMChallengeAuthenticationPolicy"
470
- policy["credentialScopes"] = [
471
- "https://management.azure.com/.default"
472
- ]
524
+ policy["credentialScopes"] = ["https://management.azure.com/.default"]
473
525
  if (
474
526
  (not self.version_tolerant or self.azure_arm)
475
527
  and parameters
@@ -489,9 +541,7 @@ class PreProcessPlugin(YamlUpdatePlugin):
489
541
  if self.azure_arm and yaml_data["parameters"]:
490
542
  yaml_data["parameters"].append(CLOUD_SETTING)
491
543
 
492
- def get_operation_updater(
493
- self, yaml_data: dict[str, Any]
494
- ) -> Callable[[dict[str, Any], dict[str, Any]], None]:
544
+ def get_operation_updater(self, yaml_data: dict[str, Any]) -> Callable[[dict[str, Any], dict[str, Any]], None]:
495
545
  if yaml_data["discriminator"] == "lropaging":
496
546
  return self.update_lro_paging_operation
497
547
  if yaml_data["discriminator"] == "lro":
@@ -503,8 +553,7 @@ class PreProcessPlugin(YamlUpdatePlugin):
503
553
  def update_parameter(self, yaml_data: dict[str, Any]) -> None:
504
554
  yaml_data["description"] = update_description(yaml_data.get("description", ""))
505
555
  if not yaml_data.get("isExactName", False) and not (
506
- yaml_data["location"] == "header"
507
- and yaml_data["clientName"] in ("content_type", "accept")
556
+ yaml_data["location"] == "header" and yaml_data["clientName"] in ("content_type", "accept")
508
557
  ):
509
558
  yaml_data["clientName"] = self.pad_reserved_words(
510
559
  yaml_data["clientName"].lower(), PadType.PARAMETER, yaml_data
@@ -520,16 +569,13 @@ class PreProcessPlugin(YamlUpdatePlugin):
520
569
  prop: (
521
570
  param_name
522
571
  if prop in exact_name_props
523
- else self.pad_reserved_words(
524
- param_name, PadType.PARAMETER, yaml_data
525
- ).lower()
572
+ else self.pad_reserved_words(param_name, PadType.PARAMETER, yaml_data).lower()
526
573
  )
527
574
  for prop, param_name in yaml_data["propertyToParameterName"].items()
528
575
  }
529
576
  wire_name_lower = (yaml_data.get("wireName") or "").lower()
530
577
  if yaml_data["location"] == "header" and (
531
- wire_name_lower in HEADERS_HIDE_IN_METHOD
532
- or yaml_data.get("clientDefaultValue") == "multipart/form-data"
578
+ wire_name_lower in HEADERS_HIDE_IN_METHOD or yaml_data.get("clientDefaultValue") == "multipart/form-data"
533
579
  ):
534
580
  yaml_data["hideInMethod"] = True
535
581
  if self.version_tolerant and yaml_data["location"] == "header":
@@ -538,10 +584,7 @@ class PreProcessPlugin(YamlUpdatePlugin):
538
584
  headers_convert(yaml_data, ETAG_MATCH_DATA)
539
585
  elif role == "ifNoneMatch":
540
586
  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
- ):
587
+ if wire_name_lower in ["$host", "content-type", "accept"] and yaml_data["type"]["type"] == "constant":
545
588
  yaml_data["clientDefaultValue"] = yaml_data["type"]["value"]
546
589
 
547
590
  def update_operation(
@@ -551,17 +594,13 @@ class PreProcessPlugin(YamlUpdatePlugin):
551
594
  *,
552
595
  is_overload: bool = False,
553
596
  ) -> None:
554
- yaml_data["groupName"] = self.pad_reserved_words(
555
- yaml_data["groupName"], PadType.OPERATION_GROUP, yaml_data
556
- )
597
+ yaml_data["groupName"] = self.pad_reserved_words(yaml_data["groupName"], PadType.OPERATION_GROUP, yaml_data)
557
598
  yaml_data["groupName"] = to_snake_case(yaml_data["groupName"])
558
599
  if yaml_data.get("isExactName", False):
559
600
  # exact() client name: keep the operation name as-is without lowercasing,
560
601
  # snake-casing, or padding reserved words.
561
602
  if yaml_data.get("isLroInitialOperation") is True:
562
- yaml_data["name"] = (
563
- "_" + extract_original_name(yaml_data["name"]) + "_initial"
564
- )
603
+ yaml_data["name"] = "_" + extract_original_name(yaml_data["name"]) + "_initial"
565
604
  else:
566
605
  yaml_data["name"] = yaml_data["name"].lower()
567
606
  if yaml_data.get("isLroInitialOperation") is True:
@@ -575,12 +614,8 @@ class PreProcessPlugin(YamlUpdatePlugin):
575
614
  + "_initial"
576
615
  )
577
616
  else:
578
- yaml_data["name"] = self.pad_reserved_words(
579
- yaml_data["name"], PadType.METHOD, yaml_data
580
- )
581
- yaml_data["description"] = update_description(
582
- yaml_data["description"], yaml_data["name"]
583
- )
617
+ yaml_data["name"] = self.pad_reserved_words(yaml_data["name"], PadType.METHOD, yaml_data)
618
+ yaml_data["description"] = update_description(yaml_data["description"], yaml_data["name"])
584
619
  yaml_data["summary"] = update_description(yaml_data.get("summary", ""))
585
620
  body_parameter = yaml_data.get("bodyParameter")
586
621
  for parameter in yaml_data["parameters"]:
@@ -601,12 +636,8 @@ class PreProcessPlugin(YamlUpdatePlugin):
601
636
  def _update_lro_operation_helper(self, yaml_data: dict[str, Any]) -> None:
602
637
  for response in yaml_data.get("responses", []):
603
638
  response["discriminator"] = "lro"
604
- response["pollerSync"] = (
605
- response.get("pollerSync") or "azure.core.polling.LROPoller"
606
- )
607
- response["pollerAsync"] = (
608
- response.get("pollerAsync") or "azure.core.polling.AsyncLROPoller"
609
- )
639
+ response["pollerSync"] = response.get("pollerSync") or "azure.core.polling.LROPoller"
640
+ response["pollerAsync"] = response.get("pollerAsync") or "azure.core.polling.AsyncLROPoller"
610
641
  if not response.get("pollingMethodSync"):
611
642
  response["pollingMethodSync"] = (
612
643
  "azure.mgmt.core.polling.arm_polling.ARMPolling"
@@ -628,9 +659,7 @@ class PreProcessPlugin(YamlUpdatePlugin):
628
659
  item_type: Optional[dict[str, Any]] = None,
629
660
  ) -> None:
630
661
  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
- )
662
+ self.update_paging_operation(code_model, yaml_data, is_overload=is_overload, item_type=item_type)
634
663
  yaml_data["discriminator"] = "lropaging"
635
664
  for response in yaml_data.get("responses", []):
636
665
  response["discriminator"] = "lropaging"
@@ -653,16 +682,12 @@ class PreProcessPlugin(YamlUpdatePlugin):
653
682
  response["type"] = KNOWN_TYPES["binary"]
654
683
 
655
684
  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
- )
685
+ self.update_operation(code_model, yaml_data["initialOperation"], is_overload=is_overload)
659
686
  convert_initial_operation_response_type(yaml_data["initialOperation"])
660
687
  self._update_lro_operation_helper(yaml_data)
661
688
  for overload in yaml_data.get("overloads", []):
662
689
  self._update_lro_operation_helper(overload)
663
- self.update_operation(
664
- code_model, overload["initialOperation"], is_overload=True
665
- )
690
+ self.update_operation(code_model, overload["initialOperation"], is_overload=True)
666
691
  convert_initial_operation_response_type(overload["initialOperation"])
667
692
 
668
693
  def update_paging_operation(
@@ -680,9 +705,7 @@ class PreProcessPlugin(YamlUpdatePlugin):
680
705
  PadType.OPERATION_GROUP,
681
706
  yaml_data["nextOperation"],
682
707
  )
683
- yaml_data["nextOperation"]["groupName"] = to_snake_case(
684
- yaml_data["nextOperation"]["groupName"]
685
- )
708
+ yaml_data["nextOperation"]["groupName"] = to_snake_case(yaml_data["nextOperation"]["groupName"])
686
709
  for response in yaml_data["nextOperation"].get("responses", []):
687
710
  update_paging_response(response)
688
711
  response["itemType"] = item_type
@@ -690,13 +713,9 @@ class PreProcessPlugin(YamlUpdatePlugin):
690
713
  update_paging_response(response)
691
714
  response["itemType"] = item_type
692
715
  for overload in yaml_data.get("overloads", []):
693
- self.update_paging_operation(
694
- code_model, overload, is_overload=True, item_type=item_type
695
- )
716
+ self.update_paging_operation(code_model, overload, is_overload=True, item_type=item_type)
696
717
 
697
- def update_operation_groups(
698
- self, code_model: dict[str, Any], client: dict[str, Any]
699
- ) -> None:
718
+ def update_operation_groups(self, code_model: dict[str, Any], client: dict[str, Any]) -> None:
700
719
  operation_groups_yaml_data = client.get("operationGroups", [])
701
720
  for operation_group in operation_groups_yaml_data:
702
721
  operation_group["identifyName"] = self.pad_reserved_words(
@@ -704,17 +723,13 @@ class PreProcessPlugin(YamlUpdatePlugin):
704
723
  PadType.OPERATION_GROUP,
705
724
  operation_group,
706
725
  )
707
- operation_group["identifyName"] = to_snake_case(
708
- operation_group["identifyName"]
709
- )
726
+ operation_group["identifyName"] = to_snake_case(operation_group["identifyName"])
710
727
  operation_group["propertyName"] = self.pad_reserved_words(
711
728
  operation_group["propertyName"],
712
729
  PadType.OPERATION_GROUP,
713
730
  operation_group,
714
731
  )
715
- operation_group["propertyName"] = to_snake_case(
716
- operation_group["propertyName"]
717
- )
732
+ operation_group["propertyName"] = to_snake_case(operation_group["propertyName"])
718
733
  operation_group["className"] = update_operation_group_class_name(
719
734
  client["name"], operation_group["className"]
720
735
  )
@@ -738,6 +753,4 @@ class PreProcessPlugin(YamlUpdatePlugin):
738
753
  if __name__ == "__main__":
739
754
  # TSP pipeline will call this
740
755
  args, unknown_args = parse_args()
741
- PreProcessPlugin(
742
- output_folder=args.output_folder, tsp_file=args.tsp_file, **unknown_args
743
- ).process()
756
+ 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",