@typespec/http-client-python 0.32.0 → 0.33.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.
@@ -29,6 +29,7 @@ class OptionsDict(MutableMapping):
29
29
  "from-typespec": False,
30
30
  "generate-sample": False,
31
31
  "keep-setup-py": False,
32
+ "keep-pyproject-fields": "",
32
33
  "generate-test": False,
33
34
  "head-as-boolean": True,
34
35
  "keep-version-file": False,
@@ -7,23 +7,24 @@ from typing import TypeVar
7
7
 
8
8
  from enum import Enum
9
9
 
10
+ from ...utils import description_ends_with_code_block
11
+
10
12
  T = TypeVar("T")
11
13
  OrderedSet = dict[T, None]
12
14
 
13
15
 
14
- CODE_BLOCK_MARKER = ".. code-block::"
15
-
16
-
17
16
  def add_to_description(description: str, entry: str) -> str:
18
17
  if not description:
19
18
  return entry
20
- # When the description contains a code block, the entry (e.g. "Required.") must be
21
- # inserted into the prose *before* the code block. Appending it after the code block
22
- # (e.g. "]. Required.") leaves it dangling at the end of the rendered block and breaks
23
- # Sphinx rendering.
24
- if CODE_BLOCK_MARKER in description:
25
- prose, _, code_block = description.partition(CODE_BLOCK_MARKER)
26
- return f"{prose.rstrip()} {entry}\n\n{CODE_BLOCK_MARKER}{code_block}"
19
+ if not entry:
20
+ return description
21
+ # When the description ends with a code block, prepend the entry (e.g. "Required.") so
22
+ # it appears before the prose instead of after the block. Appending inline (e.g.
23
+ # "]. Required.") would land it inside the rendered literal block and break Sphinx, and a
24
+ # trailing paragraph reads awkwardly. The code block stays at the very end where it renders
25
+ # cleanly. (Code-block descriptions only ever carry a single annotation in practice.)
26
+ if description_ends_with_code_block(description):
27
+ return f"{entry} {description.lstrip()}"
27
28
  return f"{description} {entry}"
28
29
 
29
30
 
@@ -44,6 +45,10 @@ class NamespaceType(str, Enum):
44
45
 
45
46
  LOCALS_LENGTH_LIMIT = 25
46
47
 
47
- REQUEST_BUILDER_BODY_VARIABLES_LENGTH = 6 # how many body variables are present in a request builder
48
+ REQUEST_BUILDER_BODY_VARIABLES_LENGTH = (
49
+ 6 # how many body variables are present in a request builder
50
+ )
48
51
 
49
- OPERATION_BODY_VARIABLES_LENGTH = 14 # how many body variables are present in an operation
52
+ OPERATION_BODY_VARIABLES_LENGTH = (
53
+ 14 # how many body variables are present in an operation
54
+ )
@@ -66,7 +66,26 @@ class GeneralSerializer(BaseSerializer):
66
66
  if dep_version > default_version:
67
67
  version_map[dep_name] = str(dep_version)
68
68
 
69
- def external_lib_version_map(self, file_content: str, additional_version_map: dict[str, str]) -> dict:
69
+ # Project-level pyproject.toml fields that may be preserved across regeneration
70
+ # via the "keep-pyproject-fields" option.
71
+ KEEPABLE_PROJECT_FIELDS = ("authors", "description", "classifiers", "urls")
72
+
73
+ @staticmethod
74
+ def _parse_keep_pyproject_fields(value: Any) -> tuple[str, ...]:
75
+ # The "keep-pyproject-fields" option may be a comma-separated string (e.g.
76
+ # "authors,description") or an already-parsed sequence of field names.
77
+ if not value:
78
+ return ()
79
+ if isinstance(value, str):
80
+ return tuple(field.strip() for field in value.split(",") if field.strip())
81
+ return tuple(value)
82
+
83
+ def external_lib_version_map(
84
+ self,
85
+ file_content: str,
86
+ additional_version_map: dict[str, str],
87
+ keep_pyproject_fields: tuple[str, ...] = (),
88
+ ) -> dict:
70
89
  # Load the pyproject.toml file if it exists and extract fields to keep.
71
90
  result: dict = {"KEEP_FIELDS": {}}
72
91
  try:
@@ -85,6 +104,14 @@ class GeneralSerializer(BaseSerializer):
85
104
 
86
105
  # Process dependencies
