@autorest/python 6.29.1 → 6.31.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/autorest/m4reformatter/__init__.py +1 -1
- 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 -7
- package/generator/build/lib/pygen/codegen/models/code_model.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/__init__.py +18 -14
- package/generator/build/lib/pygen/codegen/serializers/builder_serializer.py +47 -25
- package/generator/build/lib/pygen/codegen/serializers/general_serializer.py +5 -2
- package/generator/build/lib/pygen/codegen/serializers/test_serializer.py +1 -1
- package/generator/build/lib/pygen/codegen/templates/packaging_templates/MANIFEST.in.jinja2 +6 -2
- package/generator/build/lib/pygen/codegen/templates/packaging_templates/README.md.jinja2 +5 -5
- package/generator/build/lib/pygen/codegen/templates/packaging_templates/dev_requirements.txt.jinja2 +3 -3
- package/generator/build/lib/pygen/codegen/templates/packaging_templates/setup.py.jinja2 +14 -5
- 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 -7
- package/generator/pygen/codegen/models/code_model.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/__init__.py +18 -14
- package/generator/pygen/codegen/serializers/builder_serializer.py +47 -25
- package/generator/pygen/codegen/serializers/general_serializer.py +5 -2
- package/generator/pygen/codegen/serializers/test_serializer.py +1 -1
- package/generator/pygen/codegen/templates/packaging_templates/MANIFEST.in.jinja2 +6 -2
- package/generator/pygen/codegen/templates/packaging_templates/README.md.jinja2 +5 -5
- package/generator/pygen/codegen/templates/packaging_templates/dev_requirements.txt.jinja2 +3 -3
- package/generator/pygen/codegen/templates/packaging_templates/setup.py.jinja2 +14 -5
- 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/pygen.egg-info/PKG-INFO +4 -3
- package/generator/pygen.egg-info/requires.txt +2 -2
- package/generator/setup.py +2 -2
- package/package.json +2 -2
- package/scripts/__pycache__/venvtools.cpython-310.pyc +0 -0
|
@@ -551,7 +551,7 @@ class M4Reformatter(YamlUpdatePluginAutorest): # pylint: disable=too-many-publi
|
|
|
551
551
|
def add_paging_information(self, group_name: str, operation: Dict[str, Any], yaml_data: Dict[str, Any]) -> None:
|
|
552
552
|
operation["discriminator"] = "paging"
|
|
553
553
|
operation["itemName"] = yaml_data["extensions"]["x-ms-pageable"].get("itemName", "value")
|
|
554
|
-
operation["
|
|
554
|
+
operation["nextLinkName"] = yaml_data["extensions"]["x-ms-pageable"].get("nextLinkName")
|
|
555
555
|
returned_response_object = (
|
|
556
556
|
operation["nextOperation"]["responses"][0] if operation.get("nextOperation") else operation["responses"][0]
|
|
557
557
|
)
|
|
@@ -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:
|
|
@@ -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()
|
|
@@ -40,7 +40,6 @@ class OptionsRetriever:
|
|
|
40
40
|
"generate-test": False,
|
|
41
41
|
"from-typespec": False,
|
|
42
42
|
"emit-cross-language-definition-file": False,
|
|
43
|
-
"enable-typespec-namespace": False,
|
|
44
43
|
}
|
|
45
44
|
|
|
46
45
|
@property
|
|
@@ -79,7 +78,7 @@ class OptionsRetriever:
|
|
|
79
78
|
@property
|
|
80
79
|
def _models_mode_default(self) -> str:
|
|
81
80
|
models_mode_default = "none" if self.low_level_client or self.version_tolerant else "msrest"
|
|
82
|
-
if self.options.get("
|
|
81
|
+
if self.options.get("tsp_file") is not None:
|
|
83
82
|
models_mode_default = "dpg"
|
|
84
83
|
return models_mode_default
|
|
85
84
|
|
|
@@ -317,13 +316,12 @@ class CodeGenerator(Plugin):
|
|
|
317
316
|
"flavor",
|
|
318
317
|
"company_name",
|
|
319
318
|
"emit_cross_language_definition_file",
|
|
320
|
-
"enable_typespec_namespace",
|
|
321
319
|
]
|
|
322
320
|
return {f: getattr(self.options_retriever, f) for f in flags}
|
|
323
321
|
|
|
324
322
|
def get_yaml(self) -> Dict[str, Any]:
|
|
325
|
-
#
|
|
326
|
-
with open(self.options["
|
|
323
|
+
# tsp file doesn't have to be relative to output folder
|
|
324
|
+
with open(self.options["tsp_file"], "r", encoding="utf-8-sig") as fd:
|
|
327
325
|
return yaml.safe_load(fd.read())
|
|
328
326
|
|
|
329
327
|
def get_serializer(self, code_model: CodeModel):
|
|
@@ -350,10 +348,10 @@ class CodeGenerator(Plugin):
|
|
|
350
348
|
|
|
351
349
|
|
|
352
350
|
if __name__ == "__main__":
|
|
353
|
-
#
|
|
351
|
+
# TSP pipeline will call this
|
|
354
352
|
parsed_args, unknown_args = parse_args()
|
|
355
353
|
CodeGenerator(
|
|
356
354
|
output_folder=parsed_args.output_folder,
|
|
357
|
-
|
|
355
|
+
tsp_file=parsed_args.tsp_file,
|
|
358
356
|
**unknown_args,
|
|
359
357
|
).process()
|
|
@@ -145,12 +145,8 @@ class CodeModel: # pylint: disable=too-many-public-methods, disable=too-many-in
|
|
|
145
145
|
return result
|
|
146
146
|
return f"{result}{module_name}" if result.endswith(".") else f"{result}.{module_name}"
|
|
147
147
|
|
|
148
|
-
@property
|
|
149
|
-
def need_unique_model_alias(self) -> bool:
|
|
150
|
-
return self.has_subnamespace and self.options["enable_typespec_namespace"]
|
|
151
|
-
|
|
152
148
|
def get_unique_models_alias(self, serialize_namespace: str, imported_namespace: str) -> str:
|
|
153
|
-
if not self.
|
|
149
|
+
if not self.has_subnamespace:
|
|
154
150
|
return "_models"
|
|
155
151
|
relative_path = self.get_relative_import_path(
|
|
156
152
|
serialize_namespace, self.get_imported_namespace_for_model(imported_namespace)
|
|
@@ -406,3 +402,7 @@ class CodeModel: # pylint: disable=too-many-public-methods, disable=too-many-in
|
|
|
406
402
|
@staticmethod
|
|
407
403
|
def has_non_json_models(models: List[ModelType]) -> bool:
|
|
408
404
|
return any(m for m in models if m.base != "json")
|
|
405
|
+
|
|
406
|
+
@property
|
|
407
|
+
def is_tsp(self) -> bool:
|
|
408
|
+
return self.options.get("tsp_file") is not None
|
|
@@ -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:
|
|
@@ -197,6 +197,8 @@ class JinjaSerializer(ReaderAndWriter):
|
|
|
197
197
|
env = Environment(
|
|
198
198
|
loader=PackageLoader("pygen.codegen", "templates/packaging_templates"),
|
|
199
199
|
undefined=StrictUndefined,
|
|
200
|
+
trim_blocks=True,
|
|
201
|
+
lstrip_blocks=True,
|
|
200
202
|
)
|
|
201
203
|
|
|
202
204
|
package_files = _PACKAGE_FILES
|
|
@@ -460,21 +462,11 @@ class JinjaSerializer(ReaderAndWriter):
|
|
|
460
462
|
metadata_serializer = MetadataSerializer(self.code_model, env, client_namespace=namespace)
|
|
461
463
|
self.write_file(self.exec_path(namespace) / Path("_metadata.json"), metadata_serializer.serialize())
|
|
462
464
|
|
|
463
|
-
@property
|
|
464
|
-
def _namespace_from_package_name(self) -> str:
|
|
465
|
-
return get_namespace_from_package_name(self.code_model.options["package_name"])
|
|
466
|
-
|
|
467
|
-
def _name_space(self) -> str:
|
|
468
|
-
if self.code_model.namespace.count(".") >= self._namespace_from_package_name.count("."):
|
|
469
|
-
return self.code_model.namespace
|
|
470
|
-
|
|
471
|
-
return self._namespace_from_package_name
|
|
472
|
-
|
|
473
465
|
@property
|
|
474
466
|
def exec_path_compensation(self) -> Path:
|
|
475
467
|
"""Assume the process is running in the root folder of the package. If not, we need the path compensation."""
|
|
476
468
|
return (
|
|
477
|
-
Path("../" * (self.
|
|
469
|
+
Path("../" * (self.code_model.namespace.count(".") + 1))
|
|
478
470
|
if self.code_model.options["no_namespace_folders"]
|
|
479
471
|
else Path(".")
|
|
480
472
|
)
|
|
@@ -482,16 +474,28 @@ class JinjaSerializer(ReaderAndWriter):
|
|
|
482
474
|
def exec_path_for_test_sample(self, namespace: str) -> Path:
|
|
483
475
|
return self.exec_path_compensation / Path(*namespace.split("."))
|
|
484
476
|
|
|
477
|
+
# pylint: disable=line-too-long
|
|
485
478
|
def exec_path(self, namespace: str) -> Path:
|
|
486
479
|
if self.code_model.options["no_namespace_folders"] and not self.code_model.options["multiapi"]:
|
|
480
|
+
# when output folder contains parts different from the namespace, we fall back to current folder directly.
|
|
481
|
+
# (e.g. https://github.com/Azure/azure-sdk-for-python/blob/main/sdk/communication/azure-communication-callautomation/swagger/SWAGGER.md)
|
|
487
482
|
return Path(".")
|
|
488
483
|
return self.exec_path_compensation / Path(*namespace.split("."))
|
|
489
484
|
|
|
485
|
+
# pylint: disable=line-too-long
|
|
490
486
|
@property
|
|
491
|
-
def
|
|
487
|
+
def sample_additional_folder(self) -> Path:
|
|
488
|
+
# For special package, we need to additional folder when generate samples.
|
|
489
|
+
# For example, azure-mgmt-resource is combined by multiple modules, and each module is multiapi package.
|
|
490
|
+
# one of namespace is "azure.mgmt.resource.resources.v2020_01_01", then additional folder is "resources"
|
|
491
|
+
# so that we could avoid conflict when generate samples.
|
|
492
|
+
# python config: https://github.com/Azure/azure-rest-api-specs/blob/main/specification/resources/resource-manager/readme.python.md
|
|
493
|
+
# generated SDK: https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/resources/azure-mgmt-resource/generated_samples
|
|
492
494
|
namespace_config = get_namespace_config(self.code_model.namespace, self.code_model.options["multiapi"])
|
|
493
495
|
num_of_namespace = namespace_config.count(".") + 1
|
|
494
|
-
num_of_package_namespace =
|
|
496
|
+
num_of_package_namespace = (
|
|
497
|
+
get_namespace_from_package_name(self.code_model.options["package_name"]).count(".") + 1
|
|
498
|
+
)
|
|
495
499
|
if num_of_namespace > num_of_package_namespace:
|
|
496
500
|
return Path("/".join(namespace_config.split(".")[num_of_package_namespace:]))
|
|
497
501
|
return Path("")
|
|
@@ -514,7 +518,7 @@ class JinjaSerializer(ReaderAndWriter):
|
|
|
514
518
|
file_name = to_snake_case(extract_sample_name(file)) + ".py"
|
|
515
519
|
try:
|
|
516
520
|
self.write_file(
|
|
517
|
-
out_path / self.
|
|
521
|
+
out_path / self.sample_additional_folder / _sample_output_path(file) / file_name,
|
|
518
522
|
SampleSerializer(
|
|
519
523
|
code_model=self.code_model,
|
|
520
524
|
env=env,
|
|
@@ -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")
|
|
@@ -28,7 +28,11 @@ class GeneralSerializer(BaseSerializer):
|
|
|
28
28
|
|
|
29
29
|
def serialize_package_file(self, template_name: str, **kwargs: Any) -> str:
|
|
30
30
|
template = self.env.get_template(template_name)
|
|
31
|
-
package_parts = (
|
|
31
|
+
package_parts = (
|
|
32
|
+
self.code_model.namespace.split(".")[:-1]
|
|
33
|
+
if self.code_model.is_tsp
|
|
34
|
+
else (self.code_model.options["package_name"] or "").split("-")[:-1]
|
|
35
|
+
)
|
|
32
36
|
token_credential = any(
|
|
33
37
|
c for c in self.code_model.clients if isinstance(getattr(c.credential, "type", None), TokenCredentialType)
|
|
34
38
|
)
|
|
@@ -44,7 +48,6 @@ class GeneralSerializer(BaseSerializer):
|
|
|
44
48
|
"pkgutil_names": [".".join(package_parts[: i + 1]) for i in range(len(package_parts))],
|
|
45
49
|
"init_names": ["/".join(package_parts[: i + 1]) + "/__init__.py" for i in range(len(package_parts))],
|
|
46
50
|
"client_name": self.code_model.clients[0].name,
|
|
47
|
-
"namespace": self.code_model.namespace,
|
|
48
51
|
}
|
|
49
52
|
params.update(self.code_model.options)
|
|
50
53
|
params.update(kwargs)
|
|
@@ -1,8 +1,12 @@
|
|
|
1
1
|
include *.md
|
|
2
2
|
include LICENSE
|
|
3
|
+
{% if code_model.is_tsp %}
|
|
4
|
+
include {{ code_model.namespace.replace('.', '/') }}/py.typed
|
|
5
|
+
{% else %}
|
|
3
6
|
include {{ package_name.replace('-', '/') }}/py.typed
|
|
7
|
+
{% endif %}
|
|
4
8
|
recursive-include tests *.py
|
|
5
9
|
recursive-include samples *.py *.md
|
|
6
|
-
{
|
|
10
|
+
{% for init_name in init_names %}
|
|
7
11
|
include {{ init_name }}
|
|
8
|
-
{
|
|
12
|
+
{% endfor %}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{% if code_model.is_azure_flavor %}
|
|
2
|
-
{% if package_mode == "mgmtplane"
|
|
2
|
+
{% if package_mode == "mgmtplane" %}
|
|
3
3
|
# Microsoft Azure SDK for Python
|
|
4
4
|
|
|
5
5
|
This is the Microsoft {{package_pprint_name}} Client Library.
|
|
@@ -40,7 +40,7 @@ python -m pip install {{ package_name }}
|
|
|
40
40
|
- You need an [Azure subscription][azure_sub] to use this package.
|
|
41
41
|
- An existing {{ package_pprint_name }} instance.
|
|
42
42
|
|
|
43
|
-
{
|
|
43
|
+
{% if token_credential %}
|
|
44
44
|
#### Create with an Azure Active Directory Credential
|
|
45
45
|
To use an [Azure Active Directory (AAD) token credential][authenticate_with_token],
|
|
46
46
|
provide an instance of the desired credential type obtained from the
|
|
@@ -57,7 +57,7 @@ Set the values of the client ID, tenant ID, and client secret of the AAD applica
|
|
|
57
57
|
Use the returned token credential to authenticate the client:
|
|
58
58
|
|
|
59
59
|
```python
|
|
60
|
-
>>> from {{ namespace }} import {{ client_name }}
|
|
60
|
+
>>> from {{ code_model.namespace }} import {{ client_name }}
|
|
61
61
|
>>> from azure.identity import DefaultAzureCredential
|
|
62
62
|
>>> client = {{ client_name }}(endpoint='<endpoint>', credential=DefaultAzureCredential())
|
|
63
63
|
```
|
|
@@ -65,7 +65,7 @@ Use the returned token credential to authenticate the client:
|
|
|
65
65
|
## Examples
|
|
66
66
|
|
|
67
67
|
```python
|
|
68
|
-
>>> from {{ namespace }} import {{ client_name }}
|
|
68
|
+
>>> from {{ code_model.namespace }} import {{ client_name }}
|
|
69
69
|
>>> from azure.identity import DefaultAzureCredential
|
|
70
70
|
>>> from {{ code_model.core_library }}.exceptions import HttpResponseError
|
|
71
71
|
|
|
@@ -76,7 +76,7 @@ Use the returned token credential to authenticate the client:
|
|
|
76
76
|
print('service responds error: {}'.format(e.response.json()))
|
|
77
77
|
|
|
78
78
|
```
|
|
79
|
-
{
|
|
79
|
+
{% endif %}
|
|
80
80
|
|
|
81
81
|
## Contributing
|
|
82
82
|
|
package/generator/build/lib/pygen/codegen/templates/packaging_templates/dev_requirements.txt.jinja2
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
-e ../../../tools/azure-sdk-tools
|
|
2
2
|
../../core/azure-core
|
|
3
|
-
{% if token_credential
|
|
3
|
+
{% if token_credential %}
|
|
4
4
|
../../identity/azure-identity
|
|
5
5
|
{% endif -%}
|
|
6
|
-
{% if azure_arm
|
|
6
|
+
{% if azure_arm %}
|
|
7
7
|
../../core/azure-mgmt-core
|
|
8
|
-
{% endif
|
|
8
|
+
{% endif %}
|
|
9
9
|
aiohttp
|
|
@@ -2,19 +2,27 @@
|
|
|
2
2
|
{{ license_header }}
|
|
3
3
|
# coding: utf-8
|
|
4
4
|
{% if package_mode %}
|
|
5
|
+
|
|
5
6
|
import os
|
|
6
7
|
import re
|
|
7
|
-
{% endif
|
|
8
|
+
{% endif %}
|
|
8
9
|
from setuptools import setup, find_packages
|
|
9
10
|
|
|
10
11
|
{% set package_name = package_name or code_model.clients[0].name %}
|
|
11
12
|
|
|
12
13
|
PACKAGE_NAME = "{{ package_name|lower }}"
|
|
13
|
-
{% if package_mode
|
|
14
|
+
{% if package_mode %}
|
|
14
15
|
PACKAGE_PPRINT_NAME = "{{ package_pprint_name }}"
|
|
16
|
+
{% if code_model.is_tsp %}
|
|
17
|
+
PACKAGE_NAMESPACE = "{{ code_model.namespace|lower }}"
|
|
18
|
+
|
|
19
|
+
# a.b.c => a/b/c
|
|
20
|
+
package_folder_path = PACKAGE_NAMESPACE.replace(".", "/")
|
|
21
|
+
{% else %}
|
|
15
22
|
|
|
16
23
|
# a-b-c => a/b/c
|
|
17
24
|
package_folder_path = PACKAGE_NAME.replace("-", "/")
|
|
25
|
+
{% endif %}
|
|
18
26
|
|
|
19
27
|
# Version extraction inspired from 'requests'
|
|
20
28
|
with open(os.path.join(package_folder_path, "_version.py"), "r") as fd:
|
|
@@ -33,7 +41,8 @@ version = "{{ package_version }}"
|
|
|
33
41
|
{% set long_description = code_model.description %}
|
|
34
42
|
{% set author_email = "" %}
|
|
35
43
|
{% set url = "" %}
|
|
36
|
-
{% endif
|
|
44
|
+
{% endif %}
|
|
45
|
+
|
|
37
46
|
|
|
38
47
|
setup(
|
|
39
48
|
name=PACKAGE_NAME,
|
|
@@ -70,9 +79,9 @@ setup(
|
|
|
70
79
|
{% if pkgutil_names %}
|
|
71
80
|
# Exclude packages that will be covered by PEP420 or nspkg
|
|
72
81
|
{% endif %}
|
|
73
|
-
{
|
|
82
|
+
{% for pkgutil_name in pkgutil_names %}
|
|
74
83
|
"{{ pkgutil_name }}",
|
|
75
|
-
{
|
|
84
|
+
{% endfor %}
|
|
76
85
|
]
|
|
77
86
|
),
|
|
78
87
|
include_package_data=True,
|
|
@@ -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",
|