@autorest/python 5.16.0 → 5.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/ChangeLog.md +43 -3
- package/README.md +30 -4
- package/autorest/__init__.py +1 -1
- package/autorest/codegen/__init__.py +48 -209
- package/autorest/codegen/models/__init__.py +116 -83
- package/autorest/codegen/models/base_builder.py +49 -88
- package/autorest/codegen/models/base_model.py +1 -1
- package/autorest/codegen/models/{base_schema.py → base_type.py} +56 -40
- package/autorest/codegen/models/client.py +157 -48
- package/autorest/codegen/models/code_model.py +108 -254
- package/autorest/codegen/models/combined_type.py +107 -0
- package/autorest/codegen/models/{constant_schema.py → constant_type.py} +49 -40
- package/autorest/codegen/models/credential_types.py +224 -0
- package/autorest/codegen/models/{dictionary_schema.py → dictionary_type.py} +41 -31
- package/autorest/codegen/models/enum_type.py +195 -0
- package/autorest/codegen/models/imports.py +23 -0
- package/autorest/codegen/models/list_type.py +134 -0
- package/autorest/codegen/models/lro_operation.py +77 -156
- package/autorest/codegen/models/lro_paging_operation.py +28 -11
- package/autorest/codegen/models/model_type.py +239 -0
- package/autorest/codegen/models/operation.py +303 -269
- package/autorest/codegen/models/operation_group.py +48 -89
- package/autorest/codegen/models/paging_operation.py +80 -123
- package/autorest/codegen/models/parameter.py +289 -396
- package/autorest/codegen/models/parameter_list.py +348 -360
- package/autorest/codegen/models/primitive_types.py +544 -0
- package/autorest/codegen/models/property.py +109 -139
- package/autorest/codegen/models/request_builder.py +105 -88
- package/autorest/codegen/models/request_builder_parameter.py +112 -100
- package/autorest/codegen/models/response.py +325 -0
- package/autorest/codegen/models/utils.py +12 -19
- package/autorest/codegen/serializers/__init__.py +46 -37
- package/autorest/codegen/serializers/builder_serializer.py +604 -1146
- package/autorest/codegen/serializers/client_serializer.py +83 -88
- package/autorest/codegen/serializers/general_serializer.py +5 -64
- package/autorest/codegen/serializers/import_serializer.py +7 -4
- package/autorest/codegen/serializers/metadata_serializer.py +15 -104
- package/autorest/codegen/serializers/model_base_serializer.py +40 -32
- package/autorest/codegen/serializers/model_generic_serializer.py +8 -6
- package/autorest/codegen/serializers/model_init_serializer.py +2 -4
- package/autorest/codegen/serializers/model_python3_serializer.py +22 -16
- package/autorest/codegen/serializers/operation_groups_serializer.py +4 -13
- package/autorest/codegen/serializers/parameter_serializer.py +174 -0
- package/autorest/codegen/serializers/request_builders_serializer.py +12 -29
- package/autorest/codegen/serializers/utils.py +0 -142
- package/autorest/codegen/templates/MANIFEST.in.jinja2 +1 -0
- package/autorest/codegen/templates/{service_client.py.jinja2 → client.py.jinja2} +7 -7
- package/autorest/codegen/templates/config.py.jinja2 +13 -13
- package/autorest/codegen/templates/enum.py.jinja2 +4 -4
- package/autorest/codegen/templates/enum_container.py.jinja2 +1 -1
- package/autorest/codegen/templates/init.py.jinja2 +2 -2
- package/autorest/codegen/templates/lro_operation.py.jinja2 +4 -1
- package/autorest/codegen/templates/lro_paging_operation.py.jinja2 +4 -1
- package/autorest/codegen/templates/metadata.json.jinja2 +33 -33
- package/autorest/codegen/templates/model.py.jinja2 +23 -24
- package/autorest/codegen/templates/model_container.py.jinja2 +2 -1
- package/autorest/codegen/templates/model_init.py.jinja2 +3 -5
- package/autorest/codegen/templates/operation.py.jinja2 +6 -8
- package/autorest/codegen/templates/operation_group.py.jinja2 +7 -7
- package/autorest/codegen/templates/operation_groups_container.py.jinja2 +1 -1
- package/autorest/codegen/templates/operation_tools.jinja2 +8 -2
- package/autorest/codegen/templates/paging_operation.py.jinja2 +2 -2
- package/autorest/codegen/templates/request_builder.py.jinja2 +13 -11
- package/autorest/codegen/templates/setup.py.jinja2 +9 -3
- package/autorest/codegen/templates/vendor.py.jinja2 +1 -1
- package/autorest/jsonrpc/server.py +15 -3
- package/autorest/m4reformatter/__init__.py +1108 -0
- package/autorest/multiapi/models/code_model.py +1 -1
- package/autorest/multiapi/serializers/__init__.py +4 -4
- package/autorest/multiapi/templates/multiapi_config.py.jinja2 +3 -3
- package/autorest/multiapi/templates/multiapi_init.py.jinja2 +2 -2
- package/autorest/multiapi/templates/multiapi_operations_mixin.py.jinja2 +3 -3
- package/autorest/multiapi/templates/multiapi_service_client.py.jinja2 +9 -9
- package/autorest/postprocess/__init__.py +202 -0
- package/autorest/postprocess/get_all.py +19 -0
- package/autorest/postprocess/venvtools.py +73 -0
- package/autorest/preprocess/__init__.py +209 -0
- package/autorest/preprocess/helpers.py +54 -0
- package/autorest/{namer → preprocess}/python_mappings.py +21 -16
- package/package.json +2 -2
- package/autorest/codegen/models/credential_model.py +0 -55
- package/autorest/codegen/models/credential_schema.py +0 -95
- package/autorest/codegen/models/credential_schema_policy.py +0 -73
- package/autorest/codegen/models/enum_schema.py +0 -225
- package/autorest/codegen/models/list_schema.py +0 -135
- package/autorest/codegen/models/object_schema.py +0 -303
- package/autorest/codegen/models/primitive_schemas.py +0 -495
- package/autorest/codegen/models/request_builder_parameter_list.py +0 -249
- package/autorest/codegen/models/schema_request.py +0 -55
- package/autorest/codegen/models/schema_response.py +0 -141
- package/autorest/namer/__init__.py +0 -23
- package/autorest/namer/name_converter.py +0 -509
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
# -------------------------------------------------------------------------
|
|
2
|
+
# Copyright (c) Microsoft Corporation. All rights reserved.
|
|
3
|
+
# Licensed under the MIT License. See License.txt in the project root for
|
|
4
|
+
# license information.
|
|
5
|
+
# --------------------------------------------------------------------------
|
|
6
|
+
from typing import Any, Dict, List, TYPE_CHECKING, Optional
|
|
7
|
+
|
|
8
|
+
from .base_type import BaseType
|
|
9
|
+
from .imports import FileImport, ImportType, TypingSection
|
|
10
|
+
from .base_model import BaseModel
|
|
11
|
+
|
|
12
|
+
if TYPE_CHECKING:
|
|
13
|
+
from .code_model import CodeModel
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class EnumValue(BaseModel):
|
|
17
|
+
"""Model containing necessary information for a single value of an enum.
|
|
18
|
+
|
|
19
|
+
:param str name: The name of this enum value
|
|
20
|
+
:param str value: The value of this enum value
|
|
21
|
+
:param str description: Optional. The description for this enum value
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
def __init__(self, yaml_data: Dict[str, Any], code_model: "CodeModel") -> None:
|
|
25
|
+
super().__init__(yaml_data=yaml_data, code_model=code_model)
|
|
26
|
+
self.name: str = self.yaml_data["name"]
|
|
27
|
+
self.value: str = self.yaml_data["value"]
|
|
28
|
+
self.description: Optional[str] = self.yaml_data.get("description")
|
|
29
|
+
|
|
30
|
+
@classmethod
|
|
31
|
+
def from_yaml(
|
|
32
|
+
cls, yaml_data: Dict[str, Any], code_model: "CodeModel"
|
|
33
|
+
) -> "EnumValue":
|
|
34
|
+
"""Constructs an EnumValue from yaml data.
|
|
35
|
+
|
|
36
|
+
:param yaml_data: the yaml data from which we will construct this object
|
|
37
|
+
:type yaml_data: dict[str, Any]
|
|
38
|
+
|
|
39
|
+
:return: A created EnumValue
|
|
40
|
+
:rtype: ~autorest.models.EnumValue
|
|
41
|
+
"""
|
|
42
|
+
return cls(
|
|
43
|
+
yaml_data=yaml_data,
|
|
44
|
+
code_model=code_model,
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
class EnumType(BaseType):
|
|
49
|
+
"""Schema for enums that will be serialized.
|
|
50
|
+
|
|
51
|
+
:param yaml_data: the yaml data for this schema
|
|
52
|
+
:type yaml_data: dict[str, Any]
|
|
53
|
+
:param str description: The description of this enum
|
|
54
|
+
:param str name: The name of the enum.
|
|
55
|
+
:type element_type: ~autorest.models.PrimitiveType
|
|
56
|
+
:param values: List of the values for this enum
|
|
57
|
+
:type values: list[~autorest.models.EnumValue]
|
|
58
|
+
"""
|
|
59
|
+
|
|
60
|
+
def __init__(
|
|
61
|
+
self,
|
|
62
|
+
yaml_data: Dict[str, Any],
|
|
63
|
+
code_model: "CodeModel",
|
|
64
|
+
values: List["EnumValue"],
|
|
65
|
+
value_type: BaseType,
|
|
66
|
+
) -> None:
|
|
67
|
+
super().__init__(yaml_data=yaml_data, code_model=code_model)
|
|
68
|
+
self.name: str = yaml_data["name"]
|
|
69
|
+
self.values = values
|
|
70
|
+
self.value_type = value_type
|
|
71
|
+
|
|
72
|
+
def __lt__(self, other):
|
|
73
|
+
return self.name.lower() < other.name.lower()
|
|
74
|
+
|
|
75
|
+
@property
|
|
76
|
+
def serialization_type(self) -> str:
|
|
77
|
+
"""Returns the serialization value for msrest.
|
|
78
|
+
|
|
79
|
+
:return: The serialization value for msrest
|
|
80
|
+
:rtype: str
|
|
81
|
+
"""
|
|
82
|
+
return self.value_type.serialization_type
|
|
83
|
+
|
|
84
|
+
def description(
|
|
85
|
+
self, *, is_operation_file: bool # pylint: disable=unused-argument
|
|
86
|
+
) -> str:
|
|
87
|
+
possible_values = [self.get_declaration(v.value) for v in self.values]
|
|
88
|
+
if not possible_values:
|
|
89
|
+
return ""
|
|
90
|
+
if len(possible_values) == 1:
|
|
91
|
+
return possible_values[0]
|
|
92
|
+
if len(possible_values) == 2:
|
|
93
|
+
possible_values_str = " and ".join(possible_values)
|
|
94
|
+
else:
|
|
95
|
+
possible_values_str = (
|
|
96
|
+
", ".join(possible_values[: len(possible_values) - 1])
|
|
97
|
+
+ f", and {possible_values[-1]}"
|
|
98
|
+
)
|
|
99
|
+
|
|
100
|
+
enum_description = f"Known values are: {possible_values_str}."
|
|
101
|
+
return enum_description
|
|
102
|
+
|
|
103
|
+
def type_annotation(self, **kwargs: Any) -> str:
|
|
104
|
+
"""The python type used for type annotation
|
|
105
|
+
|
|
106
|
+
:return: The type annotation for this schema
|
|
107
|
+
:rtype: str
|
|
108
|
+
"""
|
|
109
|
+
if self.code_model.options["models_mode"]:
|
|
110
|
+
return (
|
|
111
|
+
f"Union[{self.value_type.type_annotation(**kwargs)},"
|
|
112
|
+
f' "_models.{self.name}"]'
|
|
113
|
+
)
|
|
114
|
+
return self.value_type.type_annotation(**kwargs)
|
|
115
|
+
|
|
116
|
+
def get_declaration(self, value: Any) -> str:
|
|
117
|
+
return self.value_type.get_declaration(value)
|
|
118
|
+
|
|
119
|
+
def docstring_text(self, **kwargs: Any) -> str:
|
|
120
|
+
if self.code_model.options["models_mode"]:
|
|
121
|
+
return self.name
|
|
122
|
+
return self.value_type.type_annotation(**kwargs)
|
|
123
|
+
|
|
124
|
+
def docstring_type(self, **kwargs: Any) -> str:
|
|
125
|
+
"""The python type used for RST syntax input and type annotation."""
|
|
126
|
+
if self.code_model.options["models_mode"]:
|
|
127
|
+
return f"{self.value_type.type_annotation(**kwargs)} or ~{self.code_model.namespace}.models.{self.name}"
|
|
128
|
+
return self.value_type.type_annotation(**kwargs)
|
|
129
|
+
|
|
130
|
+
def get_json_template_representation(
|
|
131
|
+
self,
|
|
132
|
+
*,
|
|
133
|
+
optional: bool = True,
|
|
134
|
+
client_default_value_declaration: Optional[str] = None,
|
|
135
|
+
description: Optional[str] = None,
|
|
136
|
+
) -> Any:
|
|
137
|
+
# for better display effect, use the only value instead of var type
|
|
138
|
+
return self.value_type.get_json_template_representation(
|
|
139
|
+
optional=optional,
|
|
140
|
+
client_default_value_declaration=client_default_value_declaration,
|
|
141
|
+
description=description,
|
|
142
|
+
)
|
|
143
|
+
|
|
144
|
+
@property
|
|
145
|
+
def instance_check_template(self) -> str:
|
|
146
|
+
return self.value_type.instance_check_template
|
|
147
|
+
|
|
148
|
+
@classmethod
|
|
149
|
+
def from_yaml(
|
|
150
|
+
cls, yaml_data: Dict[str, Any], code_model: "CodeModel"
|
|
151
|
+
) -> "EnumType":
|
|
152
|
+
"""Constructs an EnumType from yaml data.
|
|
153
|
+
|
|
154
|
+
:param yaml_data: the yaml data from which we will construct this schema
|
|
155
|
+
:type yaml_data: dict[str, Any]
|
|
156
|
+
|
|
157
|
+
:return: A created EnumType
|
|
158
|
+
:rtype: ~autorest.models.EnumType
|
|
159
|
+
"""
|
|
160
|
+
from . import build_type
|
|
161
|
+
|
|
162
|
+
return cls(
|
|
163
|
+
yaml_data=yaml_data,
|
|
164
|
+
code_model=code_model,
|
|
165
|
+
value_type=build_type(yaml_data["valueType"], code_model),
|
|
166
|
+
values=[
|
|
167
|
+
EnumValue.from_yaml(value, code_model) for value in yaml_data["values"]
|
|
168
|
+
],
|
|
169
|
+
)
|
|
170
|
+
|
|
171
|
+
def imports(self, **kwargs: Any) -> FileImport:
|
|
172
|
+
is_operation_file = kwargs.pop("is_operation_file", False)
|
|
173
|
+
file_import = FileImport()
|
|
174
|
+
if self.code_model.options["models_mode"]:
|
|
175
|
+
file_import.add_submodule_import(
|
|
176
|
+
"typing", "Union", ImportType.STDLIB, TypingSection.CONDITIONAL
|
|
177
|
+
)
|
|
178
|
+
if not is_operation_file:
|
|
179
|
+
file_import.add_submodule_import(
|
|
180
|
+
"..",
|
|
181
|
+
"models",
|
|
182
|
+
ImportType.LOCAL,
|
|
183
|
+
TypingSection.TYPING,
|
|
184
|
+
alias="_models",
|
|
185
|
+
)
|
|
186
|
+
file_import.merge(
|
|
187
|
+
self.value_type.imports(is_operation_file=is_operation_file, **kwargs)
|
|
188
|
+
)
|
|
189
|
+
relative_path = kwargs.pop("relative_path", None)
|
|
190
|
+
if self.code_model.options["models_mode"] and relative_path:
|
|
191
|
+
# add import for enums in operations file
|
|
192
|
+
file_import.add_submodule_import(
|
|
193
|
+
relative_path, "models", ImportType.LOCAL, alias="_models"
|
|
194
|
+
)
|
|
195
|
+
return file_import
|
|
@@ -147,6 +147,29 @@ class FileImport:
|
|
|
147
147
|
self._append_import(i)
|
|
148
148
|
self.type_definitions.update(file_import.type_definitions)
|
|
149
149
|
|
|
150
|
+
def define_mutable_mapping_type(self) -> None:
|
|
151
|
+
"""Helper function for defining the mutable mapping type"""
|
|
152
|
+
self.define_mypy_type(
|
|
153
|
+
"JSON",
|
|
154
|
+
"MutableMapping[str, Any] # pylint: disable=unsubscriptable-object",
|
|
155
|
+
None,
|
|
156
|
+
{
|
|
157
|
+
(3, 9): ImportModel(
|
|
158
|
+
TypingSection.CONDITIONAL,
|
|
159
|
+
ImportType.STDLIB,
|
|
160
|
+
"collections.abc",
|
|
161
|
+
submodule_name="MutableMapping",
|
|
162
|
+
),
|
|
163
|
+
None: ImportModel(
|
|
164
|
+
TypingSection.CONDITIONAL,
|
|
165
|
+
ImportType.STDLIB,
|
|
166
|
+
"typing",
|
|
167
|
+
submodule_name="MutableMapping",
|
|
168
|
+
),
|
|
169
|
+
},
|
|
170
|
+
)
|
|
171
|
+
self.add_submodule_import("typing", "Any", ImportType.STDLIB)
|
|
172
|
+
|
|
150
173
|
def to_dict(
|
|
151
174
|
self,
|
|
152
175
|
) -> Dict[
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
# -------------------------------------------------------------------------
|
|
2
|
+
# Copyright (c) Microsoft Corporation. All rights reserved.
|
|
3
|
+
# Licensed under the MIT License. See License.txt in the project root for
|
|
4
|
+
# license information.
|
|
5
|
+
# --------------------------------------------------------------------------
|
|
6
|
+
from typing import Any, Dict, Optional, Union, TYPE_CHECKING
|
|
7
|
+
from .base_type import BaseType
|
|
8
|
+
from .imports import FileImport, ImportType, TypingSection
|
|
9
|
+
|
|
10
|
+
if TYPE_CHECKING:
|
|
11
|
+
from .code_model import CodeModel
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class ListType(BaseType):
|
|
15
|
+
def __init__(
|
|
16
|
+
self,
|
|
17
|
+
yaml_data: Dict[str, Any],
|
|
18
|
+
code_model: "CodeModel",
|
|
19
|
+
element_type: BaseType,
|
|
20
|
+
) -> None:
|
|
21
|
+
super().__init__(yaml_data=yaml_data, code_model=code_model)
|
|
22
|
+
self.element_type = element_type
|
|
23
|
+
self.max_items: Optional[int] = yaml_data.get("maxItems")
|
|
24
|
+
self.min_items: Optional[int] = yaml_data.get("minItems")
|
|
25
|
+
self.unique_items: bool = yaml_data.get("uniqueItems", False)
|
|
26
|
+
|
|
27
|
+
@property
|
|
28
|
+
def serialization_type(self) -> str:
|
|
29
|
+
return f"[{self.element_type.serialization_type}]"
|
|
30
|
+
|
|
31
|
+
def type_annotation(self, **kwargs: Any) -> str:
|
|
32
|
+
if self.code_model.options["version_tolerant"] and self.element_type.is_xml:
|
|
33
|
+
# this means we're version tolerant XML, we just return the XML element
|
|
34
|
+
return self.element_type.type_annotation(**kwargs)
|
|
35
|
+
return f"List[{self.element_type.type_annotation(**kwargs)}]"
|
|
36
|
+
|
|
37
|
+
def description(self, *, is_operation_file: bool) -> str:
|
|
38
|
+
return "" if is_operation_file else self.yaml_data.get("description", "")
|
|
39
|
+
|
|
40
|
+
@property
|
|
41
|
+
def xml_serialization_ctxt(self) -> Optional[str]:
|
|
42
|
+
attrs_list = []
|
|
43
|
+
base_xml_map = super().xml_serialization_ctxt
|
|
44
|
+
if base_xml_map:
|
|
45
|
+
attrs_list.append(base_xml_map)
|
|
46
|
+
|
|
47
|
+
# Attribute at the list level
|
|
48
|
+
if self.xml_metadata.get("wrapped", False):
|
|
49
|
+
attrs_list.append("'wrapped': True")
|
|
50
|
+
|
|
51
|
+
# Attributes of the items
|
|
52
|
+
item_xml_metadata = self.element_type.xml_metadata
|
|
53
|
+
if item_xml_metadata.get("name"):
|
|
54
|
+
attrs_list.append(f"'itemsName': '{item_xml_metadata['name']}'")
|
|
55
|
+
if item_xml_metadata.get("prefix", False):
|
|
56
|
+
attrs_list.append(f"'itemsPrefix': '{item_xml_metadata['prefix']}'")
|
|
57
|
+
if item_xml_metadata.get("namespace", False):
|
|
58
|
+
attrs_list.append(f"'itemsNs': '{item_xml_metadata['namespace']}'")
|
|
59
|
+
|
|
60
|
+
return ", ".join(attrs_list)
|
|
61
|
+
|
|
62
|
+
def docstring_type(self, **kwargs: Any) -> str:
|
|
63
|
+
if (
|
|
64
|
+
self.code_model.options["version_tolerant"]
|
|
65
|
+
and self.element_type.xml_metadata
|
|
66
|
+
):
|
|
67
|
+
# this means we're version tolerant XML, we just return the XML element
|
|
68
|
+
return self.element_type.docstring_type(**kwargs)
|
|
69
|
+
return f"list[{self.element_type.docstring_type(**kwargs)}]"
|
|
70
|
+
|
|
71
|
+
def docstring_text(self, **kwargs: Any) -> str:
|
|
72
|
+
if (
|
|
73
|
+
self.code_model.options["version_tolerant"]
|
|
74
|
+
and self.element_type.xml_metadata
|
|
75
|
+
):
|
|
76
|
+
# this means we're version tolerant XML, we just return the XML element
|
|
77
|
+
return self.element_type.docstring_text(**kwargs)
|
|
78
|
+
return f"list of {self.element_type.docstring_text(**kwargs)}"
|
|
79
|
+
|
|
80
|
+
@property
|
|
81
|
+
def validation(self) -> Optional[Dict[str, Union[bool, int, str]]]:
|
|
82
|
+
validation: Dict[str, Union[bool, int, str]] = {}
|
|
83
|
+
if self.max_items:
|
|
84
|
+
validation["max_items"] = self.max_items
|
|
85
|
+
validation["min_items"] = self.min_items or 0
|
|
86
|
+
if self.min_items:
|
|
87
|
+
validation["min_items"] = self.min_items
|
|
88
|
+
if self.unique_items:
|
|
89
|
+
validation["unique"] = True
|
|
90
|
+
return validation or None
|
|
91
|
+
|
|
92
|
+
def get_json_template_representation(
|
|
93
|
+
self,
|
|
94
|
+
*,
|
|
95
|
+
optional: bool = True,
|
|
96
|
+
client_default_value_declaration: Optional[str] = None,
|
|
97
|
+
description: Optional[str] = None,
|
|
98
|
+
) -> Any:
|
|
99
|
+
return [
|
|
100
|
+
self.element_type.get_json_template_representation(
|
|
101
|
+
optional=optional,
|
|
102
|
+
client_default_value_declaration=client_default_value_declaration,
|
|
103
|
+
description=description,
|
|
104
|
+
)
|
|
105
|
+
]
|
|
106
|
+
|
|
107
|
+
@property
|
|
108
|
+
def instance_check_template(self) -> str:
|
|
109
|
+
return "isinstance({}, list)"
|
|
110
|
+
|
|
111
|
+
@classmethod
|
|
112
|
+
def from_yaml(
|
|
113
|
+
cls, yaml_data: Dict[str, Any], code_model: "CodeModel"
|
|
114
|
+
) -> "ListType":
|
|
115
|
+
from . import build_type
|
|
116
|
+
|
|
117
|
+
return cls(
|
|
118
|
+
yaml_data=yaml_data,
|
|
119
|
+
code_model=code_model,
|
|
120
|
+
element_type=build_type(
|
|
121
|
+
yaml_data=yaml_data["elementType"], code_model=code_model
|
|
122
|
+
),
|
|
123
|
+
)
|
|
124
|
+
|
|
125
|
+
def imports(self, **kwargs: Any) -> FileImport:
|
|
126
|
+
file_import = FileImport()
|
|
127
|
+
if not (
|
|
128
|
+
self.code_model.options["version_tolerant"] and self.element_type.is_xml
|
|
129
|
+
):
|
|
130
|
+
file_import.add_submodule_import(
|
|
131
|
+
"typing", "List", ImportType.STDLIB, TypingSection.CONDITIONAL
|
|
132
|
+
)
|
|
133
|
+
file_import.merge(self.element_type.imports(**kwargs))
|
|
134
|
+
return file_import
|
|
@@ -3,218 +3,139 @@
|
|
|
3
3
|
# Licensed under the MIT License. See License.txt in the project root for
|
|
4
4
|
# license information.
|
|
5
5
|
# --------------------------------------------------------------------------
|
|
6
|
-
import
|
|
7
|
-
from typing import Dict, List, Any, Optional, Set, cast, TYPE_CHECKING
|
|
6
|
+
from typing import Any, Dict, Optional, List, TYPE_CHECKING, TypeVar, Union
|
|
8
7
|
from .imports import FileImport
|
|
9
|
-
from .operation import Operation
|
|
10
|
-
from .
|
|
11
|
-
from .schema_response import SchemaResponse
|
|
8
|
+
from .operation import OperationBase, Operation
|
|
9
|
+
from .response import LROPagingResponse, LROResponse, Response
|
|
12
10
|
from .imports import ImportType, TypingSection
|
|
13
|
-
from .base_schema import BaseSchema
|
|
14
|
-
from .schema_request import SchemaRequest
|
|
15
11
|
from .request_builder import RequestBuilder
|
|
12
|
+
from .parameter_list import ParameterList
|
|
16
13
|
|
|
17
14
|
if TYPE_CHECKING:
|
|
18
15
|
from .code_model import CodeModel
|
|
19
16
|
|
|
20
|
-
|
|
17
|
+
LROResponseType = TypeVar(
|
|
18
|
+
"LROResponseType", bound=Union[LROResponse, LROPagingResponse]
|
|
19
|
+
)
|
|
21
20
|
|
|
22
21
|
|
|
23
|
-
class
|
|
22
|
+
class LROOperationBase(OperationBase[LROResponseType]):
|
|
24
23
|
def __init__(
|
|
25
24
|
self,
|
|
26
25
|
yaml_data: Dict[str, Any],
|
|
27
26
|
code_model: "CodeModel",
|
|
28
|
-
request_builder: RequestBuilder,
|
|
29
27
|
name: str,
|
|
30
|
-
|
|
31
|
-
api_versions: Set[str],
|
|
28
|
+
request_builder: RequestBuilder,
|
|
32
29
|
parameters: ParameterList,
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
summary: Optional[str] = None,
|
|
36
|
-
responses: Optional[List[SchemaResponse]] = None,
|
|
37
|
-
exceptions: Optional[List[SchemaResponse]] = None,
|
|
38
|
-
want_description_docstring: bool = True,
|
|
39
|
-
want_tracing: bool = True,
|
|
30
|
+
responses: List[LROResponseType],
|
|
31
|
+
exceptions: List[Response],
|
|
40
32
|
*,
|
|
33
|
+
overloads: Optional[List[Operation]] = None,
|
|
34
|
+
public: bool = True,
|
|
35
|
+
want_tracing: bool = True,
|
|
41
36
|
abstract: bool = False,
|
|
42
37
|
) -> None:
|
|
43
38
|
super().__init__(
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
summary,
|
|
54
|
-
responses,
|
|
55
|
-
exceptions,
|
|
56
|
-
want_description_docstring,
|
|
39
|
+
code_model=code_model,
|
|
40
|
+
yaml_data=yaml_data,
|
|
41
|
+
name=name,
|
|
42
|
+
request_builder=request_builder,
|
|
43
|
+
parameters=parameters,
|
|
44
|
+
responses=responses,
|
|
45
|
+
exceptions=exceptions,
|
|
46
|
+
overloads=overloads,
|
|
47
|
+
public=public,
|
|
57
48
|
want_tracing=want_tracing,
|
|
58
49
|
abstract=abstract,
|
|
59
50
|
)
|
|
60
|
-
self.lro_options = yaml_data.get("extensions", {}).get(
|
|
61
|
-
"x-ms-long-running-operation-options", {}
|
|
62
|
-
)
|
|
63
51
|
self.name = "begin_" + self.name
|
|
52
|
+
self.lro_options: Dict[str, Any] = self.yaml_data.get("lroOptions", {})
|
|
64
53
|
|
|
65
54
|
@property
|
|
66
|
-
def
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
55
|
+
def operation_type(self) -> str:
|
|
56
|
+
return "lro"
|
|
57
|
+
|
|
58
|
+
@property
|
|
59
|
+
def has_optional_return_type(self) -> bool:
|
|
60
|
+
return False
|
|
61
|
+
|
|
62
|
+
@property
|
|
63
|
+
def lro_response(self) -> Optional[LROResponseType]:
|
|
64
|
+
responses_with_bodies = [r for r in self.responses if r.type]
|
|
65
|
+
num_response_schemas = {
|
|
66
|
+
id(r.type.yaml_data) for r in responses_with_bodies if r.type
|
|
67
|
+
}
|
|
71
68
|
response = None
|
|
72
69
|
if len(num_response_schemas) > 1:
|
|
73
70
|
# choose the response that has a status code of 200
|
|
74
|
-
responses_with_200_status_codes = [
|
|
75
|
-
r for r in responses_with_bodies if 200 in r.status_codes
|
|
76
|
-
]
|
|
77
71
|
try:
|
|
78
|
-
response =
|
|
79
|
-
|
|
80
|
-
response_schema = cast(BaseSchema, response.schema).serialization_type
|
|
81
|
-
_LOGGER.warning(
|
|
82
|
-
"Multiple schema types in responses: %s. Choosing: %s",
|
|
83
|
-
schema_types,
|
|
84
|
-
response_schema,
|
|
72
|
+
response = next(
|
|
73
|
+
r for r in responses_with_bodies if 200 in r.status_codes
|
|
85
74
|
)
|
|
86
|
-
except
|
|
75
|
+
except StopIteration:
|
|
87
76
|
raise ValueError(
|
|
88
77
|
f"Your swagger is invalid because you have multiple response schemas for LRO"
|
|
89
|
-
+ f" method {self.
|
|
78
|
+
+ f" method {self.name} and none of them have a 200 status code."
|
|
90
79
|
)
|
|
91
80
|
|
|
92
81
|
elif num_response_schemas:
|
|
93
82
|
response = responses_with_bodies[0]
|
|
94
83
|
return response
|
|
95
84
|
|
|
85
|
+
def cls_type_annotation(self, *, async_mode: bool) -> str:
|
|
86
|
+
"""We don't want the poller to show up in ClsType, so we call super() on resposne type annotation"""
|
|
87
|
+
return f"ClsType[{Response.type_annotation(self.responses[0], async_mode=async_mode)}]"
|
|
88
|
+
|
|
96
89
|
@property
|
|
97
90
|
def initial_operation(self) -> Operation:
|
|
98
|
-
operation
|
|
99
|
-
|
|
91
|
+
"""Initial operation that creates the first call for LRO polling"""
|
|
92
|
+
return Operation(
|
|
93
|
+
yaml_data=self.yaml_data,
|
|
100
94
|
code_model=self.code_model,
|
|
101
95
|
request_builder=self.code_model.lookup_request_builder(id(self.yaml_data)),
|
|
102
96
|
name=self.name[5:] + "_initial",
|
|
103
|
-
|
|
104
|
-
api_versions=self.api_versions,
|
|
97
|
+
overloads=self.overloads,
|
|
105
98
|
parameters=self.parameters,
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
99
|
+
responses=[
|
|
100
|
+
Response(r.yaml_data, self.code_model, headers=r.headers, type=r.type)
|
|
101
|
+
for r in self.responses
|
|
102
|
+
],
|
|
103
|
+
exceptions=self.exceptions,
|
|
104
|
+
public=False,
|
|
111
105
|
want_tracing=False,
|
|
112
106
|
)
|
|
113
|
-
operation.request_builder = self.request_builder
|
|
114
|
-
return operation
|
|
115
|
-
|
|
116
|
-
@property
|
|
117
|
-
def has_optional_return_type(self) -> bool:
|
|
118
|
-
"""An LROOperation will never have an optional return type, we will always return a poller"""
|
|
119
|
-
return False
|
|
120
|
-
|
|
121
|
-
def _get_lro_extension(self, extension_base, async_mode, *, azure_arm=None):
|
|
122
|
-
extension_name = extension_base + ("-async" if async_mode else "-sync")
|
|
123
|
-
extension = self.yaml_data["extensions"][extension_name]
|
|
124
|
-
arm_extension = None
|
|
125
|
-
if azure_arm is not None:
|
|
126
|
-
arm_extension = "azure-arm" if azure_arm else "data-plane"
|
|
127
|
-
return extension[arm_extension] if arm_extension else extension
|
|
128
|
-
|
|
129
|
-
def get_poller_path(self, async_mode: bool) -> str:
|
|
130
|
-
return self._get_lro_extension("poller", async_mode)
|
|
131
107
|
|
|
132
108
|
def get_poller(self, async_mode: bool) -> str:
|
|
133
|
-
return self.
|
|
134
|
-
|
|
135
|
-
def get_default_polling_method_path(self, async_mode: bool, azure_arm: bool) -> str:
|
|
136
|
-
return self._get_lro_extension(
|
|
137
|
-
"default-polling-method", async_mode, azure_arm=azure_arm
|
|
138
|
-
)
|
|
109
|
+
return self.responses[0].get_poller(async_mode)
|
|
139
110
|
|
|
140
|
-
def
|
|
141
|
-
return self.
|
|
142
|
-
-1
|
|
143
|
-
]
|
|
144
|
-
|
|
145
|
-
def get_default_no_polling_method_path(self, async_mode: bool) -> str:
|
|
146
|
-
return self._get_lro_extension("default-no-polling-method", async_mode)
|
|
147
|
-
|
|
148
|
-
def get_default_no_polling_method(self, async_mode: bool) -> str:
|
|
149
|
-
return self.get_default_no_polling_method_path(async_mode).split(".")[-1]
|
|
150
|
-
|
|
151
|
-
def get_base_polling_method_path(self, async_mode: bool) -> str:
|
|
152
|
-
return self._get_lro_extension("base-polling-method", async_mode)
|
|
111
|
+
def get_polling_method(self, async_mode: bool) -> str:
|
|
112
|
+
return self.responses[0].get_polling_method(async_mode)
|
|
153
113
|
|
|
154
114
|
def get_base_polling_method(self, async_mode: bool) -> str:
|
|
155
|
-
return self.
|
|
115
|
+
return self.responses[0].get_base_polling_method(async_mode)
|
|
156
116
|
|
|
157
|
-
def
|
|
158
|
-
|
|
159
|
-
poller_import_path = ".".join(self.get_poller_path(async_mode).split(".")[:-1])
|
|
160
|
-
poller = self.get_poller(async_mode)
|
|
161
|
-
file_import.add_submodule_import(
|
|
162
|
-
poller_import_path, poller, ImportType.AZURECORE, TypingSection.CONDITIONAL
|
|
163
|
-
)
|
|
164
|
-
return file_import
|
|
165
|
-
|
|
166
|
-
def imports(self, async_mode: bool, is_python3_file: bool) -> FileImport:
|
|
167
|
-
file_import = self._imports_base(async_mode, is_python3_file)
|
|
168
|
-
file_import.add_submodule_import(
|
|
169
|
-
"typing", "Union", ImportType.STDLIB, TypingSection.CONDITIONAL
|
|
170
|
-
)
|
|
171
|
-
|
|
172
|
-
poller_import_path = ".".join(self.get_poller_path(async_mode).split(".")[:-1])
|
|
173
|
-
poller = self.get_poller(async_mode)
|
|
174
|
-
file_import.add_submodule_import(
|
|
175
|
-
poller_import_path, poller, ImportType.AZURECORE
|
|
176
|
-
)
|
|
177
|
-
|
|
178
|
-
default_polling_method_import_path = ".".join(
|
|
179
|
-
self.get_default_polling_method_path(
|
|
180
|
-
async_mode, self.code_model.options["azure_arm"]
|
|
181
|
-
).split(".")[:-1]
|
|
182
|
-
)
|
|
183
|
-
default_polling_method = self.get_default_polling_method(
|
|
184
|
-
async_mode, self.code_model.options["azure_arm"]
|
|
185
|
-
)
|
|
186
|
-
file_import.add_submodule_import(
|
|
187
|
-
default_polling_method_import_path,
|
|
188
|
-
default_polling_method,
|
|
189
|
-
ImportType.AZURECORE,
|
|
190
|
-
)
|
|
117
|
+
def get_base_polling_method_path(self, async_mode: bool) -> str:
|
|
118
|
+
return self.responses[0].get_base_polling_method_path(async_mode)
|
|
191
119
|
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
)
|
|
195
|
-
default_no_polling_method = self.get_default_no_polling_method(async_mode)
|
|
196
|
-
file_import.add_submodule_import(
|
|
197
|
-
default_no_polling_method_import_path,
|
|
198
|
-
default_no_polling_method,
|
|
199
|
-
ImportType.AZURECORE,
|
|
200
|
-
)
|
|
120
|
+
def get_no_polling_method(self, async_mode: bool) -> str:
|
|
121
|
+
return self.responses[0].get_no_polling_method(async_mode)
|
|
201
122
|
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
file_import.add_submodule_import(
|
|
207
|
-
base_polling_method_import_path, base_polling_method, ImportType.AZURECORE
|
|
208
|
-
)
|
|
209
|
-
file_import.add_submodule_import("typing", "cast", ImportType.STDLIB)
|
|
123
|
+
def imports(
|
|
124
|
+
self, async_mode: bool, is_python3_file: bool, **kwargs: Any
|
|
125
|
+
) -> FileImport:
|
|
126
|
+
file_import = super().imports(async_mode, is_python3_file, **kwargs)
|
|
210
127
|
if async_mode:
|
|
211
128
|
file_import.add_submodule_import(
|
|
212
|
-
"
|
|
213
|
-
|
|
214
|
-
if self.code_model.options["tracing"] and self.want_tracing:
|
|
215
|
-
file_import.add_submodule_import(
|
|
216
|
-
f"azure.core.tracing.decorator{'_async' if async_mode else ''}",
|
|
217
|
-
f"distributed_trace{'_async' if async_mode else ''}",
|
|
129
|
+
f"azure.core.tracing.decorator_async",
|
|
130
|
+
f"distributed_trace_async",
|
|
218
131
|
ImportType.AZURECORE,
|
|
219
132
|
)
|
|
133
|
+
file_import.add_submodule_import(
|
|
134
|
+
"typing", "Union", ImportType.STDLIB, TypingSection.CONDITIONAL
|
|
135
|
+
)
|
|
136
|
+
file_import.add_submodule_import("typing", "cast", ImportType.STDLIB)
|
|
220
137
|
return file_import
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
class LROOperation(LROOperationBase[LROResponse]):
|
|
141
|
+
...
|