@typespec/http-client-python 0.7.1 → 0.8.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/code-model.js +6 -6
- package/dist/emitter/code-model.js.map +1 -1
- package/dist/emitter/emitter.d.ts.map +1 -1
- package/dist/emitter/emitter.js +57 -54
- package/dist/emitter/emitter.js.map +1 -1
- package/dist/emitter/external-process.js +3 -3
- package/dist/emitter/external-process.js.map +1 -1
- package/dist/emitter/http.d.ts.map +1 -1
- package/dist/emitter/http.js +81 -23
- package/dist/emitter/http.js.map +1 -1
- package/dist/emitter/lib.d.ts +37 -1
- package/dist/emitter/lib.d.ts.map +1 -1
- package/dist/emitter/lib.js +24 -0
- package/dist/emitter/lib.js.map +1 -1
- package/dist/emitter/types.js +3 -3
- package/dist/emitter/types.js.map +1 -1
- package/dist/emitter/utils.d.ts +4 -2
- package/dist/emitter/utils.d.ts.map +1 -1
- package/dist/emitter/utils.js +21 -2
- package/dist/emitter/utils.js.map +1 -1
- package/emitter/src/code-model.ts +8 -8
- package/emitter/src/emitter.ts +57 -53
- package/emitter/src/external-process.ts +3 -3
- package/emitter/src/http.ts +113 -26
- package/emitter/src/lib.ts +24 -0
- package/emitter/src/types.ts +3 -3
- package/emitter/src/utils.ts +36 -1
- package/emitter/temp/tsconfig.tsbuildinfo +1 -1
- package/eng/scripts/setup/__pycache__/venvtools.cpython-38.pyc +0 -0
- package/eng/scripts/setup/run_tsp.py +2 -2
- package/generator/build/lib/pygen/__init__.py +3 -3
- package/generator/build/lib/pygen/black.py +2 -2
- package/generator/build/lib/pygen/codegen/__init__.py +5 -5
- package/generator/build/lib/pygen/codegen/models/paging_operation.py +11 -2
- package/generator/build/lib/pygen/codegen/models/parameter.py +2 -1
- package/generator/build/lib/pygen/codegen/models/request_builder_parameter.py +2 -0
- package/generator/build/lib/pygen/codegen/models/response.py +1 -1
- package/generator/build/lib/pygen/codegen/serializers/builder_serializer.py +47 -25
- package/generator/build/lib/pygen/preprocess/__init__.py +10 -12
- package/generator/build/lib/pygen/preprocess/python_mappings.py +1 -1
- package/generator/build/lib/pygen/utils.py +5 -5
- package/generator/component-detection-pip-report.json +7 -6
- package/generator/dist/pygen-0.1.0-py3-none-any.whl +0 -0
- package/generator/pygen/__init__.py +3 -3
- package/generator/pygen/black.py +2 -2
- package/generator/pygen/codegen/__init__.py +5 -5
- package/generator/pygen/codegen/models/paging_operation.py +11 -2
- package/generator/pygen/codegen/models/parameter.py +2 -1
- package/generator/pygen/codegen/models/request_builder_parameter.py +2 -0
- package/generator/pygen/codegen/models/response.py +1 -1
- package/generator/pygen/codegen/serializers/builder_serializer.py +47 -25
- package/generator/pygen/preprocess/__init__.py +10 -12
- package/generator/pygen/preprocess/python_mappings.py +1 -1
- package/generator/pygen/utils.py +5 -5
- package/generator/test/generic_mock_api_tests/asynctests/test_payload_pageable_async.py +75 -0
- package/generator/test/generic_mock_api_tests/test_payload_pageable.py +54 -0
- package/package.json +1 -1
- package/generator/test/unbranded/mock_api_tests/cadl-ranch-config.yaml +0 -27
|
@@ -79,7 +79,7 @@ class OptionsRetriever:
|
|
|
79
79
|
@property
|
|
80
80
|
def _models_mode_default(self) -> str:
|
|
81
81
|
models_mode_default = "none" if self.low_level_client or self.version_tolerant else "msrest"
|
|
82
|
-
if self.options.get("
|
|
82
|
+
if self.options.get("tsp_file") is not None:
|
|
83
83
|
models_mode_default = "dpg"
|
|
84
84
|
return models_mode_default
|
|
85
85
|
|
|
@@ -322,8 +322,8 @@ class CodeGenerator(Plugin):
|
|
|
322
322
|
return {f: getattr(self.options_retriever, f) for f in flags}
|
|
323
323
|
|
|
324
324
|
def get_yaml(self) -> Dict[str, Any]:
|
|
325
|
-
#
|
|
326
|
-
with open(self.options["
|
|
325
|
+
# tsp file doesn't have to be relative to output folder
|
|
326
|
+
with open(self.options["tsp_file"], "r", encoding="utf-8-sig") as fd:
|
|
327
327
|
return yaml.safe_load(fd.read())
|
|
328
328
|
|
|
329
329
|
def get_serializer(self, code_model: CodeModel):
|
|
@@ -350,10 +350,10 @@ class CodeGenerator(Plugin):
|
|
|
350
350
|
|
|
351
351
|
|
|
352
352
|
if __name__ == "__main__":
|
|
353
|
-
#
|
|
353
|
+
# TSP pipeline will call this
|
|
354
354
|
parsed_args, unknown_args = parse_args()
|
|
355
355
|
CodeGenerator(
|
|
356
356
|
output_folder=parsed_args.output_folder,
|
|
357
|
-
|
|
357
|
+
tsp_file=parsed_args.tsp_file,
|
|
358
358
|
**unknown_args,
|
|
359
359
|
).process()
|
|
@@ -58,6 +58,15 @@ class PagingOperationBase(OperationBase[PagingResponseType]):
|
|
|
58
58
|
self.override_success_response_to_200 = override_success_response_to_200
|
|
59
59
|
self.pager_sync: str = yaml_data.get("pagerSync") or f"{self.code_model.core_library}.paging.ItemPaged"
|
|
60
60
|
self.pager_async: str = yaml_data.get("pagerAsync") or f"{self.code_model.core_library}.paging.AsyncItemPaged"
|
|
61
|
+
self.continuation_token: Dict[str, Any] = yaml_data.get("continuationToken", {})
|
|
62
|
+
|
|
63
|
+
@property
|
|
64
|
+
def has_continuation_token(self) -> bool:
|
|
65
|
+
return bool(self.continuation_token.get("input") and self.continuation_token.get("output"))
|
|
66
|
+
|
|
67
|
+
@property
|
|
68
|
+
def next_variable_name(self) -> str:
|
|
69
|
+
return "_continuation_token" if self.has_continuation_token else "next_link"
|
|
61
70
|
|
|
62
71
|
def _get_attr_name(self, wire_name: str) -> str:
|
|
63
72
|
response_type = self.responses[0].type
|
|
@@ -74,8 +83,8 @@ class PagingOperationBase(OperationBase[PagingResponseType]):
|
|
|
74
83
|
return self.responses[0].get_pager(async_mode)
|
|
75
84
|
|
|
76
85
|
@property
|
|
77
|
-
def
|
|
78
|
-
wire_name = self.yaml_data.get("
|
|
86
|
+
def next_link_name(self) -> Optional[str]:
|
|
87
|
+
wire_name = self.yaml_data.get("nextLinkName")
|
|
79
88
|
if not wire_name:
|
|
80
89
|
# That's an ok scenario, it just means no next page possible
|
|
81
90
|
return None
|
|
@@ -85,6 +85,7 @@ class _ParameterBase(BaseModel, abc.ABC): # pylint: disable=too-many-instance-a
|
|
|
85
85
|
self.in_overload: bool = self.yaml_data.get("inOverload", False)
|
|
86
86
|
self.default_to_unset_sentinel: bool = self.yaml_data.get("defaultToUnsetSentinel", False)
|
|
87
87
|
self.hide_in_method: bool = self.yaml_data.get("hideInMethod", False)
|
|
88
|
+
self.is_continuation_token: bool = bool(self.yaml_data.get("isContinuationToken"))
|
|
88
89
|
|
|
89
90
|
def get_declaration(self, value: Any = None) -> Any:
|
|
90
91
|
return self.type.get_declaration(value)
|
|
@@ -314,7 +315,7 @@ class Parameter(_ParameterBase):
|
|
|
314
315
|
def hide_in_operation_signature(self) -> bool:
|
|
315
316
|
if self.code_model.options["version_tolerant"] and self.client_name == "maxpagesize":
|
|
316
317
|
return True
|
|
317
|
-
return
|
|
318
|
+
return self.is_continuation_token
|
|
318
319
|
|
|
319
320
|
@property
|
|
320
321
|
def in_method_signature(self) -> bool:
|
|
@@ -63,7 +63,7 @@ class Response(BaseModel):
|
|
|
63
63
|
def result_property(self) -> str:
|
|
64
64
|
field = self.yaml_data.get("resultProperty")
|
|
65
65
|
if field:
|
|
66
|
-
return f'.get("{field}")'
|
|
66
|
+
return "".join([f'.get("{field}", {{}})' for field in field.split(".")])
|
|
67
67
|
return ""
|
|
68
68
|
|
|
69
69
|
def get_polymorphic_subtypes(self, polymorphic_subtypes: List["ModelType"]) -> None:
|
|
@@ -630,7 +630,7 @@ class _OperationSerializer(_BuilderBaseSerializer[OperationType]):
|
|
|
630
630
|
operation_name=f"('{builder.name}')" if builder.group_name == "" else "",
|
|
631
631
|
)
|
|
632
632
|
for p in builder.parameters.parameters:
|
|
633
|
-
if p.hide_in_operation_signature:
|
|
633
|
+
if p.hide_in_operation_signature and not p.is_continuation_token:
|
|
634
634
|
kwargs.append(f'{p.client_name} = kwargs.pop("{p.client_name}", None)')
|
|
635
635
|
cls_annotation = builder.cls_type_annotation(
|
|
636
636
|
async_mode=self.async_mode, serialize_namespace=self.serialize_namespace
|
|
@@ -1001,9 +1001,7 @@ class _OperationSerializer(_BuilderBaseSerializer[OperationType]):
|
|
|
1001
1001
|
retval.extend(deserialize_code)
|
|
1002
1002
|
return retval
|
|
1003
1003
|
|
|
1004
|
-
def handle_error_response(
|
|
1005
|
-
self, builder: OperationType
|
|
1006
|
-
) -> List[str]:
|
|
1004
|
+
def handle_error_response(self, builder: OperationType) -> List[str]:
|
|
1007
1005
|
async_await = "await " if self.async_mode else ""
|
|
1008
1006
|
retval = [f"if response.status_code not in {str(builder.success_status_codes)}:"]
|
|
1009
1007
|
response_read = [
|
|
@@ -1290,16 +1288,20 @@ class _PagingOperationSerializer(_OperationSerializer[PagingOperationType]):
|
|
|
1290
1288
|
|
|
1291
1289
|
def _prepare_request_callback(self, builder: PagingOperationType) -> List[str]:
|
|
1292
1290
|
retval = self._initialize_overloads(builder)
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
retval.append("")
|
|
1297
|
-
retval.append(" else:")
|
|
1298
|
-
retval.extend([f" {line}" for line in self.call_next_link_request_builder(builder)])
|
|
1299
|
-
if not builder.next_request_builder and self.code_model.is_legacy:
|
|
1300
|
-
retval.append(' _request.method = "GET"')
|
|
1291
|
+
if builder.has_continuation_token:
|
|
1292
|
+
retval.append(f"def prepare_request({builder.next_variable_name}=None):")
|
|
1293
|
+
retval.extend([f" {line}" for line in self.call_request_builder(builder, is_paging=True)])
|
|
1301
1294
|
else:
|
|
1295
|
+
retval.append("def prepare_request(next_link=None):")
|
|
1296
|
+
retval.append(" if not next_link:")
|
|
1297
|
+
retval.extend([f" {line}" for line in self.call_request_builder(builder, is_paging=True)])
|
|
1302
1298
|
retval.append("")
|
|
1299
|
+
retval.append(" else:")
|
|
1300
|
+
retval.extend([f" {line}" for line in self.call_next_link_request_builder(builder)])
|
|
1301
|
+
if not builder.next_request_builder and self.code_model.is_legacy:
|
|
1302
|
+
retval.append(' _request.method = "GET"')
|
|
1303
|
+
else:
|
|
1304
|
+
retval.append("")
|
|
1303
1305
|
retval.append(" return _request")
|
|
1304
1306
|
return retval
|
|
1305
1307
|
|
|
@@ -1307,7 +1309,7 @@ class _PagingOperationSerializer(_OperationSerializer[PagingOperationType]):
|
|
|
1307
1309
|
def _function_def(self) -> str:
|
|
1308
1310
|
return "def"
|
|
1309
1311
|
|
|
1310
|
-
def _extract_data_callback(self, builder: PagingOperationType) -> List[str]:
|
|
1312
|
+
def _extract_data_callback(self, builder: PagingOperationType) -> List[str]: # pylint: disable=too-many-statements
|
|
1311
1313
|
retval = [f"{'async ' if self.async_mode else ''}def extract_data(pipeline_response):"]
|
|
1312
1314
|
response = builder.responses[0]
|
|
1313
1315
|
deserialized = "pipeline_response.http_response.json()"
|
|
@@ -1328,7 +1330,13 @@ class _PagingOperationSerializer(_OperationSerializer[PagingOperationType]):
|
|
|
1328
1330
|
else:
|
|
1329
1331
|
retval.append(f" deserialized = {deserialized}")
|
|
1330
1332
|
item_name = builder.item_name
|
|
1331
|
-
|
|
1333
|
+
if self.code_model.options["models_mode"] == "msrest":
|
|
1334
|
+
access = f".{item_name}"
|
|
1335
|
+
else:
|
|
1336
|
+
item_name_array = item_name.split(".")
|
|
1337
|
+
access = (
|
|
1338
|
+
"".join([f'.get("{i}", {{}})' for i in item_name_array[:-1]]) + f'.get("{item_name_array[-1]}", [])'
|
|
1339
|
+
)
|
|
1332
1340
|
list_of_elem_deserialized = ""
|
|
1333
1341
|
if self.code_model.options["models_mode"] == "dpg":
|
|
1334
1342
|
item_type = builder.item_type.type_annotation(
|
|
@@ -1341,20 +1349,34 @@ class _PagingOperationSerializer(_OperationSerializer[PagingOperationType]):
|
|
|
1341
1349
|
retval.append(" if cls:")
|
|
1342
1350
|
retval.append(" list_of_elem = cls(list_of_elem) # type: ignore")
|
|
1343
1351
|
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1352
|
+
if builder.has_continuation_token:
|
|
1353
|
+
location = builder.continuation_token.get("output", {}).get("location")
|
|
1354
|
+
wire_name = builder.continuation_token.get("output", {}).get("wireName") or ""
|
|
1355
|
+
if location == "header":
|
|
1356
|
+
cont_token_property = f'pipeline_response.http_response.headers.get("{wire_name}") or None'
|
|
1357
|
+
else:
|
|
1358
|
+
wire_name_array = wire_name.split(".")
|
|
1359
|
+
wire_name_call = (
|
|
1360
|
+
"".join([f'.get("{i}", {{}})' for i in wire_name_array[:-1]]) + f'.get("{wire_name_array[-1]}")'
|
|
1361
|
+
)
|
|
1362
|
+
cont_token_property = f"deserialized{wire_name_call} or None"
|
|
1349
1363
|
else:
|
|
1350
|
-
|
|
1364
|
+
next_link_name = builder.next_link_name
|
|
1365
|
+
if not next_link_name:
|
|
1366
|
+
cont_token_property = "None"
|
|
1367
|
+
elif self.code_model.options["models_mode"] == "msrest":
|
|
1368
|
+
cont_token_property = f"deserialized.{next_link_name} or None"
|
|
1369
|
+
else:
|
|
1370
|
+
cont_token_property = f'deserialized.get("{next_link_name}") or None'
|
|
1351
1371
|
list_type = "AsyncList" if self.async_mode else "iter"
|
|
1352
1372
|
retval.append(f" return {cont_token_property}, {list_type}(list_of_elem)")
|
|
1353
1373
|
return retval
|
|
1354
1374
|
|
|
1355
1375
|
def _get_next_callback(self, builder: PagingOperationType) -> List[str]:
|
|
1356
|
-
retval = [
|
|
1357
|
-
|
|
1376
|
+
retval = [
|
|
1377
|
+
f"{'async ' if self.async_mode else ''}def get_next({builder.next_variable_name}=None):" # pylint: disable=line-too-long
|
|
1378
|
+
]
|
|
1379
|
+
retval.append(f" _request = prepare_request({builder.next_variable_name})")
|
|
1358
1380
|
retval.append("")
|
|
1359
1381
|
retval.extend([f" {l}" for l in self.make_pipeline_call(builder)])
|
|
1360
1382
|
retval.append(" response = pipeline_response.http_response")
|
|
@@ -1506,10 +1528,10 @@ class LROPagingOperationSerializer(
|
|
|
1506
1528
|
|
|
1507
1529
|
def get_long_running_output(self, builder: LROPagingOperation) -> List[str]:
|
|
1508
1530
|
retval = ["def get_long_running_output(pipeline_response):"]
|
|
1509
|
-
retval.append(f" {self._function_def} internal_get_next(
|
|
1510
|
-
retval.append(" if
|
|
1531
|
+
retval.append(f" {self._function_def} internal_get_next({builder.next_variable_name}=None):")
|
|
1532
|
+
retval.append(f" if {builder.next_variable_name} is None:")
|
|
1511
1533
|
retval.append(" return pipeline_response")
|
|
1512
|
-
retval.append(f" return {self._call_method}get_next(
|
|
1534
|
+
retval.append(f" return {self._call_method}get_next({builder.next_variable_name})")
|
|
1513
1535
|
retval.append("")
|
|
1514
1536
|
retval.append(f" return {builder.get_pager(self.async_mode)}(")
|
|
1515
1537
|
retval.append(" internal_get_next, extract_data")
|
|
@@ -14,7 +14,7 @@ from .helpers import (
|
|
|
14
14
|
pad_builtin_namespaces,
|
|
15
15
|
pad_special_chars,
|
|
16
16
|
)
|
|
17
|
-
from .python_mappings import
|
|
17
|
+
from .python_mappings import TSP_RESERVED_WORDS, RESERVED_WORDS, PadType
|
|
18
18
|
|
|
19
19
|
from .. import YamlUpdatePlugin
|
|
20
20
|
from ..utils import (
|
|
@@ -182,11 +182,11 @@ class PreProcessPlugin(YamlUpdatePlugin):
|
|
|
182
182
|
|
|
183
183
|
@property
|
|
184
184
|
def models_mode(self) -> Optional[str]:
|
|
185
|
-
return self.options.get("models-mode", "dpg" if self.
|
|
185
|
+
return self.options.get("models-mode", "dpg" if self.is_tsp else None)
|
|
186
186
|
|
|
187
187
|
@property
|
|
188
|
-
def
|
|
189
|
-
return self.options.get("
|
|
188
|
+
def is_tsp(self) -> bool:
|
|
189
|
+
return self.options.get("tsp_file", False)
|
|
190
190
|
|
|
191
191
|
def add_body_param_type(
|
|
192
192
|
self,
|
|
@@ -197,9 +197,7 @@ class PreProcessPlugin(YamlUpdatePlugin):
|
|
|
197
197
|
if ( # pylint: disable=too-many-boolean-expressions
|
|
198
198
|
body_parameter
|
|
199
199
|
and body_parameter["type"]["type"] in ("model", "dict", "list")
|
|
200
|
-
and (
|
|
201
|
-
has_json_content_type(body_parameter) or (self.is_cadl and has_multi_part_content_type(body_parameter))
|
|
202
|
-
)
|
|
200
|
+
and (has_json_content_type(body_parameter) or (self.is_tsp and has_multi_part_content_type(body_parameter)))
|
|
203
201
|
and not body_parameter["type"].get("xmlMetadata")
|
|
204
202
|
and not any(t for t in ["flattened", "groupedBy"] if body_parameter.get(t))
|
|
205
203
|
):
|
|
@@ -210,7 +208,7 @@ class PreProcessPlugin(YamlUpdatePlugin):
|
|
|
210
208
|
"types": [body_parameter["type"]],
|
|
211
209
|
}
|
|
212
210
|
# don't add binary overload for multipart content type
|
|
213
|
-
if not (self.
|
|
211
|
+
if not (self.is_tsp and has_multi_part_content_type(body_parameter)):
|
|
214
212
|
body_parameter["type"]["types"].append(KNOWN_TYPES["binary"])
|
|
215
213
|
|
|
216
214
|
if origin_type == "model" and is_dpg_model and self.models_mode == "dpg":
|
|
@@ -223,8 +221,8 @@ class PreProcessPlugin(YamlUpdatePlugin):
|
|
|
223
221
|
# we'll pass in empty operation groups sometime etc.
|
|
224
222
|
return name
|
|
225
223
|
|
|
226
|
-
if self.
|
|
227
|
-
reserved_words = {k: (v +
|
|
224
|
+
if self.is_tsp:
|
|
225
|
+
reserved_words = {k: (v + TSP_RESERVED_WORDS.get(k, [])) for k, v in RESERVED_WORDS.items()}
|
|
228
226
|
else:
|
|
229
227
|
reserved_words = RESERVED_WORDS
|
|
230
228
|
name = pad_special_chars(name)
|
|
@@ -506,6 +504,6 @@ class PreProcessPlugin(YamlUpdatePlugin):
|
|
|
506
504
|
|
|
507
505
|
|
|
508
506
|
if __name__ == "__main__":
|
|
509
|
-
#
|
|
507
|
+
# TSP pipeline will call this
|
|
510
508
|
args, unknown_args = parse_args()
|
|
511
|
-
PreProcessPlugin(output_folder=args.output_folder,
|
|
509
|
+
PreProcessPlugin(output_folder=args.output_folder, tsp_file=args.tsp_file, **unknown_args).process()
|
|
@@ -44,7 +44,7 @@ def to_snake_case(name: str) -> str:
|
|
|
44
44
|
|
|
45
45
|
|
|
46
46
|
def parse_args(
|
|
47
|
-
|
|
47
|
+
need_tsp_file: bool = True,
|
|
48
48
|
) -> Tuple[argparse.Namespace, Dict[str, Any]]:
|
|
49
49
|
parser = argparse.ArgumentParser(
|
|
50
50
|
description="Run mypy against target folder. Add a local custom plugin to the path prior to execution. "
|
|
@@ -56,10 +56,10 @@ def parse_args(
|
|
|
56
56
|
required=True,
|
|
57
57
|
)
|
|
58
58
|
parser.add_argument(
|
|
59
|
-
"--
|
|
60
|
-
dest="
|
|
61
|
-
help="Serialized
|
|
62
|
-
required=
|
|
59
|
+
"--tsp-file",
|
|
60
|
+
dest="tsp_file",
|
|
61
|
+
help="Serialized tsp file",
|
|
62
|
+
required=need_tsp_file,
|
|
63
63
|
)
|
|
64
64
|
parser.add_argument(
|
|
65
65
|
"--debug",
|
|
@@ -4,11 +4,11 @@
|
|
|
4
4
|
"install": [
|
|
5
5
|
{
|
|
6
6
|
"download_info": {
|
|
7
|
-
"url": "https://files.pythonhosted.org/packages/
|
|
7
|
+
"url": "https://files.pythonhosted.org/packages/15/65/3f0dba35760d902849d39d38c0a72767794b1963227b69a587f8a336d08c/setuptools-75.3.2-py3-none-any.whl",
|
|
8
8
|
"archive_info": {
|
|
9
|
-
"hash": "sha256=
|
|
9
|
+
"hash": "sha256=90ab613b6583fc02d5369cbca13ea26ea0e182d1df2d943ee9cbe81d4c61add9",
|
|
10
10
|
"hashes": {
|
|
11
|
-
"sha256": "
|
|
11
|
+
"sha256": "90ab613b6583fc02d5369cbca13ea26ea0e182d1df2d943ee9cbe81d4c61add9"
|
|
12
12
|
}
|
|
13
13
|
}
|
|
14
14
|
},
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
"metadata": {
|
|
19
19
|
"metadata_version": "2.1",
|
|
20
20
|
"name": "setuptools",
|
|
21
|
-
"version": "75.3.
|
|
21
|
+
"version": "75.3.2",
|
|
22
22
|
"summary": "Easily download, build, install, upgrade, and uninstall Python packages",
|
|
23
23
|
"description_content_type": "text/x-rst",
|
|
24
24
|
"keywords": [
|
|
@@ -93,6 +93,7 @@
|
|
|
93
93
|
"pytest-subprocess ; extra == 'test'",
|
|
94
94
|
"pyproject-hooks !=1.1 ; extra == 'test'",
|
|
95
95
|
"jaraco.test >=5.5 ; extra == 'test'",
|
|
96
|
+
"ruff <=0.7.1 ; extra == 'test'",
|
|
96
97
|
"jaraco.develop >=7.21 ; (python_version >= \"3.9\" and sys_platform != \"cygwin\") and extra == 'test'",
|
|
97
98
|
"pytest-perf ; (sys_platform != \"cygwin\") and extra == 'test'",
|
|
98
99
|
"pytest-mypy ; extra == 'type'",
|
|
@@ -126,9 +127,9 @@
|
|
|
126
127
|
"implementation_version": "3.8.10",
|
|
127
128
|
"os_name": "posix",
|
|
128
129
|
"platform_machine": "x86_64",
|
|
129
|
-
"platform_release": "5.15.0-
|
|
130
|
+
"platform_release": "5.15.0-1082-azure",
|
|
130
131
|
"platform_system": "Linux",
|
|
131
|
-
"platform_version": "#
|
|
132
|
+
"platform_version": "#91~20.04.1-Ubuntu SMP Tue Feb 25 03:23:03 UTC 2025",
|
|
132
133
|
"python_full_version": "3.8.10",
|
|
133
134
|
"platform_python_implementation": "CPython",
|
|
134
135
|
"python_version": "3.8",
|
|
Binary file
|
|
@@ -78,12 +78,12 @@ class YamlUpdatePlugin(Plugin):
|
|
|
78
78
|
"""A plugin that update the YAML as input."""
|
|
79
79
|
|
|
80
80
|
def get_yaml(self) -> Dict[str, Any]:
|
|
81
|
-
#
|
|
82
|
-
with open(self.options["
|
|
81
|
+
# tsp file doesn't have to be relative to output folder
|
|
82
|
+
with open(self.options["tsp_file"], "r", encoding="utf-8-sig") as fd:
|
|
83
83
|
return yaml.safe_load(fd.read())
|
|
84
84
|
|
|
85
85
|
def write_yaml(self, yaml_string: str) -> None:
|
|
86
|
-
with open(self.options["
|
|
86
|
+
with open(self.options["tsp_file"], "w", encoding="utf-8-sig") as fd:
|
|
87
87
|
fd.write(yaml_string)
|
|
88
88
|
|
|
89
89
|
def process(self) -> bool:
|
package/generator/pygen/black.py
CHANGED
|
@@ -77,6 +77,6 @@ class BlackScriptPlugin(Plugin):
|
|
|
77
77
|
|
|
78
78
|
|
|
79
79
|
if __name__ == "__main__":
|
|
80
|
-
#
|
|
81
|
-
args, unknown_args = parse_args(
|
|
80
|
+
# TSP pipeline will call this
|
|
81
|
+
args, unknown_args = parse_args(need_tsp_file=False)
|
|
82
82
|
BlackScriptPlugin(output_folder=args.output_folder, **unknown_args).process()
|
|
@@ -79,7 +79,7 @@ class OptionsRetriever:
|
|
|
79
79
|
@property
|
|
80
80
|
def _models_mode_default(self) -> str:
|
|
81
81
|
models_mode_default = "none" if self.low_level_client or self.version_tolerant else "msrest"
|
|
82
|
-
if self.options.get("
|
|
82
|
+
if self.options.get("tsp_file") is not None:
|
|
83
83
|
models_mode_default = "dpg"
|
|
84
84
|
return models_mode_default
|
|
85
85
|
|
|
@@ -322,8 +322,8 @@ class CodeGenerator(Plugin):
|
|
|
322
322
|
return {f: getattr(self.options_retriever, f) for f in flags}
|
|
323
323
|
|
|
324
324
|
def get_yaml(self) -> Dict[str, Any]:
|
|
325
|
-
#
|
|
326
|
-
with open(self.options["
|
|
325
|
+
# tsp file doesn't have to be relative to output folder
|
|
326
|
+
with open(self.options["tsp_file"], "r", encoding="utf-8-sig") as fd:
|
|
327
327
|
return yaml.safe_load(fd.read())
|
|
328
328
|
|
|
329
329
|
def get_serializer(self, code_model: CodeModel):
|
|
@@ -350,10 +350,10 @@ class CodeGenerator(Plugin):
|
|
|
350
350
|
|
|
351
351
|
|
|
352
352
|
if __name__ == "__main__":
|
|
353
|
-
#
|
|
353
|
+
# TSP pipeline will call this
|
|
354
354
|
parsed_args, unknown_args = parse_args()
|
|
355
355
|
CodeGenerator(
|
|
356
356
|
output_folder=parsed_args.output_folder,
|
|
357
|
-
|
|
357
|
+
tsp_file=parsed_args.tsp_file,
|
|
358
358
|
**unknown_args,
|
|
359
359
|
).process()
|
|
@@ -58,6 +58,15 @@ class PagingOperationBase(OperationBase[PagingResponseType]):
|
|
|
58
58
|
self.override_success_response_to_200 = override_success_response_to_200
|
|
59
59
|
self.pager_sync: str = yaml_data.get("pagerSync") or f"{self.code_model.core_library}.paging.ItemPaged"
|
|
60
60
|
self.pager_async: str = yaml_data.get("pagerAsync") or f"{self.code_model.core_library}.paging.AsyncItemPaged"
|
|
61
|
+
self.continuation_token: Dict[str, Any] = yaml_data.get("continuationToken", {})
|
|
62
|
+
|
|
63
|
+
@property
|
|
64
|
+
def has_continuation_token(self) -> bool:
|
|
65
|
+
return bool(self.continuation_token.get("input") and self.continuation_token.get("output"))
|
|
66
|
+
|
|
67
|
+
@property
|
|
68
|
+
def next_variable_name(self) -> str:
|
|
69
|
+
return "_continuation_token" if self.has_continuation_token else "next_link"
|
|
61
70
|
|
|
62
71
|
def _get_attr_name(self, wire_name: str) -> str:
|
|
63
72
|
response_type = self.responses[0].type
|
|
@@ -74,8 +83,8 @@ class PagingOperationBase(OperationBase[PagingResponseType]):
|
|
|
74
83
|
return self.responses[0].get_pager(async_mode)
|
|
75
84
|
|
|
76
85
|
@property
|
|
77
|
-
def
|
|
78
|
-
wire_name = self.yaml_data.get("
|
|
86
|
+
def next_link_name(self) -> Optional[str]:
|
|
87
|
+
wire_name = self.yaml_data.get("nextLinkName")
|
|
79
88
|
if not wire_name:
|
|
80
89
|
# That's an ok scenario, it just means no next page possible
|
|
81
90
|
return None
|
|
@@ -85,6 +85,7 @@ class _ParameterBase(BaseModel, abc.ABC): # pylint: disable=too-many-instance-a
|
|
|
85
85
|
self.in_overload: bool = self.yaml_data.get("inOverload", False)
|
|
86
86
|
self.default_to_unset_sentinel: bool = self.yaml_data.get("defaultToUnsetSentinel", False)
|
|
87
87
|
self.hide_in_method: bool = self.yaml_data.get("hideInMethod", False)
|
|
88
|
+
self.is_continuation_token: bool = bool(self.yaml_data.get("isContinuationToken"))
|
|
88
89
|
|
|
89
90
|
def get_declaration(self, value: Any = None) -> Any:
|
|
90
91
|
return self.type.get_declaration(value)
|
|
@@ -314,7 +315,7 @@ class Parameter(_ParameterBase):
|
|
|
314
315
|
def hide_in_operation_signature(self) -> bool:
|
|
315
316
|
if self.code_model.options["version_tolerant"] and self.client_name == "maxpagesize":
|
|
316
317
|
return True
|
|
317
|
-
return
|
|
318
|
+
return self.is_continuation_token
|
|
318
319
|
|
|
319
320
|
@property
|
|
320
321
|
def in_method_signature(self) -> bool:
|
|
@@ -63,7 +63,7 @@ class Response(BaseModel):
|
|
|
63
63
|
def result_property(self) -> str:
|
|
64
64
|
field = self.yaml_data.get("resultProperty")
|
|
65
65
|
if field:
|
|
66
|
-
return f'.get("{field}")'
|
|
66
|
+
return "".join([f'.get("{field}", {{}})' for field in field.split(".")])
|
|
67
67
|
return ""
|
|
68
68
|
|
|
69
69
|
def get_polymorphic_subtypes(self, polymorphic_subtypes: List["ModelType"]) -> None:
|
|
@@ -630,7 +630,7 @@ class _OperationSerializer(_BuilderBaseSerializer[OperationType]):
|
|
|
630
630
|
operation_name=f"('{builder.name}')" if builder.group_name == "" else "",
|
|
631
631
|
)
|
|
632
632
|
for p in builder.parameters.parameters:
|
|
633
|
-
if p.hide_in_operation_signature:
|
|
633
|
+
if p.hide_in_operation_signature and not p.is_continuation_token:
|
|
634
634
|
kwargs.append(f'{p.client_name} = kwargs.pop("{p.client_name}", None)')
|
|
635
635
|
cls_annotation = builder.cls_type_annotation(
|
|
636
636
|
async_mode=self.async_mode, serialize_namespace=self.serialize_namespace
|
|
@@ -1001,9 +1001,7 @@ class _OperationSerializer(_BuilderBaseSerializer[OperationType]):
|
|
|
1001
1001
|
retval.extend(deserialize_code)
|
|
1002
1002
|
return retval
|
|
1003
1003
|
|
|
1004
|
-
def handle_error_response(
|
|
1005
|
-
self, builder: OperationType
|
|
1006
|
-
) -> List[str]:
|
|
1004
|
+
def handle_error_response(self, builder: OperationType) -> List[str]:
|
|
1007
1005
|
async_await = "await " if self.async_mode else ""
|
|
1008
1006
|
retval = [f"if response.status_code not in {str(builder.success_status_codes)}:"]
|
|
1009
1007
|
response_read = [
|
|
@@ -1290,16 +1288,20 @@ class _PagingOperationSerializer(_OperationSerializer[PagingOperationType]):
|
|
|
1290
1288
|
|
|
1291
1289
|
def _prepare_request_callback(self, builder: PagingOperationType) -> List[str]:
|
|
1292
1290
|
retval = self._initialize_overloads(builder)
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
retval.append("")
|
|
1297
|
-
retval.append(" else:")
|
|
1298
|
-
retval.extend([f" {line}" for line in self.call_next_link_request_builder(builder)])
|
|
1299
|
-
if not builder.next_request_builder and self.code_model.is_legacy:
|
|
1300
|
-
retval.append(' _request.method = "GET"')
|
|
1291
|
+
if builder.has_continuation_token:
|
|
1292
|
+
retval.append(f"def prepare_request({builder.next_variable_name}=None):")
|
|
1293
|
+
retval.extend([f" {line}" for line in self.call_request_builder(builder, is_paging=True)])
|
|
1301
1294
|
else:
|
|
1295
|
+
retval.append("def prepare_request(next_link=None):")
|
|
1296
|
+
retval.append(" if not next_link:")
|
|
1297
|
+
retval.extend([f" {line}" for line in self.call_request_builder(builder, is_paging=True)])
|
|
1302
1298
|
retval.append("")
|
|
1299
|
+
retval.append(" else:")
|
|
1300
|
+
retval.extend([f" {line}" for line in self.call_next_link_request_builder(builder)])
|
|
1301
|
+
if not builder.next_request_builder and self.code_model.is_legacy:
|
|
1302
|
+
retval.append(' _request.method = "GET"')
|
|
1303
|
+
else:
|
|
1304
|
+
retval.append("")
|
|
1303
1305
|
retval.append(" return _request")
|
|
1304
1306
|
return retval
|
|
1305
1307
|
|
|
@@ -1307,7 +1309,7 @@ class _PagingOperationSerializer(_OperationSerializer[PagingOperationType]):
|
|
|
1307
1309
|
def _function_def(self) -> str:
|
|
1308
1310
|
return "def"
|
|
1309
1311
|
|
|
1310
|
-
def _extract_data_callback(self, builder: PagingOperationType) -> List[str]:
|
|
1312
|
+
def _extract_data_callback(self, builder: PagingOperationType) -> List[str]: # pylint: disable=too-many-statements
|
|
1311
1313
|
retval = [f"{'async ' if self.async_mode else ''}def extract_data(pipeline_response):"]
|
|
1312
1314
|
response = builder.responses[0]
|
|
1313
1315
|
deserialized = "pipeline_response.http_response.json()"
|
|
@@ -1328,7 +1330,13 @@ class _PagingOperationSerializer(_OperationSerializer[PagingOperationType]):
|
|
|
1328
1330
|
else:
|
|
1329
1331
|
retval.append(f" deserialized = {deserialized}")
|
|
1330
1332
|
item_name = builder.item_name
|
|
1331
|
-
|
|
1333
|
+
if self.code_model.options["models_mode"] == "msrest":
|
|
1334
|
+
access = f".{item_name}"
|
|
1335
|
+
else:
|
|
1336
|
+
item_name_array = item_name.split(".")
|
|
1337
|
+
access = (
|
|
1338
|
+
"".join([f'.get("{i}", {{}})' for i in item_name_array[:-1]]) + f'.get("{item_name_array[-1]}", [])'
|
|
1339
|
+
)
|
|
1332
1340
|
list_of_elem_deserialized = ""
|
|
1333
1341
|
if self.code_model.options["models_mode"] == "dpg":
|
|
1334
1342
|
item_type = builder.item_type.type_annotation(
|
|
@@ -1341,20 +1349,34 @@ class _PagingOperationSerializer(_OperationSerializer[PagingOperationType]):
|
|
|
1341
1349
|
retval.append(" if cls:")
|
|
1342
1350
|
retval.append(" list_of_elem = cls(list_of_elem) # type: ignore")
|
|
1343
1351
|
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1352
|
+
if builder.has_continuation_token:
|
|
1353
|
+
location = builder.continuation_token.get("output", {}).get("location")
|
|
1354
|
+
wire_name = builder.continuation_token.get("output", {}).get("wireName") or ""
|
|
1355
|
+
if location == "header":
|
|
1356
|
+
cont_token_property = f'pipeline_response.http_response.headers.get("{wire_name}") or None'
|
|
1357
|
+
else:
|
|
1358
|
+
wire_name_array = wire_name.split(".")
|
|
1359
|
+
wire_name_call = (
|
|
1360
|
+
"".join([f'.get("{i}", {{}})' for i in wire_name_array[:-1]]) + f'.get("{wire_name_array[-1]}")'
|
|
1361
|
+
)
|
|
1362
|
+
cont_token_property = f"deserialized{wire_name_call} or None"
|
|
1349
1363
|
else:
|
|
1350
|
-
|
|
1364
|
+
next_link_name = builder.next_link_name
|
|
1365
|
+
if not next_link_name:
|
|
1366
|
+
cont_token_property = "None"
|
|
1367
|
+
elif self.code_model.options["models_mode"] == "msrest":
|
|
1368
|
+
cont_token_property = f"deserialized.{next_link_name} or None"
|
|
1369
|
+
else:
|
|
1370
|
+
cont_token_property = f'deserialized.get("{next_link_name}") or None'
|
|
1351
1371
|
list_type = "AsyncList" if self.async_mode else "iter"
|
|
1352
1372
|
retval.append(f" return {cont_token_property}, {list_type}(list_of_elem)")
|
|
1353
1373
|
return retval
|
|
1354
1374
|
|
|
1355
1375
|
def _get_next_callback(self, builder: PagingOperationType) -> List[str]:
|
|
1356
|
-
retval = [
|
|
1357
|
-
|
|
1376
|
+
retval = [
|
|
1377
|
+
f"{'async ' if self.async_mode else ''}def get_next({builder.next_variable_name}=None):" # pylint: disable=line-too-long
|
|
1378
|
+
]
|
|
1379
|
+
retval.append(f" _request = prepare_request({builder.next_variable_name})")
|
|
1358
1380
|
retval.append("")
|
|
1359
1381
|
retval.extend([f" {l}" for l in self.make_pipeline_call(builder)])
|
|
1360
1382
|
retval.append(" response = pipeline_response.http_response")
|
|
@@ -1506,10 +1528,10 @@ class LROPagingOperationSerializer(
|
|
|
1506
1528
|
|
|
1507
1529
|
def get_long_running_output(self, builder: LROPagingOperation) -> List[str]:
|
|
1508
1530
|
retval = ["def get_long_running_output(pipeline_response):"]
|
|
1509
|
-
retval.append(f" {self._function_def} internal_get_next(
|
|
1510
|
-
retval.append(" if
|
|
1531
|
+
retval.append(f" {self._function_def} internal_get_next({builder.next_variable_name}=None):")
|
|
1532
|
+
retval.append(f" if {builder.next_variable_name} is None:")
|
|
1511
1533
|
retval.append(" return pipeline_response")
|
|
1512
|
-
retval.append(f" return {self._call_method}get_next(
|
|
1534
|
+
retval.append(f" return {self._call_method}get_next({builder.next_variable_name})")
|
|
1513
1535
|
retval.append("")
|
|
1514
1536
|
retval.append(f" return {builder.get_pager(self.async_mode)}(")
|
|
1515
1537
|
retval.append(" internal_get_next, extract_data")
|