@autorest/python 6.4.2 → 6.4.3

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.
@@ -83,6 +83,10 @@ class OperationBase( # pylint: disable=too-many-public-methods
83
83
  )
84
84
  self.include_documentation: bool = not self.is_lro_initial_operation
85
85
 
86
+ @property
87
+ def expose_stream_keyword(self) -> bool:
88
+ return self.yaml_data.get("exposeStreamKeyword", False)
89
+
86
90
  @property
87
91
  def operation_type(self) -> str:
88
92
  return "operation"
@@ -639,11 +639,17 @@ class _OperationSerializer(
639
639
 
640
640
  def make_pipeline_call(self, builder: OperationType) -> List[str]:
641
641
  type_ignore = self.async_mode and builder.group_name == "" # is in a mixin
642
+ stream_value = (
643
+ 'kwargs.pop("stream", False)'
644
+ if builder.expose_stream_keyword
645
+ else builder.has_stream_response
646
+ )
642
647
  return [
648
+ f"_stream = {stream_value}",
643
649
  f"pipeline_response: PipelineResponse = {self._call_method}self._client._pipeline.run( "
644
650
  + f"{'# type: ignore' if type_ignore else ''} # pylint: disable=protected-access",
645
651
  " request,",
646
- f" stream={builder.has_stream_response},",
652
+ " stream=_stream,",
647
653
  " **kwargs",
648
654
  ")",
649
655
  ]
@@ -669,6 +675,11 @@ class _OperationSerializer(
669
675
 
670
676
  def param_description(self, builder: OperationType) -> List[str]:
671
677
  description_list = super().param_description(builder)
678
+ if builder.expose_stream_keyword:
679
+ description_list.append(
680
+ ":keyword bool stream: Whether to stream the response of this operation. "
681
+ "Defaults to False. You will have to context manage the returned stream."
682
+ )
672
683
  if not self.code_model.options["version_tolerant"]:
673
684
  description_list.append(
674
685
  ":keyword callable cls: A custom type or function that will be passed the direct response"
@@ -1014,6 +1025,7 @@ class _OperationSerializer(
1014
1025
 
1015
1026
  def response_headers_and_deserialization(
1016
1027
  self,
1028
+ builder: OperationType,
1017
1029
  response: Response,
1018
1030
  ) -> List[str]:
1019
1031
  retval: List[str] = [
@@ -1025,8 +1037,9 @@ class _OperationSerializer(
1025
1037
  ]
1026
1038
  if response.headers:
1027
1039
  retval.append("")
1040
+ deserialize_code: List[str] = []
1028
1041
  if response.is_stream_response:
1029
- retval.append(
1042
+ deserialize_code.append(
1030
1043
  "deserialized = {}".format(
1031
1044
  "response.iter_bytes()"
1032
1045
  if self.code_model.options["version_tolerant"]
@@ -1035,11 +1048,11 @@ class _OperationSerializer(
1035
1048
  )
1036
1049
  elif response.type:
1037
1050
  if self.code_model.options["models_mode"] == "msrest":
1038
- retval.append(
1051
+ deserialize_code.append(
1039
1052
  f"deserialized = self._deserialize('{response.serialization_type}', pipeline_response)"
1040
1053
  )
1041
1054
  elif self.code_model.options["models_mode"] == "dpg":
1042
- retval.append(
1055
+ deserialize_code.append(
1043
1056
  f"deserialized = _deserialize({response.type.type_annotation(is_operation_file=True)}"
1044
1057
  ", response.json())"
1045
1058
  )
@@ -1049,10 +1062,17 @@ class _OperationSerializer(
1049
1062
  if response.type.is_xml
1050
1063
  else "response.json()"
1051
1064
  )
1052
- retval.append("if response.content:")
1053
- retval.append(f" deserialized = {deserialized_value}")
1054
- retval.append("else:")
1055
- retval.append(" deserialized = None")
1065
+ deserialize_code.append("if response.content:")
1066
+ deserialize_code.append(f" deserialized = {deserialized_value}")
1067
+ deserialize_code.append("else:")
1068
+ deserialize_code.append(" deserialized = None")
1069
+ if builder.expose_stream_keyword:
1070
+ retval.append("if _stream:")
1071
+ retval.append(" deserialized = response.iter_bytes()")
1072
+ retval.append("else:")
1073
+ retval.extend([f" {dc}" for dc in deserialize_code])
1074
+ else:
1075
+ retval.extend(deserialize_code)
1056
1076
  return retval
1057
1077
 
1058
1078
  def handle_error_response(self, builder: OperationType) -> List[str]:
@@ -1106,14 +1126,16 @@ class _OperationSerializer(
1106
1126
  [
1107
1127
  f" {line}"
1108
1128
  for line in self.response_headers_and_deserialization(
1109
- response
1129
+ builder, response
1110
1130
  )
1111
1131
  ]
1112
1132
  )
1113
1133
  retval.append("")
1114
1134
  else:
1115
1135
  retval.extend(
1116
- self.response_headers_and_deserialization(builder.responses[0])
1136
+ self.response_headers_and_deserialization(
1137
+ builder, builder.responses[0]
1138
+ )
1117
1139
  )
1118
1140
  retval.append("")
1119
1141
  type_ignore = (
@@ -1559,7 +1581,7 @@ class _LROOperationSerializer(_OperationSerializer[LROOperationType]):
1559
1581
  [
1560
1582
  f" {line}"
1561
1583
  for line in self.response_headers_and_deserialization(
1562
- builder.lro_response
1584
+ builder, builder.lro_response
1563
1585
  )
1564
1586
  ]
1565
1587
  )
@@ -108,8 +108,8 @@ class FileImportSerializer:
108
108
  "typing", "TYPE_CHECKING", ImportType.STDLIB
109
109
  )
110
110
 
111
- def _get_typing_definitions(self) -> str:
112
- def declare_defintion(
111
+ def get_typing_definitions(self) -> str:
112
+ def declare_definition(
113
113
  type_name: str, type_definition: TypeDefinition
114
114
  ) -> List[str]:
115
115
  ret: List[str] = []
@@ -125,7 +125,7 @@ class FileImportSerializer:
125
125
  return ""
126
126
  declarations: List[str] = [""]
127
127
  for type_name, value in self.file_import.type_definitions.items():
128
- declarations.extend(declare_defintion(type_name, value))
128
+ declarations.extend(declare_definition(type_name, value))
129
129
  return "\n".join(declarations)
130
130
 
131
131
  def __str__(self) -> str:
@@ -151,4 +151,4 @@ class FileImportSerializer:
151
151
  typing_imports += "\n\n ".join(
152
152
  _get_import_clauses(typing_imports_list, "\n ")
153
153
  )
154
- return regular_imports + typing_imports + self._get_typing_definitions()
154
+ return regular_imports + typing_imports + self.get_typing_definitions()
@@ -16,6 +16,7 @@ from ..models import (
16
16
  CodeModel,
17
17
  )
18
18
  from .builder_serializer import get_operation_serializer
19
+ from .import_serializer import FileImportSerializer
19
20
 
20
21
 
21
22
  def _to_string(data: Union[Tuple[Any], List[Any], str]) -> str:
@@ -91,6 +92,24 @@ def _mixin_imports(
91
92
  ), _json_serialize_imports(async_mixin_imports.to_dict())
92
93
 
93
94
 
95
+ def _mixin_typing_definitions(
96
+ mixin_operation_group: Optional[OperationGroup],
97
+ ) -> Tuple[Optional[str], Optional[str]]:
98
+ if not mixin_operation_group:
99
+ return None, None
100
+
101
+ sync_mixin_imports = mixin_operation_group.imports_for_multiapi(async_mode=False)
102
+ async_mixin_imports = mixin_operation_group.imports_for_multiapi(async_mode=True)
103
+ sync_mixin_typing_definitions = FileImportSerializer(
104
+ sync_mixin_imports, False
105
+ ).get_typing_definitions()
106
+ async_mixin_typing_definitions = FileImportSerializer(
107
+ async_mixin_imports, True
108
+ ).get_typing_definitions()
109
+
110
+ return sync_mixin_typing_definitions, async_mixin_typing_definitions
111
+
112
+
94
113
  class MetadataSerializer:
95
114
  def __init__(self, code_model: CodeModel, env: Environment) -> None:
96
115
  self.code_model = code_model
@@ -141,6 +160,10 @@ class MetadataSerializer:
141
160
  mixin_operation_group.operations if mixin_operation_group else []
142
161
  )
143
162
  sync_mixin_imports, async_mixin_imports = _mixin_imports(mixin_operation_group)
163
+ (
164
+ sync_mixin_typing_definitions,
165
+ async_mixin_typing_definitions,
166
+ ) = _mixin_typing_definitions(mixin_operation_group)
144
167
 
145
168
  chosen_version, total_api_version_list = self._choose_api_version()
146
169
 
@@ -161,6 +184,8 @@ class MetadataSerializer:
161
184
  str=str,
162
185
  sync_mixin_imports=sync_mixin_imports,
163
186
  async_mixin_imports=async_mixin_imports,
187
+ sync_mixin_typing_definitions=sync_mixin_typing_definitions,
188
+ async_mixin_typing_definitions=async_mixin_typing_definitions,
164
189
  sync_client_imports=_json_serialize_imports(
165
190
  self.client.imports_for_multiapi(async_mode=False).to_dict()
166
191
  ),
@@ -115,6 +115,8 @@
115
115
  "operation_mixins": {
116
116
  "sync_imports": {{ str(sync_mixin_imports) | tojson }},
117
117
  "async_imports": {{ str(async_mixin_imports) | tojson }},
118
+ "sync_mixin_typing_definitions": {{ str(sync_mixin_typing_definitions) | tojson }},
119
+ "async_mixin_typing_definitions": {{ str(async_mixin_typing_definitions) | tojson }},
118
120
  "operations": {
119
121
  {% for operation in mixin_operations %}
120
122
  {{ operation.name | tojson }} : {
@@ -31,6 +31,20 @@ class OperationMixinGroup:
31
31
  imports.merge(current_version_imports)
32
32
  return imports
33
33
 
34
+ def typing_definitions(self, async_mode: bool) -> str:
35
+ key = (
36
+ "sync_mixin_typing_definitions"
37
+ if async_mode
38
+ else "async_mixin_typing_definitions"
39
+ )
40
+ origin = "".join(
41
+ [
42
+ metadata_json.get("operation_mixins", {}).get(key, "")
43
+ for metadata_json in self.version_path_to_metadata.values()
44
+ ]
45
+ )
46
+ return "\n".join(set(origin.split("\n")))
47
+
34
48
  def _use_metadata_of_default_api_version(
35
49
  self, mixin_operations: List[MixinOperation]
36
50
  ) -> List[MixinOperation]:
@@ -101,7 +101,8 @@ class MultiAPISerializer(ReaderAndWriter): # pylint: disable=abstract-method
101
101
  # serialize mixins
102
102
  if code_model.operation_mixin_group.mixin_operations:
103
103
  imports = FileImportSerializer(
104
- code_model.operation_mixin_group.imports(async_mode)
104
+ code_model.operation_mixin_group.imports(async_mode),
105
+ code_model.operation_mixin_group.typing_definitions(async_mode),
105
106
  )
106
107
  self.write_file(
107
108
  _get_file_path("_operations_mixin", async_mode),
@@ -135,8 +135,9 @@ def _get_import_clauses(
135
135
 
136
136
 
137
137
  class FileImportSerializer:
138
- def __init__(self, file_import: FileImport) -> None:
138
+ def __init__(self, file_import: FileImport, typing_definitions: str = "") -> None:
139
139
  self._file_import = file_import
140
+ self._typing_definitions = typing_definitions
140
141
 
141
142
  def _switch_typing_section_key(self, new_key: TypingSection):
142
143
  switched_dictionary = {}
@@ -193,4 +194,4 @@ class FileImportSerializer:
193
194
  _get_import_clauses(typing_imports_dict, "\n ")
194
195
  )
195
196
 
196
- return regular_imports + typing_imports
197
+ return regular_imports + typing_imports + self._typing_definitions
@@ -10,11 +10,11 @@ from typing import Callable, Dict, Any, List, Optional
10
10
 
11
11
  from .._utils import to_snake_case
12
12
  from .helpers import (
13
- pad_reserved_words,
14
13
  add_redefined_builtin_info,
15
14
  pad_builtin_namespaces,
15
+ pad_special_chars,
16
16
  )
17
- from .python_mappings import PadType
17
+ from .python_mappings import CADL_RESERVED_WORDS, RESERVED_WORDS, PadType
18
18
 
19
19
  from .. import YamlUpdatePlugin, YamlUpdatePluginAutorest
20
20
  from .._utils import parse_args, get_body_type_for_description, JSON_REGEXP, KNOWN_TYPES
@@ -168,51 +168,6 @@ def update_operation_group_class_name(
168
168
  return class_name + "Operations"
169
169
 
170
170
 
171
- def update_parameter(yaml_data: Dict[str, Any]) -> None:
172
- yaml_data["description"] = update_description(yaml_data["description"])
173
- if not (
174
- yaml_data["location"] == "header"
175
- and yaml_data["clientName"] in ("content_type", "accept")
176
- ):
177
- yaml_data["clientName"] = pad_reserved_words(
178
- yaml_data["clientName"].lower(), PadType.PARAMETER
179
- )
180
- if yaml_data.get("propertyToParameterName"):
181
- # need to create a new one with padded keys and values
182
- yaml_data["propertyToParameterName"] = {
183
- pad_reserved_words(prop, PadType.PROPERTY)
184
- .lower(): pad_reserved_words(param_name, PadType.PARAMETER)
185
- .lower()
186
- for prop, param_name in yaml_data["propertyToParameterName"].items()
187
- }
188
-
189
-
190
- def update_types(yaml_data: List[Dict[str, Any]]) -> None:
191
- for type in yaml_data:
192
- for property in type.get("properties", []):
193
- property["description"] = update_description(property["description"])
194
- property["clientName"] = pad_reserved_words(
195
- property["clientName"].lower(), PadType.PROPERTY
196
- )
197
- add_redefined_builtin_info(property["clientName"], property)
198
- if type.get("name"):
199
- type["description"] = update_description(type["description"], type["name"])
200
- type["snakeCaseName"] = to_snake_case(type["name"])
201
-
202
-
203
- def update_client(yaml_data: Dict[str, Any]) -> None:
204
- yaml_data["description"] = update_description(
205
- yaml_data["description"], default_description=yaml_data["name"]
206
- )
207
- yaml_data["legacyFilename"] = to_snake_case(yaml_data["name"].replace(" ", "_"))
208
- for parameter in yaml_data["parameters"]:
209
- update_parameter(parameter)
210
- prop_name = yaml_data["name"]
211
- if prop_name.endswith("Client"):
212
- prop_name = prop_name[: len(prop_name) - len("Client")]
213
- yaml_data["builderPadName"] = to_snake_case(prop_name)
214
-
215
-
216
171
  def update_paging_response(yaml_data: Dict[str, Any]) -> None:
217
172
  yaml_data["discriminator"] = "paging"
218
173
  yaml_data["pagerSync"] = yaml_data.get("pagerSync") or "azure.core.paging.ItemPaged"
@@ -230,9 +185,55 @@ class PreProcessPlugin(YamlUpdatePlugin): # pylint: disable=abstract-method
230
185
 
231
186
  @property
232
187
  def models_mode(self) -> Optional[str]:
233
- return self.options.get(
234
- "models-mode", "dpg" if self.options.get("cadl_file") else None
188
+ return self.options.get("models-mode", "dpg" if self.is_cadl else None)
189
+
190
+ @property
191
+ def is_cadl(self) -> bool:
192
+ return self.options.get("cadl_file", False)
193
+
194
+ def pad_reserved_words(self, name: str, pad_type: PadType):
195
+ # we want to pad hidden variables as well
196
+ if not name:
197
+ # we'll pass in empty operation groups sometime etc.
198
+ return name
199
+
200
+ if self.is_cadl:
201
+ reserved_words = copy.copy(CADL_RESERVED_WORDS)
202
+ reserved_words.update(RESERVED_WORDS)
203
+ else:
204
+ reserved_words = RESERVED_WORDS
205
+ name = pad_special_chars(name)
206
+ name_prefix = "_" if name[0] == "_" else ""
207
+ name = name[1:] if name[0] == "_" else name
208
+ if name.lower() in reserved_words[pad_type]:
209
+ return name_prefix + name + pad_type
210
+ return name_prefix + name
211
+
212
+ def update_types(self, yaml_data: List[Dict[str, Any]]) -> None:
213
+ for type in yaml_data:
214
+ for property in type.get("properties", []):
215
+ property["description"] = update_description(property["description"])
216
+ property["clientName"] = self.pad_reserved_words(
217
+ property["clientName"].lower(), PadType.PROPERTY
218
+ )
219
+ add_redefined_builtin_info(property["clientName"], property)
220
+ if type.get("name"):
221
+ type["description"] = update_description(
222
+ type["description"], type["name"]
223
+ )
224
+ type["snakeCaseName"] = to_snake_case(type["name"])
225
+
226
+ def update_client(self, yaml_data: Dict[str, Any]) -> None:
227
+ yaml_data["description"] = update_description(
228
+ yaml_data["description"], default_description=yaml_data["name"]
235
229
  )
230
+ yaml_data["legacyFilename"] = to_snake_case(yaml_data["name"].replace(" ", "_"))
231
+ for parameter in yaml_data["parameters"]:
232
+ self.update_parameter(parameter)
233
+ prop_name = yaml_data["name"]
234
+ if prop_name.endswith("Client"):
235
+ prop_name = prop_name[: len(prop_name) - len("Client")]
236
+ yaml_data["builderPadName"] = to_snake_case(prop_name)
236
237
 
237
238
  def get_operation_updater(
238
239
  self, yaml_data: Dict[str, Any]
@@ -245,6 +246,24 @@ class PreProcessPlugin(YamlUpdatePlugin): # pylint: disable=abstract-method
245
246
  return self.update_paging_operation
246
247
  return self.update_operation
247
248
 
249
+ def update_parameter(self, yaml_data: Dict[str, Any]) -> None:
250
+ yaml_data["description"] = update_description(yaml_data["description"])
251
+ if not (
252
+ yaml_data["location"] == "header"
253
+ and yaml_data["clientName"] in ("content_type", "accept")
254
+ ):
255
+ yaml_data["clientName"] = self.pad_reserved_words(
256
+ yaml_data["clientName"].lower(), PadType.PARAMETER
257
+ )
258
+ if yaml_data.get("propertyToParameterName"):
259
+ # need to create a new one with padded keys and values
260
+ yaml_data["propertyToParameterName"] = {
261
+ self.pad_reserved_words(prop, PadType.PROPERTY)
262
+ .lower(): self.pad_reserved_words(param_name, PadType.PARAMETER)
263
+ .lower()
264
+ for prop, param_name in yaml_data["propertyToParameterName"].items()
265
+ }
266
+
248
267
  def update_operation(
249
268
  self,
250
269
  code_model: Dict[str, Any],
@@ -252,23 +271,23 @@ class PreProcessPlugin(YamlUpdatePlugin): # pylint: disable=abstract-method
252
271
  *,
253
272
  is_overload: bool = False,
254
273
  ) -> None:
255
- yaml_data["groupName"] = pad_reserved_words(
274
+ yaml_data["groupName"] = self.pad_reserved_words(
256
275
  yaml_data["groupName"], PadType.OPERATION_GROUP
257
276
  )
258
277
  yaml_data["groupName"] = to_snake_case(yaml_data["groupName"])
259
278
  yaml_data["name"] = yaml_data["name"].lower()
260
- yaml_data["name"] = pad_reserved_words(yaml_data["name"], PadType.METHOD)
279
+ yaml_data["name"] = self.pad_reserved_words(yaml_data["name"], PadType.METHOD)
261
280
  yaml_data["description"] = update_description(
262
281
  yaml_data["description"], yaml_data["name"]
263
282
  )
264
283
  yaml_data["summary"] = update_description(yaml_data.get("summary", ""))
265
284
  body_parameter = yaml_data.get("bodyParameter")
266
285
  for parameter in yaml_data["parameters"]:
267
- update_parameter(parameter)
286
+ self.update_parameter(parameter)
268
287
  if yaml_data.get("bodyParameter"):
269
- update_parameter(yaml_data["bodyParameter"])
288
+ self.update_parameter(yaml_data["bodyParameter"])
270
289
  for entry in yaml_data["bodyParameter"].get("entries", []):
271
- update_parameter(entry)
290
+ self.update_parameter(entry)
272
291
  for overload in yaml_data.get("overloads", []):
273
292
  self.update_operation(code_model, overload, is_overload=True)
274
293
  for response in yaml_data.get("responses", []):
@@ -360,7 +379,7 @@ class PreProcessPlugin(YamlUpdatePlugin): # pylint: disable=abstract-method
360
379
  if yaml_data.get("nextOperation"):
361
380
  if self.version_tolerant:
362
381
  _remove_paging_maxpagesize(yaml_data["nextOperation"])
363
- yaml_data["nextOperation"]["groupName"] = pad_reserved_words(
382
+ yaml_data["nextOperation"]["groupName"] = self.pad_reserved_words(
364
383
  yaml_data["nextOperation"]["groupName"], PadType.OPERATION_GROUP
365
384
  )
366
385
  yaml_data["nextOperation"]["groupName"] = to_snake_case(
@@ -381,7 +400,7 @@ class PreProcessPlugin(YamlUpdatePlugin): # pylint: disable=abstract-method
381
400
  operation_groups_yaml_data = client["operationGroups"]
382
401
  for operation_group in operation_groups_yaml_data:
383
402
  operation_group["clientName"] = client["name"]
384
- operation_group["propertyName"] = pad_reserved_words(
403
+ operation_group["propertyName"] = self.pad_reserved_words(
385
404
  operation_group["propertyName"], PadType.OPERATION_GROUP
386
405
  )
387
406
  operation_group["propertyName"] = to_snake_case(
@@ -395,13 +414,13 @@ class PreProcessPlugin(YamlUpdatePlugin): # pylint: disable=abstract-method
395
414
 
396
415
  def update_yaml(self, yaml_data: Dict[str, Any]) -> None:
397
416
  """Convert in place the YAML str."""
398
- update_types(yaml_data["types"])
417
+ self.update_types(yaml_data["types"])
399
418
  for client in yaml_data["clients"]:
400
- update_client(client)
419
+ self.update_client(client)
401
420
  self.update_operation_groups(yaml_data, client)
402
421
  for clients in yaml_data["subnamespaceToClients"].values():
403
422
  for client in clients:
404
- update_client(client)
423
+ self.update_client(client)
405
424
  self.update_operation_groups(yaml_data, client)
406
425
  if yaml_data.get("namespace"):
407
426
  yaml_data["namespace"] = pad_builtin_namespaces(yaml_data["namespace"])
@@ -6,26 +6,11 @@
6
6
  import re
7
7
  from typing import Any, Dict
8
8
  from .python_mappings import (
9
- PadType,
10
- RESERVED_WORDS,
11
9
  REDEFINED_BUILTINS,
12
10
  BUILTIN_PACKAGES,
13
11
  )
14
12
 
15
13
 
16
- def pad_reserved_words(name: str, pad_type: PadType):
17
- # we want to pad hidden variables as well
18
- if not name:
19
- # we'll pass in empty operation groups sometime etc.
20
- return name
21
- name = pad_special_chars(name)
22
- name_prefix = "_" if name[0] == "_" else ""
23
- name = name[1:] if name[0] == "_" else name
24
- if name.lower() in RESERVED_WORDS[pad_type]:
25
- return name_prefix + name + pad_type
26
- return name_prefix + name
27
-
28
-
29
14
  def add_redefined_builtin_info(name: str, yaml_data: Dict[str, Any]) -> None:
30
15
  if name in REDEFINED_BUILTINS:
31
16
  yaml_data["pylintDisable"] = "redefined-builtin"
@@ -168,6 +168,8 @@ RESERVED_WORDS = {
168
168
  PadType.OPERATION_GROUP: [*_always_reserved],
169
169
  }
170
170
 
171
+ CADL_RESERVED_WORDS = {PadType.PARAMETER: ["stream"]}
172
+
171
173
  REDEFINED_BUILTINS = [ # we don't pad, but we need to do lint ignores
172
174
  "id",
173
175
  "min",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@autorest/python",
3
- "version": "6.4.2",
3
+ "version": "6.4.3",
4
4
  "description": "The Python extension for generators in AutoRest.",
5
5
  "main": "index.js",
6
6
  "repository": {
package/requirements.txt CHANGED
@@ -7,6 +7,6 @@ m2r2==0.3.3
7
7
  MarkupSafe==2.1.2
8
8
  mistune==0.8.4
9
9
  pathspec==0.11.0
10
- platformdirs==2.6.2
10
+ platformdirs==3.1.0
11
11
  PyYAML==6.0
12
12
  tomli==2.0.1