87
106
  if "project" in loaded_pyproject_toml:
107
+ project = loaded_pyproject_toml["project"]
108
+
109
+ # Keep manually customized project fields the emitter would otherwise overwrite.
110
+ # Only the fields explicitly listed in the "keep-pyproject-fields" option are preserved.
111
+ for field in keep_pyproject_fields:
112
+ if field in self.KEEPABLE_PROJECT_FIELDS and field in project:
113
+ result["KEEP_FIELDS"][f"project.{field}"] = project[field]
114
+
88
115
  # Handle main dependencies
89
116
  if "dependencies" in loaded_pyproject_toml["project"]:
90
117
  kept_deps = []
@@ -127,7 +154,10 @@ class GeneralSerializer(BaseSerializer):
127
154
 
128
155
  # Add fields to keep from an existing pyproject.toml
129
156
  if template_name == "pyproject.toml.jinja2":
130
- params = self.external_lib_version_map(file_content, additional_version_map)
157
+ keep_pyproject_fields = self._parse_keep_pyproject_fields(
158
+ self.code_model.options.get("keep-pyproject-fields")
159
+ )
160
+ params = self.external_lib_version_map(file_content, additional_version_map, keep_pyproject_fields)
131
161
  else:
132
162
  params = {}
133
163
 
@@ -11,15 +11,32 @@ build-backend = "setuptools.build_meta"
11
11
  [project]
12
12
  name = "{{ options.get('package-name')|lower }}"
13
13
  {% if options.get('package-mode') %}
14
+ {% if KEEP_FIELDS and KEEP_FIELDS.get('project.authors') %}
15
+ authors = [
16
+ {% for author in KEEP_FIELDS.get('project.authors') %}
17
+ { {% for key, val in author.items() %}{{ key }} = {{ val|tojson }}{% if not loop.last %}, {% endif %}{% endfor %} },
18
+ {% endfor %}
19
+ ]
20
+ {% else %}
14
21
  authors = [
15
22
  { name = "{{ code_model.company_name }}"{% if code_model.is_azure_flavor %}, email = "azpysdkhelp@microsoft.com"{% endif %} },
16
23
  ]
17
- {% if options.get("azure-arm") %}
24
+ {% endif %}
25
+ {% if KEEP_FIELDS and KEEP_FIELDS.get('project.description') %}
26
+ description = {{ KEEP_FIELDS.get('project.description')|tojson }}
27
+ {% elif options.get("azure-arm") %}
18
28
  description = "Microsoft Azure {{ options.get('package-pprint-name') }} Client Library for Python"
19
29
  {% else %}
20
30
  description = "{{ code_model.company_name }} {% if code_model.is_azure_flavor and not options.get('package-pprint-name').startswith('Azure ') %}Azure {% endif %}{{ options.get('package-pprint-name') }} Client Library for Python"
21
31
  {% endif %}
22
32
  license = "MIT"
33
+ {% if KEEP_FIELDS and KEEP_FIELDS.get('project.classifiers') %}
34
+ classifiers = [
35
+ {% for classifier in KEEP_FIELDS.get('project.classifiers') %}
36
+ {{ classifier|tojson }},
37
+ {% endfor %}
38
+ ]
39
+ {% else %}
23
40
  classifiers = [
24
41
  "Development Status :: {{ dev_status }}",
25
42
  "Programming Language :: Python",
@@ -29,10 +46,15 @@ classifiers = [
29
46
  "Programming Language :: Python :: 3.{{ version }}",
30
47
  {% endfor %}
31
48
  ]
49
+ {% endif %}
32
50
  requires-python = ">={{ MIN_PYTHON_VERSION }}"
33
51
  {% else %}
52
+ {% if KEEP_FIELDS and KEEP_FIELDS.get('project.description') %}
53
+ description = {{ KEEP_FIELDS.get('project.description')|tojson }}
54
+ {% else %}
34
55
  description = "{{ options.get('package-name') }}"
35
56
  {% endif %}
57
+ {% endif %}
36
58
  {% if code_model.is_azure_flavor %}
37
59
  keywords = ["azure", "azure sdk"]
38
60
  {% endif %}
@@ -77,7 +99,13 @@ version = "{{ options.get("package-version", "unknown") }}"
77
99
  ]
78
100
  {% endfor %}
79
101
  {% endif %}
