@autorest/python 5.16.0 → 5.19.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 +79 -4
- package/README.md +30 -4
- package/autorest/__init__.py +1 -1
- package/autorest/codegen/__init__.py +55 -211
- 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} +61 -39
- package/autorest/codegen/models/client.py +165 -53
- package/autorest/codegen/models/code_model.py +122 -257
- 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_type.py +131 -0
- package/autorest/codegen/models/enum_type.py +195 -0
- package/autorest/codegen/models/imports.py +80 -2
- package/autorest/codegen/models/list_type.py +149 -0
- package/autorest/codegen/models/lro_operation.py +79 -156
- package/autorest/codegen/models/lro_paging_operation.py +28 -11
- package/autorest/codegen/models/model_type.py +262 -0
- package/autorest/codegen/models/operation.py +331 -298
- package/autorest/codegen/models/operation_group.py +54 -91
- package/autorest/codegen/models/paging_operation.py +82 -123
- package/autorest/codegen/models/parameter.py +289 -396
- package/autorest/codegen/models/parameter_list.py +355 -360
- package/autorest/codegen/models/primitive_types.py +544 -0
- package/autorest/codegen/models/property.py +123 -139
- package/autorest/codegen/models/request_builder.py +130 -102
- 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 +55 -37
- package/autorest/codegen/serializers/builder_serializer.py +695 -1144
- package/autorest/codegen/serializers/client_serializer.py +92 -89
- package/autorest/codegen/serializers/general_serializer.py +15 -69
- 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 +49 -36
- 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 +7 -13
- package/autorest/codegen/serializers/parameter_serializer.py +174 -0
- package/autorest/codegen/serializers/request_builders_serializer.py +13 -30
- package/autorest/codegen/serializers/utils.py +0 -140
- package/autorest/codegen/templates/MANIFEST.in.jinja2 +1 -0
- package/autorest/codegen/templates/{service_client.py.jinja2 → client.py.jinja2} +10 -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 +21 -8
- package/autorest/codegen/templates/operation_groups_container.py.jinja2 +2 -2
- package/autorest/codegen/templates/operation_tools.jinja2 +11 -3
- package/autorest/codegen/templates/paging_operation.py.jinja2 +2 -2
- package/autorest/codegen/templates/request_builder.py.jinja2 +10 -15
- package/autorest/codegen/templates/request_builders.py.jinja2 +1 -1
- package/autorest/codegen/templates/serialization.py.jinja2 +2006 -0
- package/autorest/codegen/templates/setup.py.jinja2 +13 -3
- package/autorest/codegen/templates/vendor.py.jinja2 +11 -1
- package/autorest/jsonrpc/server.py +15 -3
- package/autorest/m4reformatter/__init__.py +1126 -0
- package/autorest/multiapi/models/client.py +12 -2
- package/autorest/multiapi/models/code_model.py +1 -1
- package/autorest/multiapi/serializers/__init__.py +18 -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 +4 -4
- 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 +210 -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/dictionary_schema.py +0 -106
- 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
|
@@ -3,218 +3,141 @@
|
|
|
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
|
-
|
|
207
|
-
|
|
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)
|
|
127
|
+
if self.abstract:
|
|
128
|
+
return file_import
|
|
210
129
|
if async_mode:
|
|
211
130
|
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 ''}",
|
|
131
|
+
f"azure.core.tracing.decorator_async",
|
|
132
|
+
f"distributed_trace_async",
|
|
218
133
|
ImportType.AZURECORE,
|
|
219
134
|
)
|
|
135
|
+
file_import.add_submodule_import(
|
|
136
|
+
"typing", "Union", ImportType.STDLIB, TypingSection.CONDITIONAL
|
|
137
|
+
)
|
|
138
|
+
file_import.add_submodule_import("typing", "cast", ImportType.STDLIB)
|
|
220
139
|
return file_import
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
class LROOperation(LROOperationBase[LROResponse]):
|
|
143
|
+
...
|
|
@@ -3,21 +3,38 @@
|
|
|
3
3
|
# Licensed under the MIT License. See License.txt in the project root for
|
|
4
4
|
# license information.
|
|
5
5
|
# --------------------------------------------------------------------------
|
|
6
|
+
from typing import Any
|
|
6
7
|
from .imports import FileImport
|
|
7
|
-
from .lro_operation import
|
|
8
|
-
from .paging_operation import
|
|
8
|
+
from .lro_operation import LROOperationBase
|
|
9
|
+
from .paging_operation import PagingOperationBase
|
|
10
|
+
from .response import LROPagingResponse, Response
|
|
9
11
|
|
|
10
12
|
|
|
11
|
-
class LROPagingOperation(
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
13
|
+
class LROPagingOperation(
|
|
14
|
+
LROOperationBase[LROPagingResponse], PagingOperationBase[LROPagingResponse]
|
|
15
|
+
):
|
|
16
|
+
@property
|
|
17
|
+
def success_status_codes(self):
|
|
18
|
+
"""The list of all successfull status code."""
|
|
19
|
+
return [200]
|
|
20
|
+
|
|
21
|
+
@property
|
|
22
|
+
def operation_type(self) -> str:
|
|
23
|
+
return "lropaging"
|
|
24
|
+
|
|
25
|
+
def cls_type_annotation(self, *, async_mode: bool) -> str:
|
|
26
|
+
return f"ClsType[{Response.type_annotation(self.responses[0], async_mode=async_mode)}]" # pylint: disable=no-member
|
|
27
|
+
|
|
28
|
+
def imports(
|
|
29
|
+
self, async_mode: bool, is_python3_file: bool, **kwargs: Any
|
|
30
|
+
) -> FileImport:
|
|
31
|
+
lro_imports = LROOperationBase.imports(
|
|
32
|
+
self, async_mode, is_python3_file, **kwargs
|
|
33
|
+
)
|
|
34
|
+
paging_imports = PagingOperationBase.imports(
|
|
35
|
+
self, async_mode, is_python3_file, **kwargs
|
|
36
|
+
)
|
|
15
37
|
|
|
16
38
|
file_import = lro_imports
|
|
17
39
|
file_import.merge(paging_imports)
|
|
18
40
|
return file_import
|
|
19
|
-
|
|
20
|
-
@property
|
|
21
|
-
def success_status_code(self):
|
|
22
|
-
"""The list of all successfull status code."""
|
|
23
|
-
return [200]
|
|
@@ -0,0 +1,262 @@
|
|
|
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, Optional, TYPE_CHECKING, cast
|
|
7
|
+
|
|
8
|
+
from autorest.codegen.models.utils import add_to_pylint_disable
|
|
9
|
+
from .base_type import BaseType
|
|
10
|
+
from .property import Property
|
|
11
|
+
from .imports import FileImport, ImportType, TypingSection
|
|
12
|
+
|
|
13
|
+
if TYPE_CHECKING:
|
|
14
|
+
from .code_model import CodeModel
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def _get_properties(type: "ModelType", properties: List[Property]) -> List[Property]:
|
|
18
|
+
for parent in type.parents:
|
|
19
|
+
# here we're adding the properties from our parents
|
|
20
|
+
|
|
21
|
+
# need to make sure that the properties we choose from our parent also don't contain
|
|
22
|
+
# any of our own properties
|
|
23
|
+
property_names = set(
|
|
24
|
+
[p.client_name for p in properties]
|
|
25
|
+
+ [p.client_name for p in type.properties]
|
|
26
|
+
)
|
|
27
|
+
chosen_parent_properties = [
|
|
28
|
+
p for p in parent.properties if p.client_name not in property_names
|
|
29
|
+
]
|
|
30
|
+
properties = _get_properties(parent, chosen_parent_properties) + properties
|
|
31
|
+
return properties
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
class ModelType(BaseType): # pylint: disable=too-many-instance-attributes
|
|
35
|
+
"""Represents a class ready to be serialized in Python.
|
|
36
|
+
|
|
37
|
+
:param str name: The name of the class.
|
|
38
|
+
:param str description: The description of the class.
|
|
39
|
+
:param properties: the optional properties of the class.
|
|
40
|
+
:type properties: dict(str, str)
|
|
41
|
+
"""
|
|
42
|
+
|
|
43
|
+
def __init__(
|
|
44
|
+
self,
|
|
45
|
+
yaml_data: Dict[str, Any],
|
|
46
|
+
code_model: "CodeModel",
|
|
47
|
+
*,
|
|
48
|
+
properties: Optional[List[Property]] = None,
|
|
49
|
+
parents: Optional[List["ModelType"]] = None,
|
|
50
|
+
discriminated_subtypes: Optional[Dict[str, "ModelType"]] = None,
|
|
51
|
+
) -> None:
|
|
52
|
+
super().__init__(yaml_data=yaml_data, code_model=code_model)
|
|
53
|
+
self.name: str = self.yaml_data["name"]
|
|
54
|
+
self.max_properties: Optional[int] = self.yaml_data.get("maxProperties")
|
|
55
|
+
self.min_properties: Optional[int] = self.yaml_data.get("minProperties")
|
|
56
|
+
self.properties = properties or []
|
|
57
|
+
self.parents = parents or []
|
|
58
|
+
self.discriminated_subtypes = discriminated_subtypes or {}
|
|
59
|
+
self.discriminator_value: Optional[str] = self.yaml_data.get(
|
|
60
|
+
"discriminatorValue"
|
|
61
|
+
)
|
|
62
|
+
self._created_json_template_representation = False
|
|
63
|
+
self.is_public: bool = self.yaml_data.get("isPublic", True)
|
|
64
|
+
self.snake_case_name: str = self.yaml_data["snakeCaseName"]
|
|
65
|
+
|
|
66
|
+
@property
|
|
67
|
+
def is_xml(self) -> bool:
|
|
68
|
+
return self.yaml_data.get("isXml", False)
|
|
69
|
+
|
|
70
|
+
@property
|
|
71
|
+
def serialization_type(self) -> str:
|
|
72
|
+
if self.code_model.options["models_mode"]:
|
|
73
|
+
return self.name
|
|
74
|
+
return "object"
|
|
75
|
+
|
|
76
|
+
def type_annotation(self, **kwargs: Any) -> str:
|
|
77
|
+
if self.code_model.options["models_mode"]:
|
|
78
|
+
is_operation_file = kwargs.pop("is_operation_file", False)
|
|
79
|
+
if self.is_public:
|
|
80
|
+
retval = f"_models.{self.name}"
|
|
81
|
+
return retval if is_operation_file else f'"{retval}"'
|
|
82
|
+
return self.name if is_operation_file else f'"{self.name}"'
|
|
83
|
+
return "ET.Element" if self.is_xml else "JSON"
|
|
84
|
+
|
|
85
|
+
def docstring_type(self, **kwargs: Any) -> str:
|
|
86
|
+
if self.code_model.options["models_mode"]:
|
|
87
|
+
return f"~{self.code_model.namespace}.models.{self.name}"
|
|
88
|
+
return "ET.Element" if self.is_xml else "JSON"
|
|
89
|
+
|
|
90
|
+
def description(self, *, is_operation_file: bool = False) -> str:
|
|
91
|
+
return "" if is_operation_file else self.yaml_data.get("description", self.name)
|
|
92
|
+
|
|
93
|
+
def docstring_text(self, **kwargs: Any) -> str:
|
|
94
|
+
if self.code_model.options["models_mode"]:
|
|
95
|
+
return self.name
|
|
96
|
+
return "XML Element" if self.is_xml else "JSON object"
|
|
97
|
+
|
|
98
|
+
def get_declaration(self, value: Any) -> str:
|
|
99
|
+
return f"{self.name}()"
|
|
100
|
+
|
|
101
|
+
def __repr__(self) -> str:
|
|
102
|
+
return f"<{self.__class__.__name__} {self.name}>"
|
|
103
|
+
|
|
104
|
+
@property
|
|
105
|
+
def xml_serialization_ctxt(self) -> Optional[str]:
|
|
106
|
+
# object schema contains _xml_map, they don't need serialization context
|
|
107
|
+
return ""
|
|
108
|
+
|
|
109
|
+
@property
|
|
110
|
+
def xml_map_content(self) -> Optional[str]:
|
|
111
|
+
# This is NOT an error on the super call, we use the serialization context for "xml_map",
|
|
112
|
+
# but we don't want to write a serialization context for an object.
|
|
113
|
+
return super().xml_serialization_ctxt
|
|
114
|
+
|
|
115
|
+
@property
|
|
116
|
+
def discriminated_subtypes_name_mapping(self) -> Dict[str, str]:
|
|
117
|
+
return {k: v.name for k, v in self.discriminated_subtypes.items()}
|
|
118
|
+
|
|
119
|
+
def get_json_template_representation(
|
|
120
|
+
self,
|
|
121
|
+
*,
|
|
122
|
+
optional: bool = True,
|
|
123
|
+
client_default_value_declaration: Optional[str] = None,
|
|
124
|
+
description: Optional[str] = None,
|
|
125
|
+
) -> Any:
|
|
126
|
+
if self._created_json_template_representation:
|
|
127
|
+
return "..." # do this to avoid loop
|
|
128
|
+
self._created_json_template_representation = True
|
|
129
|
+
if self.discriminated_subtypes:
|
|
130
|
+
# we will instead print the discriminated subtypes
|
|
131
|
+
self._created_json_template_representation = False
|
|
132
|
+
return self.snake_case_name
|
|
133
|
+
|
|
134
|
+
# don't add additional properties, because there's not really a concept of
|
|
135
|
+
# additional properties in the template
|
|
136
|
+
representation = {
|
|
137
|
+
f'"{prop.rest_api_name}"': prop.get_json_template_representation(
|
|
138
|
+
optional=optional,
|
|
139
|
+
client_default_value_declaration=client_default_value_declaration,
|
|
140
|
+
description=description,
|
|
141
|
+
)
|
|
142
|
+
for prop in [
|
|
143
|
+
p
|
|
144
|
+
for p in self.properties
|
|
145
|
+
if not (p.is_discriminator or p.client_name == "additional_properties")
|
|
146
|
+
]
|
|
147
|
+
}
|
|
148
|
+
if self.discriminator and self.discriminator_value:
|
|
149
|
+
representation[
|
|
150
|
+
f'"{self.discriminator.rest_api_name}"'
|
|
151
|
+
] = f'"{self.discriminator_value}"'
|
|
152
|
+
|
|
153
|
+
# once we've finished, we want to reset created_json_template_representation to false
|
|
154
|
+
# so we can call it again
|
|
155
|
+
self._created_json_template_representation = False
|
|
156
|
+
return representation
|
|
157
|
+
|
|
158
|
+
def get_polymorphic_subtypes(self, polymorphic_subtypes: List["ModelType"]) -> None:
|
|
159
|
+
is_polymorphic_subtype = (
|
|
160
|
+
self.discriminator_value and not self.discriminated_subtypes
|
|
161
|
+
)
|
|
162
|
+
if (
|
|
163
|
+
self.name not in (m.name for m in polymorphic_subtypes)
|
|
164
|
+
and is_polymorphic_subtype
|
|
165
|
+
):
|
|
166
|
+
polymorphic_subtypes.append(self)
|
|
167
|
+
for discriminated_subtype in self.discriminated_subtypes.values():
|
|
168
|
+
discriminated_subtype.get_polymorphic_subtypes(polymorphic_subtypes)
|
|
169
|
+
for property in self.properties:
|
|
170
|
+
property.get_polymorphic_subtypes(polymorphic_subtypes)
|
|
171
|
+
|
|
172
|
+
@classmethod
|
|
173
|
+
def from_yaml(
|
|
174
|
+
cls, yaml_data: Dict[str, Any], code_model: "CodeModel"
|
|
175
|
+
) -> "ModelType":
|
|
176
|
+
raise ValueError(
|
|
177
|
+
"You shouldn't call from_yaml for ModelType to avoid recursion. "
|
|
178
|
+
"Please initial a blank ModelType, then call .fill_instance_from_yaml on the created type."
|
|
179
|
+
)
|
|
180
|
+
|
|
181
|
+
def fill_instance_from_yaml(
|
|
182
|
+
self, yaml_data: Dict[str, Any], code_model: "CodeModel"
|
|
183
|
+
) -> None:
|
|
184
|
+
from . import build_type
|
|
185
|
+
|
|
186
|
+
self.parents = [
|
|
187
|
+
cast(ModelType, build_type(bm, code_model))
|
|
188
|
+
for bm in yaml_data.get("parents", [])
|
|
189
|
+
]
|
|
190
|
+
properties = [
|
|
191
|
+
Property.from_yaml(p, code_model) for p in yaml_data["properties"]
|
|
192
|
+
]
|
|
193
|
+
self.properties = _get_properties(self, properties)
|
|
194
|
+
# checking to see if this is a polymorphic class
|
|
195
|
+
self.discriminated_subtypes = {
|
|
196
|
+
k: cast(ModelType, build_type(v, code_model))
|
|
197
|
+
for k, v in self.yaml_data.get("discriminatedSubtypes", {}).items()
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
@property
|
|
201
|
+
def has_readonly_or_constant_property(self) -> bool:
|
|
202
|
+
return any(x.readonly or x.constant for x in self.properties)
|
|
203
|
+
|
|
204
|
+
@property
|
|
205
|
+
def discriminator(self) -> Optional[Property]:
|
|
206
|
+
try:
|
|
207
|
+
return next(p for p in self.properties if p.is_discriminator)
|
|
208
|
+
except StopIteration:
|
|
209
|
+
return None
|
|
210
|
+
|
|
211
|
+
@property
|
|
212
|
+
def instance_check_template(self) -> str:
|
|
213
|
+
if self.code_model.options["models_mode"]:
|
|
214
|
+
return "isinstance({}, msrest.Model)"
|
|
215
|
+
return "isinstance({}, MutableMapping)"
|
|
216
|
+
|
|
217
|
+
@property
|
|
218
|
+
def pylint_disable(self) -> str:
|
|
219
|
+
retval: str = ""
|
|
220
|
+
if len(self.properties) > 10:
|
|
221
|
+
retval = add_to_pylint_disable(retval, "too-many-instance-attributes")
|
|
222
|
+
return retval
|
|
223
|
+
|
|
224
|
+
@property
|
|
225
|
+
def init_pylint_disable(self) -> str:
|
|
226
|
+
retval: str = ""
|
|
227
|
+
if len(self.properties) > 23:
|
|
228
|
+
retval = add_to_pylint_disable(retval, "too-many-locals")
|
|
229
|
+
return retval
|
|
230
|
+
|
|
231
|
+
def imports(self, **kwargs: Any) -> FileImport:
|
|
232
|
+
file_import = FileImport()
|
|
233
|
+
relative_path = kwargs.pop("relative_path", None)
|
|
234
|
+
if self.code_model.options["models_mode"] and relative_path:
|
|
235
|
+
# add import for models in operations file
|
|
236
|
+
if self.is_public:
|
|
237
|
+
file_import.add_submodule_import(
|
|
238
|
+
relative_path, "models", ImportType.LOCAL, alias="_models"
|
|
239
|
+
)
|
|
240
|
+
else:
|
|
241
|
+
# a little hacky, but we only do this for version tolerant
|
|
242
|
+
# models files, which are all python3 only
|
|
243
|
+
models_filename = self.code_model.get_models_filename(
|
|
244
|
+
is_python3_file=True
|
|
245
|
+
)
|
|
246
|
+
file_import.add_submodule_import(
|
|
247
|
+
f"{relative_path}models.{models_filename}",
|
|
248
|
+
self.name,
|
|
249
|
+
ImportType.LOCAL,
|
|
250
|
+
)
|
|
251
|
+
if self.code_model.options["models_mode"]:
|
|
252
|
+
return file_import
|
|
253
|
+
file_import.add_submodule_import(
|
|
254
|
+
"typing", "Any", ImportType.STDLIB, TypingSection.CONDITIONAL
|
|
255
|
+
)
|
|
256
|
+
file_import.add_import("sys", ImportType.STDLIB)
|
|
257
|
+
file_import.define_mutable_mapping_type()
|
|
258
|
+
if self.is_xml:
|
|
259
|
+
file_import.add_submodule_import(
|
|
260
|
+
"xml.etree", "ElementTree", ImportType.STDLIB, alias="ET"
|
|
261
|
+
)
|
|
262
|
+
return file_import
|