@autorest/python 6.15.0 → 6.17.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/generator/pygen/__init__.py +1 -1
- package/generator/pygen/black.py +7 -8
- package/generator/pygen/codegen/__init__.py +4 -0
- package/generator/pygen/codegen/models/client.py +2 -1
- package/generator/pygen/codegen/models/model_type.py +5 -1
- package/generator/pygen/codegen/models/operation.py +2 -0
- package/generator/pygen/codegen/serializers/__init__.py +4 -0
- package/generator/pygen/codegen/serializers/builder_serializer.py +75 -20
- package/generator/pygen/codegen/serializers/parameter_serializer.py +1 -1
- package/generator/pygen/codegen/templates/model_base.py.jinja2 +1 -0
- package/generator/pygen/codegen/templates/request_builder.py.jinja2 +2 -2
- package/generator/pygen/preprocess/__init__.py +10 -4
- package/generator/pygen/preprocess/python_mappings.py +5 -3
- package/generator/pygen/utils.py +4 -0
- package/package.json +2 -2
- package/scripts/__pycache__/venvtools.cpython-310.pyc +0 -0
- package/scripts/__pycache__/venvtools.cpython-38.pyc +0 -0
|
@@ -54,7 +54,7 @@ class ReaderAndWriter:
|
|
|
54
54
|
fd.write(file_content)
|
|
55
55
|
|
|
56
56
|
def list_file(self) -> List[str]:
|
|
57
|
-
return [str(f) for f in self.output_folder.glob("**/*") if f.is_file()]
|
|
57
|
+
return [str(f.relative_to(self.output_folder)) for f in self.output_folder.glob("**/*") if f.is_file()]
|
|
58
58
|
|
|
59
59
|
|
|
60
60
|
class Plugin(ReaderAndWriter, ABC):
|
package/generator/pygen/black.py
CHANGED
|
@@ -37,15 +37,14 @@ class BlackScriptPlugin(Plugin): # pylint: disable=abstract-method
|
|
|
37
37
|
[
|
|
38
38
|
Path(f)
|
|
39
39
|
for f in self.list_file()
|
|
40
|
-
if
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
".mypy_cache",
|
|
47
|
-
)
|
|
40
|
+
if Path(f).parts[0]
|
|
41
|
+
not in (
|
|
42
|
+
"__pycache__",
|
|
43
|
+
"node_modules",
|
|
44
|
+
"venv",
|
|
45
|
+
"env",
|
|
48
46
|
)
|
|
47
|
+
and not Path(f).parts[0].startswith(".")
|
|
49
48
|
and Path(f).suffix == ".py"
|
|
50
49
|
],
|
|
51
50
|
)
|
|
@@ -164,6 +164,10 @@ class OptionsRetriever:
|
|
|
164
164
|
except AttributeError:
|
|
165
165
|
return packaging_files_config
|
|
166
166
|
|
|
167
|
+
@property
|
|
168
|
+
def package_version(self) -> Optional[str]:
|
|
169
|
+
return str(self.options.get("package-version", ""))
|
|
170
|
+
|
|
167
171
|
|
|
168
172
|
class CodeGenerator(Plugin):
|
|
169
173
|
def __init__(self, *args, **kwargs: Any) -> None:
|
|
@@ -18,6 +18,7 @@ from .request_builder import (
|
|
|
18
18
|
from .parameter import Parameter, ParameterMethodLocation
|
|
19
19
|
from .lro_operation import LROOperation
|
|
20
20
|
from .lro_paging_operation import LROPagingOperation
|
|
21
|
+
from ...utils import extract_original_name
|
|
21
22
|
|
|
22
23
|
ParameterListType = TypeVar(
|
|
23
24
|
"ParameterListType",
|
|
@@ -92,7 +93,7 @@ class Client(_ClientConfigBase[ClientGlobalParameterList]):
|
|
|
92
93
|
if operation_yaml.get("isLroInitialOperation"):
|
|
93
94
|
# we want to change the name
|
|
94
95
|
request_builder.name = request_builder.get_name(
|
|
95
|
-
request_builder.yaml_data["name"]
|
|
96
|
+
extract_original_name(request_builder.yaml_data["name"]),
|
|
96
97
|
request_builder.yaml_data,
|
|
97
98
|
request_builder.code_model,
|
|
98
99
|
request_builder.client,
|
|
@@ -32,6 +32,10 @@ class UsageFlags(Enum):
|
|
|
32
32
|
ApiVersionEnum = 8
|
|
33
33
|
JsonMergePatch = 16
|
|
34
34
|
MultipartFormData = 32
|
|
35
|
+
Spread = 64
|
|
36
|
+
Error = 128
|
|
37
|
+
Json = 256
|
|
38
|
+
Xml = 512
|
|
35
39
|
|
|
36
40
|
|
|
37
41
|
def _get_properties(type: "ModelType", properties: List[Property]) -> List[Property]:
|
|
@@ -86,7 +90,7 @@ class ModelType( # pylint: disable=abstract-method
|
|
|
86
90
|
|
|
87
91
|
@property
|
|
88
92
|
def is_usage_output(self) -> bool:
|
|
89
|
-
return self.usage
|
|
93
|
+
return self.usage & UsageFlags.Output.value
|
|
90
94
|
|
|
91
95
|
@property
|
|
92
96
|
def flattened_property(self) -> Optional[Property]:
|
|
@@ -343,6 +343,8 @@ class OperationBase( # pylint: disable=too-many-public-methods,too-many-instanc
|
|
|
343
343
|
"ResourceExistsError",
|
|
344
344
|
"ResourceNotModifiedError",
|
|
345
345
|
]
|
|
346
|
+
if self.stream_value:
|
|
347
|
+
errors.extend(["StreamConsumedError", "StreamClosedError"])
|
|
346
348
|
for error in errors:
|
|
347
349
|
file_import.add_submodule_import("exceptions", error, ImportType.SDKCORE)
|
|
348
350
|
if self.code_model.options["azure_arm"]:
|
|
@@ -555,6 +555,10 @@ class JinjaSerializer(ReaderAndWriter): # pylint: disable=abstract-method
|
|
|
555
555
|
|
|
556
556
|
for client in self.code_model.clients:
|
|
557
557
|
for og in client.operation_groups:
|
|
558
|
+
if self.code_model.options["multiapi"] and any(
|
|
559
|
+
o.api_versions[0] != self.code_model.options["default_api_version"] for o in og.operations
|
|
560
|
+
):
|
|
561
|
+
continue
|
|
558
562
|
test_serializer = TestSerializer(self.code_model, env, client=client, operation_group=og)
|
|
559
563
|
for is_async in (True, False):
|
|
560
564
|
try:
|
|
@@ -58,6 +58,10 @@ OperationType = TypeVar(
|
|
|
58
58
|
)
|
|
59
59
|
|
|
60
60
|
|
|
61
|
+
def _all_same(data: List[List[str]]) -> bool:
|
|
62
|
+
return len(data) > 1 and all(sorted(data[0]) == sorted(data[i]) for i in range(1, len(data)))
|
|
63
|
+
|
|
64
|
+
|
|
61
65
|
def _json_serializable(content_type: str) -> bool:
|
|
62
66
|
return bool(JSON_REGEXP.match(content_type.split(";")[0].strip().lower()))
|
|
63
67
|
|
|
@@ -410,14 +414,19 @@ class RequestBuilderSerializer(_BuilderBaseSerializer[RequestBuilderType]): # p
|
|
|
410
414
|
return "response.json()"
|
|
411
415
|
|
|
412
416
|
@staticmethod
|
|
413
|
-
def
|
|
417
|
+
def declare_non_inputtable_headers_queries(builder: RequestBuilderType) -> List[str]:
|
|
414
418
|
def _get_value(param):
|
|
419
|
+
declaration = param.get_declaration() if param.constant else None
|
|
415
420
|
if param.location in [ParameterLocation.HEADER, ParameterLocation.QUERY]:
|
|
416
421
|
kwarg_dict = "headers" if param.location == ParameterLocation.HEADER else "params"
|
|
417
|
-
return f"_{kwarg_dict}.pop('{param.wire_name}', {
|
|
418
|
-
return
|
|
422
|
+
return f"_{kwarg_dict}.pop('{param.wire_name}', {declaration})"
|
|
423
|
+
return declaration
|
|
419
424
|
|
|
420
|
-
return [
|
|
425
|
+
return [
|
|
426
|
+
f"{p.client_name} = {_get_value(p)}"
|
|
427
|
+
for p in (builder.parameters.headers + builder.parameters.query)
|
|
428
|
+
if not p.in_method_signature
|
|
429
|
+
]
|
|
421
430
|
|
|
422
431
|
@property
|
|
423
432
|
def _function_def(self) -> str:
|
|
@@ -561,16 +570,22 @@ class _OperationSerializer(_BuilderBaseSerializer[OperationType]): # pylint: di
|
|
|
561
570
|
return retval
|
|
562
571
|
|
|
563
572
|
def make_pipeline_call(self, builder: OperationType) -> List[str]:
|
|
573
|
+
retval = []
|
|
564
574
|
type_ignore = self.async_mode and builder.group_name == "" # is in a mixin
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
575
|
+
if builder.stream_value is True and not self.code_model.options["version_tolerant"]:
|
|
576
|
+
retval.append("_decompress = kwargs.pop('decompress', True)")
|
|
577
|
+
retval.extend(
|
|
578
|
+
[
|
|
579
|
+
f"_stream = {builder.stream_value}",
|
|
580
|
+
f"pipeline_response: PipelineResponse = {self._call_method}self._client.{self.pipeline_name}.run( "
|
|
581
|
+
+ f"{'# type: ignore' if type_ignore else ''} # pylint: disable=protected-access",
|
|
582
|
+
" _request,",
|
|
583
|
+
" stream=_stream,",
|
|
584
|
+
" **kwargs",
|
|
585
|
+
")",
|
|
586
|
+
]
|
|
587
|
+
)
|
|
588
|
+
return retval
|
|
574
589
|
|
|
575
590
|
@property
|
|
576
591
|
def _function_def(self) -> str:
|
|
@@ -894,6 +909,9 @@ class _OperationSerializer(_BuilderBaseSerializer[OperationType]): # pylint: di
|
|
|
894
909
|
builder: OperationType,
|
|
895
910
|
response: Response,
|
|
896
911
|
) -> List[str]:
|
|
912
|
+
return self.response_headers(response) + self.response_deserialization(builder, response)
|
|
913
|
+
|
|
914
|
+
def response_headers(self, response: Response) -> List[str]:
|
|
897
915
|
retval: List[str] = [
|
|
898
916
|
(
|
|
899
917
|
f"response_headers['{response_header.wire_name}']=self._deserialize("
|
|
@@ -903,6 +921,14 @@ class _OperationSerializer(_BuilderBaseSerializer[OperationType]): # pylint: di
|
|
|
903
921
|
]
|
|
904
922
|
if response.headers:
|
|
905
923
|
retval.append("")
|
|
924
|
+
return retval
|
|
925
|
+
|
|
926
|
+
def response_deserialization(
|
|
927
|
+
self,
|
|
928
|
+
builder: OperationType,
|
|
929
|
+
response: Response,
|
|
930
|
+
) -> List[str]:
|
|
931
|
+
retval: List[str] = []
|
|
906
932
|
deserialize_code: List[str] = []
|
|
907
933
|
stream_logic = True
|
|
908
934
|
if builder.has_stream_response:
|
|
@@ -913,7 +939,9 @@ class _OperationSerializer(_BuilderBaseSerializer[OperationType]): # pylint: di
|
|
|
913
939
|
if self.code_model.options["version_tolerant"]:
|
|
914
940
|
deserialized = "response.iter_bytes()"
|
|
915
941
|
else:
|
|
916
|
-
deserialized =
|
|
942
|
+
deserialized = (
|
|
943
|
+
f"response.stream_download(self._client.{self.pipeline_name}, decompress=_decompress)"
|
|
944
|
+
)
|
|
917
945
|
deserialize_code.append(f"deserialized = {deserialized}")
|
|
918
946
|
elif response.type:
|
|
919
947
|
pylint_disable = ""
|
|
@@ -961,11 +989,17 @@ class _OperationSerializer(_BuilderBaseSerializer[OperationType]): # pylint: di
|
|
|
961
989
|
def handle_error_response(self, builder: OperationType) -> List[str]:
|
|
962
990
|
async_await = "await " if self.async_mode else ""
|
|
963
991
|
retval = [f"if response.status_code not in {str(builder.success_status_codes)}:"]
|
|
964
|
-
response_read =
|
|
992
|
+
response_read = [
|
|
993
|
+
" try:",
|
|
994
|
+
f" {async_await}response.read() # Load the body in memory and close the socket",
|
|
995
|
+
" except (StreamConsumedError, StreamClosedError):",
|
|
996
|
+
" pass",
|
|
997
|
+
]
|
|
965
998
|
if builder.stream_value is True: # _stream is True so no need to judge it
|
|
966
|
-
retval.
|
|
999
|
+
retval.extend(response_read)
|
|
967
1000
|
elif isinstance(builder.stream_value, str): # _stream is not sure, so we need to judge it
|
|
968
|
-
retval.
|
|
1001
|
+
retval.append(" if _stream:")
|
|
1002
|
+
retval.extend([f" {l}" for l in response_read])
|
|
969
1003
|
type_ignore = " # type: ignore" if _need_type_ignore(builder) else ""
|
|
970
1004
|
retval.append(
|
|
971
1005
|
f" map_error(status_code=response.status_code, response=response, error_map=error_map){type_ignore}"
|
|
@@ -999,13 +1033,34 @@ class _OperationSerializer(_BuilderBaseSerializer[OperationType]): # pylint: di
|
|
|
999
1033
|
retval.append("response_headers = {}")
|
|
1000
1034
|
if builder.has_response_body or builder.any_response_has_headers:
|
|
1001
1035
|
if len(builder.responses) > 1:
|
|
1036
|
+
status_codes, res_headers, res_deserialization = [], [], []
|
|
1002
1037
|
for status_code in builder.success_status_codes:
|
|
1003
1038
|
response = builder.get_response_from_status(status_code)
|
|
1004
1039
|
if response.headers or response.type:
|
|
1040
|
+
status_codes.append(status_code)
|
|
1041
|
+
res_headers.append(self.response_headers(response))
|
|
1042
|
+
res_deserialization.append(self.response_deserialization(builder, response))
|
|
1043
|
+
|
|
1044
|
+
is_headers_same = _all_same(res_headers)
|
|
1045
|
+
is_deserialization_same = _all_same(res_deserialization)
|
|
1046
|
+
if is_deserialization_same:
|
|
1047
|
+
if is_headers_same:
|
|
1048
|
+
retval.extend(res_headers[0])
|
|
1049
|
+
retval.extend(res_deserialization[0])
|
|
1050
|
+
retval.append("")
|
|
1051
|
+
else:
|
|
1052
|
+
for status_code, headers in zip(status_codes, res_headers):
|
|
1053
|
+
if headers:
|
|
1054
|
+
retval.append(f"if response.status_code == {status_code}:")
|
|
1055
|
+
retval.extend([f" {line}" for line in headers])
|
|
1056
|
+
retval.append("")
|
|
1057
|
+
retval.extend(res_deserialization[0])
|
|
1058
|
+
retval.append("")
|
|
1059
|
+
else:
|
|
1060
|
+
for status_code, headers, deserialization in zip(status_codes, res_headers, res_deserialization):
|
|
1005
1061
|
retval.append(f"if response.status_code == {status_code}:")
|
|
1006
|
-
retval.extend(
|
|
1007
|
-
|
|
1008
|
-
)
|
|
1062
|
+
retval.extend([f" {line}" for line in headers])
|
|
1063
|
+
retval.extend([f" {line}" for line in deserialization])
|
|
1009
1064
|
retval.append("")
|
|
1010
1065
|
else:
|
|
1011
1066
|
retval.extend(self.response_headers_and_deserialization(builder, builder.responses[0]))
|
|
@@ -148,7 +148,7 @@ class ParameterSerializer:
|
|
|
148
148
|
param.wire_name,
|
|
149
149
|
ParameterSerializer.serialize_parameter(param, serializer_name),
|
|
150
150
|
)
|
|
151
|
-
if not param.optional:
|
|
151
|
+
if not param.optional and (param.in_method_signature or param.constant):
|
|
152
152
|
retval = [set_parameter]
|
|
153
153
|
else:
|
|
154
154
|
retval = [
|
|
@@ -8,8 +8,8 @@
|
|
|
8
8
|
{% if request_builder_serializer.pop_kwargs_from_signature(request_builder) %}
|
|
9
9
|
{{ op_tools.serialize(request_builder_serializer.pop_kwargs_from_signature(request_builder)) | indent }}
|
|
10
10
|
{%- endif -%}
|
|
11
|
-
{% if request_builder_serializer.
|
|
12
|
-
{{ op_tools.serialize(request_builder_serializer.
|
|
11
|
+
{% if request_builder_serializer.declare_non_inputtable_headers_queries(request_builder) %}
|
|
12
|
+
{{ op_tools.serialize(request_builder_serializer.declare_non_inputtable_headers_queries(request_builder)) | indent }}
|
|
13
13
|
{% endif %}
|
|
14
14
|
# Construct URL
|
|
15
15
|
{{ request_builder_serializer.construct_url(request_builder) }}
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
import copy
|
|
9
9
|
from typing import Callable, Dict, Any, List, Optional
|
|
10
10
|
|
|
11
|
-
from ..utils import to_snake_case
|
|
11
|
+
from ..utils import to_snake_case, extract_original_name
|
|
12
12
|
from .helpers import (
|
|
13
13
|
add_redefined_builtin_info,
|
|
14
14
|
pad_builtin_namespaces,
|
|
@@ -235,7 +235,8 @@ class PreProcessPlugin(YamlUpdatePlugin): # pylint: disable=abstract-method
|
|
|
235
235
|
property["clientName"] = self.pad_reserved_words(property["clientName"].lower(), PadType.PROPERTY)
|
|
236
236
|
add_redefined_builtin_info(property["clientName"], property)
|
|
237
237
|
if type.get("name"):
|
|
238
|
-
|
|
238
|
+
pad_type = PadType.MODEL if type["type"] == "model" else PadType.ENUM_CLASS
|
|
239
|
+
name = self.pad_reserved_words(type["name"], pad_type)
|
|
239
240
|
type["name"] = name[0].upper() + name[1:]
|
|
240
241
|
type["description"] = update_description(type.get("description", ""), type["name"])
|
|
241
242
|
type["snakeCaseName"] = to_snake_case(type["name"])
|
|
@@ -243,7 +244,7 @@ class PreProcessPlugin(YamlUpdatePlugin): # pylint: disable=abstract-method
|
|
|
243
244
|
# we're enums
|
|
244
245
|
values_to_add = []
|
|
245
246
|
for value in type["values"]:
|
|
246
|
-
padded_name = self.pad_reserved_words(value["name"].lower(), PadType.
|
|
247
|
+
padded_name = self.pad_reserved_words(value["name"].lower(), PadType.ENUM_VALUE).upper()
|
|
247
248
|
if self.version_tolerant:
|
|
248
249
|
if padded_name[0] in "0123456789":
|
|
249
250
|
padded_name = "ENUM_" + padded_name
|
|
@@ -362,7 +363,12 @@ class PreProcessPlugin(YamlUpdatePlugin): # pylint: disable=abstract-method
|
|
|
362
363
|
yaml_data["groupName"] = self.pad_reserved_words(yaml_data["groupName"], PadType.OPERATION_GROUP)
|
|
363
364
|
yaml_data["groupName"] = to_snake_case(yaml_data["groupName"])
|
|
364
365
|
yaml_data["name"] = yaml_data["name"].lower()
|
|
365
|
-
yaml_data
|
|
366
|
+
if yaml_data.get("isLroInitialOperation") is True:
|
|
367
|
+
yaml_data["name"] = (
|
|
368
|
+
"_" + self.pad_reserved_words(extract_original_name(yaml_data["name"]), PadType.METHOD) + "_initial"
|
|
369
|
+
)
|
|
370
|
+
else:
|
|
371
|
+
yaml_data["name"] = self.pad_reserved_words(yaml_data["name"], PadType.METHOD)
|
|
366
372
|
yaml_data["description"] = update_description(yaml_data["description"], yaml_data["name"])
|
|
367
373
|
yaml_data["summary"] = update_description(yaml_data.get("summary", ""))
|
|
368
374
|
body_parameter = yaml_data.get("bodyParameter")
|
|
@@ -53,9 +53,10 @@ basic_latin_chars = {
|
|
|
53
53
|
|
|
54
54
|
class PadType(str, Enum):
|
|
55
55
|
MODEL = "Model"
|
|
56
|
+
ENUM_CLASS = "Enum"
|
|
56
57
|
METHOD = "_method"
|
|
57
58
|
PARAMETER = "_parameter"
|
|
58
|
-
|
|
59
|
+
ENUM_VALUE = "_enum"
|
|
59
60
|
PROPERTY = "_property"
|
|
60
61
|
OPERATION_GROUP = "Operations"
|
|
61
62
|
|
|
@@ -175,9 +176,10 @@ RESERVED_WORDS = {
|
|
|
175
176
|
"retry_on_status_codes",
|
|
176
177
|
*_always_reserved,
|
|
177
178
|
],
|
|
178
|
-
PadType.MODEL: [*_always_reserved],
|
|
179
|
+
PadType.MODEL: ["enum", *_always_reserved],
|
|
179
180
|
PadType.PROPERTY: ["self", *_always_reserved],
|
|
180
|
-
PadType.
|
|
181
|
+
PadType.ENUM_CLASS: ["enum", *_always_reserved],
|
|
182
|
+
PadType.ENUM_VALUE: ["mro", *_always_reserved],
|
|
181
183
|
PadType.OPERATION_GROUP: [*_always_reserved],
|
|
182
184
|
}
|
|
183
185
|
|
package/generator/pygen/utils.py
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@autorest/python",
|
|
3
|
-
"version": "6.
|
|
3
|
+
"version": "6.17.0",
|
|
4
4
|
"description": "The Python extension for generators in AutoRest.",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"repository": {
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
"devDependencies": {
|
|
26
26
|
"@microsoft.azure/autorest.testserver": "^3.3.46",
|
|
27
27
|
"typescript": "~5.1.3",
|
|
28
|
-
"@azure-tools/typespec-python": "^0.
|
|
28
|
+
"@azure-tools/typespec-python": "^0.27.0"
|
|
29
29
|
},
|
|
30
30
|
"files": [
|
|
31
31
|
"autorest/**/*.py",
|
|
Binary file
|
|
Binary file
|