80
- {% if code_model.is_azure_flavor %}
102
+ {% if KEEP_FIELDS and KEEP_FIELDS.get('project.urls') %}
103
+
104
+ [project.urls]
105
+ {% for key, val in KEEP_FIELDS.get('project.urls').items() %}
106
+ {{ key }} = {{ val|tojson }}
107
+ {% endfor %}
108
+ {% elif code_model.is_azure_flavor %}
81
109
 
82
110
  [project.urls]
83
111
  repository = "https://github.com/Azure/azure-sdk-for-python"
@@ -22,6 +22,7 @@ from ..utils import (
22
22
  get_body_type_for_description,
23
23
  JSON_REGEXP,
24
24
  KNOWN_TYPES,
25
+ description_ends_with_code_block,
25
26
  )
26
27
 
27
28
 
@@ -35,14 +36,18 @@ def update_overload_section(
35
36
  if overload_s.get("type"):
36
37
  overload_s["type"] = original_s["type"]
37
38
  if overload_s.get("headers"):
38
- for overload_h, original_h in zip(overload_s["headers"], original_s["headers"]):
39
+ for overload_h, original_h in zip(
40
+ overload_s["headers"], original_s["headers"]
41
+ ):
39
42
  if overload_h.get("type"):
40
43
  overload_h["type"] = original_h["type"]
41
44
  except KeyError as exc:
42
45
  raise ValueError(overload["name"]) from exc
43
46
 
44
47
 
45
- def add_overload(yaml_data: dict[str, Any], body_type: dict[str, Any], for_flatten_params=False):
48
+ def add_overload(
49
+ yaml_data: dict[str, Any], body_type: dict[str, Any], for_flatten_params=False
50
+ ):
46
51
  overload = copy.deepcopy(yaml_data)
47
52
  overload["isOverload"] = True
48
53
  overload["bodyParameter"]["type"] = body_type
@@ -54,7 +59,9 @@ def add_overload(yaml_data: dict[str, Any], body_type: dict[str, Any], for_flatt
54
59
  if for_flatten_params:
55
60
  overload["bodyParameter"]["flattened"] = True
56
61
  else:
57
- overload["parameters"] = [p for p in overload["parameters"] if not p.get("inFlattenedBody")]
62
+ overload["parameters"] = [
63
+ p for p in overload["parameters"] if not p.get("inFlattenedBody")
64
+ ]
58
65
  # for yaml sync, we need to make sure all of the responses, parameters, and exceptions' types have the same yaml id
59
66
  for overload_p, original_p in zip(overload["parameters"], yaml_data["parameters"]):
60
67
  overload_p["type"] = original_p["type"]
@@ -62,7 +69,9 @@ def add_overload(yaml_data: dict[str, Any], body_type: dict[str, Any], for_flatt
62
69
  update_overload_section(overload, yaml_data, "exceptions")
63
70
 
64
71
  # update content type to be an overloads content type
65
- content_type_param = next(p for p in overload["parameters"] if p["wireName"].lower() == "content-type")
72
+ content_type_param = next(
73
+ p for p in overload["parameters"] if p["wireName"].lower() == "content-type"
74
+ )
66
75
  content_type_param["inOverload"] = True
67
76
  content_type_param["inDocstring"] = True
68
77
  body_type_description = get_body_type_for_description(overload["bodyParameter"])
@@ -85,16 +94,25 @@ def add_overloads_for_body_param(yaml_data: dict[str, Any]) -> None:
85
94
  body_parameter = yaml_data["bodyParameter"]
86
95
  if not (
87
96
  body_parameter["type"]["type"] == "combined"
88
- and len(yaml_data["bodyParameter"]["type"]["types"]) > len(yaml_data["overloads"])
97
+ and len(yaml_data["bodyParameter"]["type"]["types"])
98
+ > len(yaml_data["overloads"])
89
99
  ):
90
100
  return
91
101
  for body_type in body_parameter["type"]["types"]:
92
- if any(o for o in yaml_data["overloads"] if id(o["bodyParameter"]["type"]) == id(body_type)):
102
+ if any(
103
+ o
104
+ for o in yaml_data["overloads"]
105
+ if id(o["bodyParameter"]["type"]) == id(body_type)
106
+ ):
93
107
  continue
94
108
  if body_type.get("type") == "model" and body_type.get("base") == "json":
95
- yaml_data["overloads"].append(add_overload(yaml_data, body_type, for_flatten_params=True))
109
+ yaml_data["overloads"].append(
110
+ add_overload(yaml_data, body_type, for_flatten_params=True)
111
+ )
96
112
  yaml_data["overloads"].append(add_overload(yaml_data, body_type))
97
- content_type_param = next(p for p in yaml_data["parameters"] if p["wireName"].lower() == "content-type")
113
+ content_type_param = next(
114
+ p for p in yaml_data["parameters"] if p["wireName"].lower() == "content-type"
115
+ )
98
116
  content_type_param["inOverload"] = False
99
117
  content_type_param["inOverridden"] = True
100
118
  content_type_param["inDocstring"] = True
@@ -104,11 +122,19 @@ def add_overloads_for_body_param(yaml_data: dict[str, Any]) -> None:
104
122
  content_type_param["optional"] = True
105
123
 
106
124
 
107
- def update_description(description: Optional[str], default_description: str = "") -> str:
125
+ def update_description(
126
+ description: Optional[str], default_description: str = ""
127
+ ) -> str:
108
128
  if not description:
109
129
  description = default_description
110
130
  description.rstrip(" ")
111
- if description and description[-1] != ".":
131
+ # Don't append a trailing period when the description ends with a code block: the
132
+ # 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
+ ):
112
138
  description += "."
113
139
  return description
114
140
 
@@ -171,7 +197,9 @@ def _get_etag_role(parameter: dict[str, Any]) -> Optional[str]:
171
197
  return parameter.get("etagRole")
172
198
 
173
199
 
174
- def _pick_etag_slot(candidates: list[dict[str, Any]], standard_wire_name: str) -> Optional[dict[str, Any]]:
200
+ def _pick_etag_slot(
201
+ candidates: list[dict[str, Any]], standard_wire_name: str
202
+ ) -> Optional[dict[str, Any]]:
175
203
  """Choose which etag-typed header should be promoted to the etag/match_condition slot.
176
204
 
177
205
  When more than one etag-typed header is present in an operation, prefer the
@@ -199,16 +227,25 @@ def _resolve_etag_pair(
199
227
  Returns (property_if_match, property_if_none_match) — both None when
200
228
  there are no etag candidates.
201
229
  """
202
- property_if_match = _pick_etag_slot(if_match_candidates, STANDARD_IF_MATCH_WIRE_NAME)
203
- property_if_none_match = _pick_etag_slot(if_none_match_candidates, STANDARD_IF_NONE_MATCH_WIRE_NAME)
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
+ )
204
236
 
205
237
  # Ensure the promoted pair come from the same family. When one slot is
206
238
  # standard and the other custom (cross-family), replace the custom slot
207
239
  # with a synthetic standard partner. Also synthesize the missing partner
208
240
  # when only one side is present.
209
241
  if property_if_match and property_if_none_match:
210
- match_is_std = get_wire_name_lower(property_if_match) == STANDARD_IF_MATCH_WIRE_NAME
211
- none_match_is_std = get_wire_name_lower(property_if_none_match) == STANDARD_IF_NONE_MATCH_WIRE_NAME
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
+ )
212
249
  if match_is_std and not none_match_is_std:
213
250
  property_if_none_match = property_if_match.copy()
214
251
  property_if_none_match["wireName"] = STANDARD_IF_NONE_MATCH_WIRE_NAME
@@ -256,11 +293,15 @@ def _process_operation_etag_headers(
256
293
  elif role == "ifNoneMatch":
257
294
  if_none_match_candidates.append(p)
258
295
 
259
- property_if_match, property_if_none_match = _resolve_etag_pair(if_match_candidates, if_none_match_candidates)
296
+ property_if_match, property_if_none_match = _resolve_etag_pair(
297
+ if_match_candidates, if_none_match_candidates
298
+ )
260
299
 
261
300
  if property_if_match and property_if_none_match:
262
301
  etag_params = {id(property_if_match), id(property_if_none_match)}
263
- operation["parameters"] = [item for item in operation["parameters"] if id(item) not in etag_params] + [
302
+ operation["parameters"] = [
303
+ item for item in operation["parameters"] if id(item) not in etag_params
304
+ ] + [
264
305
  property_if_match,
265
306
  property_if_none_match,
266
307
  ]
@@ -279,7 +320,9 @@ def has_json_content_type(yaml_data: dict[str, Any]) -> bool:
279
320
 
280
321
 
281
322
  def has_multi_part_content_type(yaml_data: dict[str, Any]) -> bool:
282
- return any(ct for ct in yaml_data.get("contentTypes", []) if ct == "multipart/form-data")
323
+ return any(
324
+ ct for ct in yaml_data.get("contentTypes", []) if ct == "multipart/form-data"
325
+ )
283
326
 
284
327
 
285
328
  class PreProcessPlugin(YamlUpdatePlugin):
@@ -310,13 +353,18 @@ class PreProcessPlugin(YamlUpdatePlugin):
310
353
  if ( # pylint: disable=too-many-boolean-expressions
311
354
  body_parameter
312
355
  and body_parameter["type"]["type"] in ("model", "dict", "list")
313
- and (has_json_content_type(body_parameter) or (self.is_tsp and has_multi_part_content_type(body_parameter)))
356
+ and (
357
+ has_json_content_type(body_parameter)
358
+ or (self.is_tsp and has_multi_part_content_type(body_parameter))
359
+ )
314
360
  and not body_parameter["type"].get("xmlMetadata")
315
361
  and not any(t for t in ["flattened", "groupedBy"] if body_parameter.get(t))
316
362
  ):
317
363
  origin_type = body_parameter["type"]["type"]
318
364
  model_type = (
319
- body_parameter["type"] if origin_type == "model" else body_parameter["type"].get("elementType", {})
365
+ body_parameter["type"]
366
+ if origin_type == "model"
367
+ else body_parameter["type"].get("elementType", {})
320
368
  )
321
369
  is_dpg_model = model_type.get("base") == "dpg"
322
370
  body_parameter["type"] = {
@@ -333,19 +381,26 @@ class PreProcessPlugin(YamlUpdatePlugin):
333
381
  else:
334
382
  # dict or list
335
383
  # copy the original dict / list type
336
- any_obj_list_or_dict = copy.deepcopy(body_parameter["type"]["types"][0])
384
+ any_obj_list_or_dict = copy.deepcopy(
385
+ body_parameter["type"]["types"][0]
386
+ )
337
387
  any_obj_list_or_dict["elementType"] = KNOWN_TYPES["any-object"]
338
388
  body_parameter["type"]["types"].insert(1, any_obj_list_or_dict)
339
389
  code_model["types"].append(body_parameter["type"])
340
390
 
341
- def pad_reserved_words(self, name: str, pad_type: PadType, yaml_type: dict[str, Any]) -> str:
391
+ def pad_reserved_words(
392
+ self, name: str, pad_type: PadType, yaml_type: dict[str, Any]
393
+ ) -> str:
342
394
  # we want to pad hidden variables as well
343
395
  if not name:
344
396
  # we'll pass in empty operation groups sometime etc.
345
397
  return name
346
398
 
347
399
  if self.is_tsp:
348
- reserved_words = {k: (v + TSP_RESERVED_WORDS.get(k, [])) for k, v in RESERVED_WORDS.items()}
400
+ reserved_words = {
401
+ k: (v + TSP_RESERVED_WORDS.get(k, []))
402
+ for k, v in RESERVED_WORDS.items()
403
+ }
349
404
  else:
350
405
  reserved_words = RESERVED_WORDS
351
406
  name = pad_special_chars(name)
@@ -362,18 +417,24 @@ class PreProcessPlugin(YamlUpdatePlugin):
362
417
  def update_types(self, yaml_data: list[dict[str, Any]]) -> None:
363
418
  for type in yaml_data:
364
419
  for property in type.get("properties", []):
365
- property["description"] = update_description(property.get("description", ""))
420
+ property["description"] = update_description(
421
+ property.get("description", "")
422
+ )
366
423
  if not property.get("isExactName", False):
367
424
  property["clientName"] = self.pad_reserved_words(
368
425
  property["clientName"].lower(), PadType.PROPERTY, property
369
426
  )
370
427
  add_redefined_builtin_info(property["clientName"], property)
371
428
  if type.get("name"):
372
- pad_type = PadType.MODEL if type["type"] == "model" else PadType.ENUM_CLASS
429
+ pad_type = (
430
+ PadType.MODEL if type["type"] == "model" else PadType.ENUM_CLASS
431
+ )
373
432
  if type["type"] != "enumvalue":
374
433
  name = self.pad_reserved_words(type["name"], pad_type, type)
375
434
  type["name"] = name[0].upper() + name[1:]
376
- type["description"] = update_description(type.get("description", ""), type["name"])
435
+ type["description"] = update_description(
436
+ type.get("description", ""), type["name"]
437
+ )
377
438
  type["snakeCaseName"] = to_snake_case(type["name"])
378
439
  if type.get("values"):
379
440
  # we're enums - enum values are UPPER_CASE so no padding needed for reserved words
@@ -391,16 +452,24 @@ class PreProcessPlugin(YamlUpdatePlugin):
391
452
  yaml_data.append(CLOUD_SETTING["type"]) # type: ignore
392
453
 
393
454
  def update_client(self, yaml_data: dict[str, Any]) -> None:
394
- yaml_data["description"] = update_description(yaml_data["description"], default_description=yaml_data["name"])
455
+ yaml_data["description"] = update_description(
456
+ yaml_data["description"], default_description=yaml_data["name"]
457
+ )
395
458
  yaml_data["legacyFilename"] = to_snake_case(yaml_data["name"].replace(" ", "_"))
396
459
  parameters = yaml_data["parameters"]
397
460
  for parameter in parameters:
398
461
  self.update_parameter(parameter)
399
462
  if parameter["clientName"] == "credential":
400
463
  policy = parameter["type"].get("policy")
401
- if policy and policy["type"] == "BearerTokenCredentialPolicy" and self.azure_arm:
464
+ if (
465
+ policy
466
+ and policy["type"] == "BearerTokenCredentialPolicy"
467
+ and self.azure_arm
468
+ ):
402
469
  policy["type"] = "ARMChallengeAuthenticationPolicy"
403
- policy["credentialScopes"] = ["https://management.azure.com/.default"]
470
+ policy["credentialScopes"] = [
471
+ "https://management.azure.com/.default"
472
+ ]
404
473
  if (
405
474
  (not self.version_tolerant or self.azure_arm)
406
475
  and parameters
@@ -420,7 +489,9 @@ class PreProcessPlugin(YamlUpdatePlugin):
420
489
  if self.azure_arm and yaml_data["parameters"]:
421
490
  yaml_data["parameters"].append(CLOUD_SETTING)
422
491
 
423
- def get_operation_updater(self, yaml_data: dict[str, Any]) -> Callable[[dict[str, Any], dict[str, Any]], None]:
492
+ def get_operation_updater(
493
+ self, yaml_data: dict[str, Any]
494
+ ) -> Callable[[dict[str, Any], dict[str, Any]], None]:
424
495
  if yaml_data["discriminator"] == "lropaging":
425
496
  return self.update_lro_paging_operation
426
497
  if yaml_data["discriminator"] == "lro":
@@ -432,7 +503,8 @@ class PreProcessPlugin(YamlUpdatePlugin):
432
503
  def update_parameter(self, yaml_data: dict[str, Any]) -> None:
433
504
  yaml_data["description"] = update_description(yaml_data.get("description", ""))
434
505
  if not yaml_data.get("isExactName", False) and not (
435
- yaml_data["location"] == "header" and yaml_data["clientName"] in ("content_type", "accept")
506
+ yaml_data["location"] == "header"
507
+ and yaml_data["clientName"] in ("content_type", "accept")
436
508
  ):
437
509
  yaml_data["clientName"] = self.pad_reserved_words(
438
510
  yaml_data["clientName"].lower(), PadType.PARAMETER, yaml_data
@@ -448,13 +520,16 @@ class PreProcessPlugin(YamlUpdatePlugin):
448
520
  prop: (
449
521
  param_name
450
522
  if prop in exact_name_props
451
- else self.pad_reserved_words(param_name, PadType.PARAMETER, yaml_data).lower()
523
+ else self.pad_reserved_words(
524
+ param_name, PadType.PARAMETER, yaml_data
525
+ ).lower()
452
526
  )
453
527
  for prop, param_name in yaml_data["propertyToParameterName"].items()
454
528
  }
455
529
  wire_name_lower = (yaml_data.get("wireName") or "").lower()
456
530
  if yaml_data["location"] == "header" and (
457
- wire_name_lower in HEADERS_HIDE_IN_METHOD or yaml_data.get("clientDefaultValue") == "multipart/form-data"
531
+ wire_name_lower in HEADERS_HIDE_IN_METHOD
532
+ or yaml_data.get("clientDefaultValue") == "multipart/form-data"
458
533
  ):
459
534
  yaml_data["hideInMethod"] = True
460
535
  if self.version_tolerant and yaml_data["location"] == "header":
@@ -463,7 +538,10 @@ class PreProcessPlugin(YamlUpdatePlugin):
463
538
  headers_convert(yaml_data, ETAG_MATCH_DATA)
464
539
  elif role == "ifNoneMatch":
465
540
  headers_convert(yaml_data, ETAG_NONE_MATCH_DATA)
466
- if wire_name_lower in ["$host", "content-type", "accept"] and yaml_data["type"]["type"] == "constant":
541
+ if (
542
+ wire_name_lower in ["$host", "content-type", "accept"]
543
+ and yaml_data["type"]["type"] == "constant"
544
+ ):
467
545
  yaml_data["clientDefaultValue"] = yaml_data["type"]["value"]
468
546
 
469
547
  def update_operation(
@@ -473,24 +551,36 @@ class PreProcessPlugin(YamlUpdatePlugin):
473
551
  *,
474
552
  is_overload: bool = False,
475
553
  ) -> None:
476
- yaml_data["groupName"] = self.pad_reserved_words(yaml_data["groupName"], PadType.OPERATION_GROUP, yaml_data)
554
+ yaml_data["groupName"] = self.pad_reserved_words(
555
+ yaml_data["groupName"], PadType.OPERATION_GROUP, yaml_data
556
+ )
477
557
  yaml_data["groupName"] = to_snake_case(yaml_data["groupName"])
478
558
  if yaml_data.get("isExactName", False):
479
559
  # exact() client name: keep the operation name as-is without lowercasing,
480
560
  # snake-casing, or padding reserved words.
481
561
  if yaml_data.get("isLroInitialOperation") is True:
482
- yaml_data["name"] = "_" + extract_original_name(yaml_data["name"]) + "_initial"
562
+ yaml_data["name"] = (
563
+ "_" + extract_original_name(yaml_data["name"]) + "_initial"
564
+ )
483
565
  else:
484
566
  yaml_data["name"] = yaml_data["name"].lower()
485
567
  if yaml_data.get("isLroInitialOperation") is True:
486
568
  yaml_data["name"] = (
487
569
  "_"
488
- + self.pad_reserved_words(extract_original_name(yaml_data["name"]), PadType.METHOD, yaml_data)
570
+ + self.pad_reserved_words(
571
+ extract_original_name(yaml_data["name"]),
572
+ PadType.METHOD,
573
+ yaml_data,
574
+ )
489
575
  + "_initial"
490
576
  )
491
577
  else:
492
- yaml_data["name"] = self.pad_reserved_words(yaml_data["name"], PadType.METHOD, yaml_data)
493
- yaml_data["description"] = update_description(yaml_data["description"], yaml_data["name"])
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
+ )
494
584
  yaml_data["summary"] = update_description(yaml_data.get("summary", ""))
495
585
  body_parameter = yaml_data.get("bodyParameter")
496
586
  for parameter in yaml_data["parameters"]:
@@ -511,8 +601,12 @@ class PreProcessPlugin(YamlUpdatePlugin):
511
601
  def _update_lro_operation_helper(self, yaml_data: dict[str, Any]) -> None:
512
602
  for response in yaml_data.get("responses", []):
513
603
  response["discriminator"] = "lro"
514
- response["pollerSync"] = response.get("pollerSync") or "azure.core.polling.LROPoller"
515
- response["pollerAsync"] = response.get("pollerAsync") or "azure.core.polling.AsyncLROPoller"
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
+ )
516
610
  if not response.get("pollingMethodSync"):
517
611
  response["pollingMethodSync"] = (
518
612
  "azure.mgmt.core.polling.arm_polling.ARMPolling"
@@ -534,7 +628,9 @@ class PreProcessPlugin(YamlUpdatePlugin):
534
628
  item_type: Optional[dict[str, Any]] = None,
535
629
  ) -> None:
536
630
  self.update_lro_operation(code_model, yaml_data, is_overload=is_overload)
537
- self.update_paging_operation(code_model, yaml_data, is_overload=is_overload, item_type=item_type)
631
+ self.update_paging_operation(
632
+ code_model, yaml_data, is_overload=is_overload, item_type=item_type
633
+ )
538
634
  yaml_data["discriminator"] = "lropaging"
539
635
  for response in yaml_data.get("responses", []):
540
636
  response["discriminator"] = "lropaging"
@@ -557,12 +653,16 @@ class PreProcessPlugin(YamlUpdatePlugin):
557
653
  response["type"] = KNOWN_TYPES["binary"]
558
654
 
559
655
  self.update_operation(code_model, yaml_data, is_overload=is_overload)
560
- self.update_operation(code_model, yaml_data["initialOperation"], is_overload=is_overload)
656
+ self.update_operation(
657
+ code_model, yaml_data["initialOperation"], is_overload=is_overload
658
+ )
561
659
  convert_initial_operation_response_type(yaml_data["initialOperation"])
562
660
  self._update_lro_operation_helper(yaml_data)
563
661
  for overload in yaml_data.get("overloads", []):
564
662
  self._update_lro_operation_helper(overload)
565
- self.update_operation(code_model, overload["initialOperation"], is_overload=True)
663
+ self.update_operation(
664
+ code_model, overload["initialOperation"], is_overload=True
665
+ )
566
666
  convert_initial_operation_response_type(overload["initialOperation"])
567
667
 
568
668
  def update_paging_operation(
@@ -576,9 +676,13 @@ class PreProcessPlugin(YamlUpdatePlugin):
576
676
  item_type = item_type or yaml_data["itemType"]["elementType"]
577
677
  if yaml_data.get("nextOperation"):
578
678
  yaml_data["nextOperation"]["groupName"] = self.pad_reserved_words(
579
- yaml_data["nextOperation"]["groupName"], PadType.OPERATION_GROUP, yaml_data["nextOperation"]
679
+ yaml_data["nextOperation"]["groupName"],
680
+ PadType.OPERATION_GROUP,
681
+ yaml_data["nextOperation"],
682
+ )
683
+ yaml_data["nextOperation"]["groupName"] = to_snake_case(
684
+ yaml_data["nextOperation"]["groupName"]
580
685
  )
581
- yaml_data["nextOperation"]["groupName"] = to_snake_case(yaml_data["nextOperation"]["groupName"])
582
686
  for response in yaml_data["nextOperation"].get("responses", []):
583
687
  update_paging_response(response)
584
688
  response["itemType"] = item_type
@@ -586,9 +690,13 @@ class PreProcessPlugin(YamlUpdatePlugin):
586
690
  update_paging_response(response)
587
691
  response["itemType"] = item_type
588
692
  for overload in yaml_data.get("overloads", []):
589
- self.update_paging_operation(code_model, overload, is_overload=True, item_type=item_type)
693
+ self.update_paging_operation(
694
+ code_model, overload, is_overload=True, item_type=item_type
695
+ )
590
696
 
591
- def update_operation_groups(self, code_model: dict[str, Any], client: dict[str, Any]) -> None:
697
+ def update_operation_groups(
698
+ self, code_model: dict[str, Any], client: dict[str, Any]
699
+ ) -> None:
592
700
  operation_groups_yaml_data = client.get("operationGroups", [])
593
701
  for operation_group in operation_groups_yaml_data:
594
702
  operation_group["identifyName"] = self.pad_reserved_words(
@@ -596,11 +704,17 @@ class PreProcessPlugin(YamlUpdatePlugin):
596
704
  PadType.OPERATION_GROUP,
597
705
  operation_group,
598
706
  )
599
- operation_group["identifyName"] = to_snake_case(operation_group["identifyName"])
707
+ operation_group["identifyName"] = to_snake_case(
708
+ operation_group["identifyName"]
709
+ )
600
710
  operation_group["propertyName"] = self.pad_reserved_words(
601
- operation_group["propertyName"], PadType.OPERATION_GROUP, operation_group
711
+ operation_group["propertyName"],
712
+ PadType.OPERATION_GROUP,
713
+ operation_group,
714
+ )
715
+ operation_group["propertyName"] = to_snake_case(
716
+ operation_group["propertyName"]
602
717
  )
603
- operation_group["propertyName"] = to_snake_case(operation_group["propertyName"])
604
718
  operation_group["className"] = update_operation_group_class_name(
605
719
  client["name"], operation_group["className"]
606
720
  )
@@ -624,4 +738,6 @@ class PreProcessPlugin(YamlUpdatePlugin):
624
738
  if __name__ == "__main__":
625
739
  # TSP pipeline will call this
626
740
  args, unknown_args = parse_args()
627
- PreProcessPlugin(output_folder=args.output_folder, tsp_file=args.tsp_file, **unknown_args).process()
741
+ PreProcessPlugin(
742
+ output_folder=args.output_folder, tsp_file=args.tsp_file, **unknown_args
743
+ ).process()