@autorest/python 5.13.0 → 5.16.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 +67 -0
- package/autorest/__init__.py +1 -2
- package/autorest/black/__init__.py +12 -5
- package/autorest/codegen/__init__.py +239 -105
- package/autorest/codegen/models/__init__.py +29 -18
- package/autorest/codegen/models/base_builder.py +48 -11
- package/autorest/codegen/models/base_model.py +6 -4
- package/autorest/codegen/models/base_schema.py +21 -24
- package/autorest/codegen/models/client.py +70 -20
- package/autorest/codegen/models/code_model.py +144 -129
- package/autorest/codegen/models/constant_schema.py +32 -16
- package/autorest/codegen/models/credential_model.py +55 -0
- package/autorest/codegen/models/credential_schema.py +21 -16
- package/autorest/codegen/models/credential_schema_policy.py +11 -15
- package/autorest/codegen/models/dictionary_schema.py +27 -24
- package/autorest/codegen/models/enum_schema.py +41 -62
- package/autorest/codegen/models/imports.py +72 -41
- package/autorest/codegen/models/list_schema.py +40 -18
- package/autorest/codegen/models/lro_operation.py +61 -25
- package/autorest/codegen/models/lro_paging_operation.py +5 -6
- package/autorest/codegen/models/object_schema.py +113 -59
- package/autorest/codegen/models/operation.py +251 -111
- package/autorest/codegen/models/operation_group.py +67 -32
- package/autorest/codegen/models/paging_operation.py +48 -21
- package/autorest/codegen/models/parameter.py +182 -90
- package/autorest/codegen/models/parameter_list.py +184 -163
- package/autorest/codegen/models/primitive_schemas.py +89 -70
- package/autorest/codegen/models/property.py +49 -31
- package/autorest/codegen/models/request_builder.py +67 -32
- package/autorest/codegen/models/request_builder_parameter.py +54 -23
- package/autorest/codegen/models/request_builder_parameter_list.py +77 -108
- package/autorest/codegen/models/schema_request.py +16 -6
- package/autorest/codegen/models/schema_response.py +35 -17
- package/autorest/codegen/models/utils.py +24 -1
- package/autorest/codegen/serializers/__init__.py +273 -89
- package/autorest/codegen/serializers/builder_serializer.py +711 -333
- package/autorest/codegen/serializers/client_serializer.py +114 -43
- package/autorest/codegen/serializers/general_serializer.py +84 -25
- package/autorest/codegen/serializers/import_serializer.py +93 -31
- package/autorest/codegen/serializers/metadata_serializer.py +73 -24
- package/autorest/codegen/serializers/model_base_serializer.py +42 -14
- package/autorest/codegen/serializers/model_generic_serializer.py +1 -4
- package/autorest/codegen/serializers/model_init_serializer.py +5 -1
- package/autorest/codegen/serializers/model_python3_serializer.py +9 -8
- package/autorest/codegen/serializers/operation_groups_serializer.py +20 -8
- package/autorest/codegen/serializers/operations_init_serializer.py +23 -11
- package/autorest/codegen/serializers/patch_serializer.py +14 -2
- package/autorest/codegen/serializers/{rest_serializer.py → request_builders_serializer.py} +29 -12
- package/autorest/codegen/serializers/utils.py +60 -21
- package/autorest/codegen/templates/CHANGELOG.md.jinja2 +6 -0
- package/autorest/codegen/templates/LICENSE.jinja2 +21 -0
- package/autorest/codegen/templates/MANIFEST.in.jinja2 +7 -0
- package/autorest/codegen/templates/README.md.jinja2 +105 -0
- package/autorest/codegen/templates/config.py.jinja2 +4 -4
- package/autorest/codegen/templates/dev_requirements.txt.jinja2 +10 -0
- package/autorest/codegen/templates/enum.py.jinja2 +1 -1
- package/autorest/codegen/templates/enum_container.py.jinja2 +0 -1
- package/autorest/codegen/templates/init.py.jinja2 +9 -6
- package/autorest/codegen/templates/keywords.jinja2 +14 -1
- package/autorest/codegen/templates/lro_operation.py.jinja2 +5 -7
- package/autorest/codegen/templates/lro_paging_operation.py.jinja2 +5 -7
- package/autorest/codegen/templates/metadata.json.jinja2 +10 -9
- package/autorest/codegen/templates/model.py.jinja2 +1 -6
- package/autorest/codegen/templates/model_init.py.jinja2 +7 -4
- package/autorest/codegen/templates/operation.py.jinja2 +8 -11
- package/autorest/codegen/templates/operation_group.py.jinja2 +15 -18
- package/autorest/codegen/templates/operation_groups_container.py.jinja2 +1 -2
- package/autorest/codegen/templates/operations_folder_init.py.jinja2 +4 -0
- package/autorest/codegen/templates/paging_operation.py.jinja2 +7 -8
- package/autorest/codegen/templates/patch.py.jinja2 +18 -29
- package/autorest/codegen/templates/request_builder.py.jinja2 +19 -14
- package/autorest/codegen/templates/setup.py.jinja2 +79 -20
- package/autorest/codegen/templates/vendor.py.jinja2 +12 -2
- package/autorest/jsonrpc/__init__.py +7 -12
- package/autorest/jsonrpc/localapi.py +4 -3
- package/autorest/jsonrpc/server.py +13 -6
- package/autorest/jsonrpc/stdstream.py +13 -6
- package/autorest/m2r/__init__.py +5 -8
- package/autorest/multiapi/__init__.py +24 -14
- package/autorest/multiapi/models/client.py +21 -11
- package/autorest/multiapi/models/code_model.py +23 -10
- package/autorest/multiapi/models/config.py +4 -1
- package/autorest/multiapi/models/constant_global_parameter.py +1 -0
- package/autorest/multiapi/models/global_parameter.py +2 -1
- package/autorest/multiapi/models/global_parameters.py +14 -8
- package/autorest/multiapi/models/imports.py +35 -18
- package/autorest/multiapi/models/mixin_operation.py +5 -5
- package/autorest/multiapi/models/operation_group.py +2 -1
- package/autorest/multiapi/models/operation_mixin_group.py +21 -10
- package/autorest/multiapi/serializers/__init__.py +18 -23
- package/autorest/multiapi/serializers/import_serializer.py +47 -15
- package/autorest/multiapi/serializers/multiapi_serializer.py +17 -17
- package/autorest/multiapi/templates/multiapi_operations_mixin.py.jinja2 +1 -1
- package/autorest/multiapi/utils.py +3 -3
- package/autorest/namer/__init__.py +2 -4
- package/autorest/namer/name_converter.py +200 -103
- package/autorest/namer/python_mappings.py +10 -22
- package/package.json +3 -3
- package/run-python3.js +2 -3
- package/venvtools.py +1 -1
- package/autorest/codegen/models/rest.py +0 -42
|
@@ -5,29 +5,40 @@
|
|
|
5
5
|
# --------------------------------------------------------------------------
|
|
6
6
|
from itertools import chain
|
|
7
7
|
import logging
|
|
8
|
-
from typing import cast, Dict, List, Any, Optional, Union, Set
|
|
8
|
+
from typing import cast, Dict, List, Any, Optional, Union, Set, TYPE_CHECKING
|
|
9
9
|
|
|
10
10
|
from .base_builder import BaseBuilder, create_parameters
|
|
11
11
|
from .imports import FileImport, ImportType, TypingSection
|
|
12
12
|
from .schema_response import SchemaResponse
|
|
13
|
-
from .parameter import
|
|
14
|
-
|
|
13
|
+
from .parameter import (
|
|
14
|
+
Parameter,
|
|
15
|
+
ParameterMethodLocation,
|
|
16
|
+
get_parameter,
|
|
17
|
+
ParameterLocation,
|
|
18
|
+
)
|
|
19
|
+
from .parameter_list import ParameterList
|
|
15
20
|
from .base_schema import BaseSchema
|
|
16
21
|
from .object_schema import ObjectSchema
|
|
17
22
|
from .request_builder import RequestBuilder
|
|
18
23
|
from .schema_request import SchemaRequest
|
|
19
24
|
from .primitive_schemas import IOSchema
|
|
20
25
|
|
|
26
|
+
if TYPE_CHECKING:
|
|
27
|
+
from .code_model import CodeModel
|
|
28
|
+
|
|
21
29
|
_LOGGER = logging.getLogger(__name__)
|
|
22
30
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
31
|
+
|
|
32
|
+
class Operation(
|
|
33
|
+
BaseBuilder
|
|
34
|
+
): # pylint: disable=too-many-public-methods, too-many-instance-attributes
|
|
35
|
+
"""Represent an self."""
|
|
26
36
|
|
|
27
37
|
def __init__(
|
|
28
38
|
self,
|
|
29
|
-
code_model,
|
|
30
39
|
yaml_data: Dict[str, Any],
|
|
40
|
+
code_model: "CodeModel",
|
|
41
|
+
request_builder: RequestBuilder,
|
|
31
42
|
name: str,
|
|
32
43
|
description: str,
|
|
33
44
|
api_versions: Set[str],
|
|
@@ -39,6 +50,8 @@ class Operation(BaseBuilder): # pylint: disable=too-many-public-methods, too-ma
|
|
|
39
50
|
exceptions: Optional[List[SchemaResponse]] = None,
|
|
40
51
|
want_description_docstring: bool = True,
|
|
41
52
|
want_tracing: bool = True,
|
|
53
|
+
*,
|
|
54
|
+
abstract: bool = False,
|
|
42
55
|
) -> None:
|
|
43
56
|
super().__init__(
|
|
44
57
|
code_model=code_model,
|
|
@@ -49,33 +62,21 @@ class Operation(BaseBuilder): # pylint: disable=too-many-public-methods, too-ma
|
|
|
49
62
|
responses=responses,
|
|
50
63
|
schema_requests=schema_requests,
|
|
51
64
|
summary=summary,
|
|
65
|
+
abstract=abstract,
|
|
66
|
+
want_tracing=want_tracing,
|
|
52
67
|
)
|
|
53
68
|
self.multiple_content_type_parameters = multiple_content_type_parameters
|
|
54
69
|
self.api_versions = api_versions
|
|
55
70
|
self.multiple_content_type_parameters = multiple_content_type_parameters
|
|
56
71
|
self.exceptions = exceptions or []
|
|
57
72
|
self.want_description_docstring = want_description_docstring
|
|
58
|
-
self.
|
|
59
|
-
self._request_builder: Optional[RequestBuilder] = None
|
|
73
|
+
self.request_builder = request_builder
|
|
60
74
|
self.deprecated = False
|
|
61
75
|
|
|
62
76
|
@property
|
|
63
77
|
def python_name(self) -> str:
|
|
64
78
|
return self.name
|
|
65
79
|
|
|
66
|
-
@property
|
|
67
|
-
def request_builder(self) -> RequestBuilder:
|
|
68
|
-
if not self._request_builder:
|
|
69
|
-
raise ValueError(
|
|
70
|
-
"You're calling request_builder when you haven't linked up operation to its "
|
|
71
|
-
"request builder through the code model"
|
|
72
|
-
)
|
|
73
|
-
return self._request_builder
|
|
74
|
-
|
|
75
|
-
@request_builder.setter
|
|
76
|
-
def request_builder(self, r: RequestBuilder) -> None:
|
|
77
|
-
self._request_builder = r
|
|
78
|
-
|
|
79
80
|
@property
|
|
80
81
|
def is_stream_response(self) -> bool:
|
|
81
82
|
"""Is the response expected to be streamable, like a download."""
|
|
@@ -93,19 +94,22 @@ class Operation(BaseBuilder): # pylint: disable=too-many-public-methods, too-ma
|
|
|
93
94
|
|
|
94
95
|
# successful status codes of responses that have bodies
|
|
95
96
|
status_codes_for_responses_with_bodies = [
|
|
96
|
-
code
|
|
97
|
+
code
|
|
98
|
+
for code in self.success_status_code
|
|
97
99
|
if isinstance(code, int) and self.get_response_from_status(code).has_body
|
|
98
100
|
]
|
|
99
101
|
|
|
100
102
|
successful_responses = [
|
|
101
|
-
response
|
|
103
|
+
response
|
|
104
|
+
for response in self.responses
|
|
102
105
|
if any(code in self.success_status_code for code in response.status_codes)
|
|
103
106
|
]
|
|
104
107
|
|
|
105
108
|
return (
|
|
106
|
-
self.has_response_body
|
|
107
|
-
len(successful_responses) > 1
|
|
108
|
-
len(self.success_status_code)
|
|
109
|
+
self.has_response_body
|
|
110
|
+
and len(successful_responses) > 1
|
|
111
|
+
and len(self.success_status_code)
|
|
112
|
+
!= len(status_codes_for_responses_with_bodies)
|
|
109
113
|
)
|
|
110
114
|
|
|
111
115
|
@property
|
|
@@ -115,9 +119,11 @@ class Operation(BaseBuilder): # pylint: disable=too-many-public-methods, too-ma
|
|
|
115
119
|
|
|
116
120
|
@property
|
|
117
121
|
def has_response_body(self) -> bool:
|
|
118
|
-
"""Tell if at least one response has a body.
|
|
119
|
-
|
|
120
|
-
|
|
122
|
+
"""Tell if at least one response has a body."""
|
|
123
|
+
return any(
|
|
124
|
+
response.has_body or response.is_stream_response
|
|
125
|
+
for response in self.responses
|
|
126
|
+
)
|
|
121
127
|
|
|
122
128
|
@property
|
|
123
129
|
def any_response_has_headers(self) -> bool:
|
|
@@ -125,30 +131,45 @@ class Operation(BaseBuilder): # pylint: disable=too-many-public-methods, too-ma
|
|
|
125
131
|
|
|
126
132
|
@property
|
|
127
133
|
def default_exception(self) -> Optional[str]:
|
|
128
|
-
default_excp = [
|
|
134
|
+
default_excp = [
|
|
135
|
+
excp
|
|
136
|
+
for excp in self.exceptions
|
|
137
|
+
for code in excp.status_codes
|
|
138
|
+
if code == "default"
|
|
139
|
+
]
|
|
129
140
|
if not default_excp:
|
|
130
141
|
return None
|
|
131
142
|
excep_schema = default_excp[0].schema
|
|
132
143
|
if isinstance(excep_schema, ObjectSchema):
|
|
133
144
|
return f"_models.{excep_schema.name}"
|
|
134
145
|
# in this case, it's just an AnySchema
|
|
135
|
-
return "
|
|
146
|
+
return "'object'"
|
|
136
147
|
|
|
137
148
|
@property
|
|
138
149
|
def status_code_exceptions(self) -> List[SchemaResponse]:
|
|
139
|
-
return [
|
|
150
|
+
return [
|
|
151
|
+
excp for excp in self.exceptions if list(excp.status_codes) != ["default"]
|
|
152
|
+
]
|
|
140
153
|
|
|
141
154
|
@property
|
|
142
155
|
def status_code_exceptions_status_codes(self) -> List[Union[str, int]]:
|
|
143
156
|
"""Actually returns all of the status codes from exceptions (besides default)"""
|
|
144
|
-
return list(
|
|
145
|
-
|
|
146
|
-
|
|
157
|
+
return list(
|
|
158
|
+
chain.from_iterable(
|
|
159
|
+
[excp.status_codes for excp in self.status_code_exceptions]
|
|
160
|
+
)
|
|
161
|
+
)
|
|
147
162
|
|
|
148
|
-
def _imports_shared(
|
|
163
|
+
def _imports_shared(
|
|
164
|
+
self, async_mode: bool # pylint: disable=unused-argument
|
|
165
|
+
) -> FileImport:
|
|
149
166
|
file_import = FileImport()
|
|
150
|
-
file_import.add_submodule_import(
|
|
167
|
+
file_import.add_submodule_import(
|
|
168
|
+
"typing", "Any", ImportType.STDLIB, TypingSection.CONDITIONAL
|
|
169
|
+
)
|
|
151
170
|
for param in self.parameters.method:
|
|
171
|
+
if self.abstract and (param.is_multipart or param.is_data_input):
|
|
172
|
+
continue
|
|
152
173
|
file_import.merge(param.imports())
|
|
153
174
|
|
|
154
175
|
for param in self.multiple_content_type_parameters:
|
|
@@ -159,104 +180,178 @@ class Operation(BaseBuilder): # pylint: disable=too-many-public-methods, too-ma
|
|
|
159
180
|
if response.has_body:
|
|
160
181
|
file_import.merge(cast(BaseSchema, response.schema).imports())
|
|
161
182
|
|
|
162
|
-
response_types = [
|
|
183
|
+
response_types = [
|
|
184
|
+
r.type_annotation(is_operation_file=True)
|
|
185
|
+
for r in self.responses
|
|
186
|
+
if r.has_body
|
|
187
|
+
]
|
|
163
188
|
if len(set(response_types)) > 1:
|
|
164
|
-
file_import.add_submodule_import(
|
|
189
|
+
file_import.add_submodule_import(
|
|
190
|
+
"typing", "Union", ImportType.STDLIB, TypingSection.CONDITIONAL
|
|
191
|
+
)
|
|
165
192
|
|
|
166
193
|
if self.is_stream_response:
|
|
167
|
-
file_import.add_submodule_import(
|
|
194
|
+
file_import.add_submodule_import(
|
|
195
|
+
"typing", "IO", ImportType.STDLIB, TypingSection.CONDITIONAL
|
|
196
|
+
)
|
|
168
197
|
return file_import
|
|
169
198
|
|
|
170
|
-
|
|
171
|
-
|
|
199
|
+
def imports_for_multiapi(
|
|
200
|
+
self, async_mode: bool
|
|
201
|
+
) -> FileImport: # pylint: disable=unused-argument
|
|
172
202
|
return self._imports_shared(async_mode)
|
|
173
203
|
|
|
174
|
-
def imports(self, async_mode: bool) -> FileImport:
|
|
204
|
+
def imports(self, async_mode: bool, is_python3_file: bool) -> FileImport:
|
|
205
|
+
file_import = self._imports_base(async_mode, is_python3_file)
|
|
206
|
+
if self.abstract:
|
|
207
|
+
return file_import
|
|
208
|
+
if (
|
|
209
|
+
self.has_response_body
|
|
210
|
+
and not self.has_optional_return_type
|
|
211
|
+
and not self.code_model.options["models_mode"]
|
|
212
|
+
):
|
|
213
|
+
file_import.add_submodule_import("typing", "cast", ImportType.STDLIB)
|
|
214
|
+
return file_import
|
|
215
|
+
|
|
216
|
+
@staticmethod
|
|
217
|
+
def has_kwargs_to_pop_with_default(
|
|
218
|
+
kwargs_to_pop: List[Parameter], location: ParameterLocation
|
|
219
|
+
) -> bool:
|
|
220
|
+
return any(
|
|
221
|
+
kwarg.has_default_value and kwarg.location == location
|
|
222
|
+
for kwarg in kwargs_to_pop
|
|
223
|
+
)
|
|
224
|
+
|
|
225
|
+
def _imports_base(self, async_mode: bool, is_python3_file: bool) -> FileImport:
|
|
175
226
|
file_import = self._imports_shared(async_mode)
|
|
176
227
|
|
|
177
228
|
# Exceptions
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
file_import.add_submodule_import("azure.mgmt.core.exceptions", "ARMErrorFormat", ImportType.AZURECORE)
|
|
181
|
-
file_import.add_submodule_import("azure.core.exceptions", "HttpResponseError", ImportType.AZURECORE)
|
|
182
|
-
|
|
183
|
-
file_import.add_submodule_import("typing", "Callable", ImportType.STDLIB, TypingSection.CONDITIONAL)
|
|
184
|
-
file_import.add_submodule_import("typing", "Optional", ImportType.STDLIB, TypingSection.CONDITIONAL)
|
|
185
|
-
file_import.add_submodule_import("typing", "Dict", ImportType.STDLIB, TypingSection.CONDITIONAL)
|
|
186
|
-
file_import.add_submodule_import("typing", "TypeVar", ImportType.STDLIB, TypingSection.CONDITIONAL)
|
|
187
|
-
file_import.add_submodule_import("azure.core.pipeline", "PipelineResponse", ImportType.AZURECORE)
|
|
188
|
-
file_import.add_submodule_import("azure.core.rest", "HttpRequest", ImportType.AZURECORE)
|
|
189
|
-
if async_mode:
|
|
190
|
-
file_import.add_submodule_import("azure.core.pipeline.transport", "AsyncHttpResponse", ImportType.AZURECORE)
|
|
229
|
+
if self.abstract:
|
|
230
|
+
file_import.add_import("abc", ImportType.STDLIB)
|
|
191
231
|
else:
|
|
192
|
-
file_import.add_submodule_import(
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
232
|
+
file_import.add_submodule_import(
|
|
233
|
+
"azure.core.exceptions", "map_error", ImportType.AZURECORE
|
|
234
|
+
)
|
|
235
|
+
if self.code_model.options["azure_arm"]:
|
|
236
|
+
file_import.add_submodule_import(
|
|
237
|
+
"azure.mgmt.core.exceptions", "ARMErrorFormat", ImportType.AZURECORE
|
|
238
|
+
)
|
|
239
|
+
file_import.add_submodule_import(
|
|
240
|
+
"azure.core.exceptions", "HttpResponseError", ImportType.AZURECORE
|
|
241
|
+
)
|
|
242
|
+
file_import.add_submodule_import(
|
|
243
|
+
"azure.core.exceptions",
|
|
244
|
+
"ClientAuthenticationError",
|
|
245
|
+
ImportType.AZURECORE,
|
|
246
|
+
)
|
|
247
|
+
file_import.add_submodule_import(
|
|
248
|
+
"azure.core.exceptions", "ResourceNotFoundError", ImportType.AZURECORE
|
|
249
|
+
)
|
|
250
|
+
file_import.add_submodule_import(
|
|
251
|
+
"azure.core.exceptions", "ResourceExistsError", ImportType.AZURECORE
|
|
252
|
+
)
|
|
196
253
|
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
254
|
+
kwargs_to_pop = self.parameters.kwargs_to_pop(is_python3_file)
|
|
255
|
+
if self.has_kwargs_to_pop_with_default(
|
|
256
|
+
kwargs_to_pop, ParameterLocation.Header
|
|
257
|
+
) or self.has_kwargs_to_pop_with_default(
|
|
258
|
+
kwargs_to_pop, ParameterLocation.Query
|
|
259
|
+
):
|
|
201
260
|
file_import.add_submodule_import(
|
|
202
|
-
|
|
203
|
-
builder_group_name,
|
|
204
|
-
import_type=ImportType.LOCAL,
|
|
205
|
-
alias=f"rest_{builder_group_name}"
|
|
261
|
+
"azure.core.utils", "case_insensitive_dict", ImportType.AZURECORE
|
|
206
262
|
)
|
|
207
|
-
|
|
263
|
+
if self.deprecated:
|
|
264
|
+
file_import.add_import("warnings", ImportType.STDLIB)
|
|
265
|
+
if self.code_model.options["builders_visibility"] != "embedded":
|
|
266
|
+
builder_group_name = self.request_builder.builder_group_name
|
|
267
|
+
rest_import_path = "..." if async_mode else ".."
|
|
268
|
+
if builder_group_name:
|
|
269
|
+
file_import.add_submodule_import(
|
|
270
|
+
f"{rest_import_path}{self.code_model.rest_layer_name}",
|
|
271
|
+
builder_group_name,
|
|
272
|
+
import_type=ImportType.LOCAL,
|
|
273
|
+
alias=f"rest_{builder_group_name}",
|
|
274
|
+
)
|
|
275
|
+
else:
|
|
276
|
+
file_import.add_submodule_import(
|
|
277
|
+
rest_import_path,
|
|
278
|
+
self.code_model.rest_layer_name,
|
|
279
|
+
import_type=ImportType.LOCAL,
|
|
280
|
+
alias="rest",
|
|
281
|
+
)
|
|
282
|
+
if self.code_model.need_request_converter:
|
|
283
|
+
relative_path = "..." if async_mode else ".."
|
|
208
284
|
file_import.add_submodule_import(
|
|
209
|
-
|
|
210
|
-
self.code_model.rest_layer_name,
|
|
211
|
-
import_type=ImportType.LOCAL,
|
|
212
|
-
alias="rest"
|
|
285
|
+
f"{relative_path}_vendor", "_convert_request", ImportType.LOCAL
|
|
213
286
|
)
|
|
214
|
-
if
|
|
215
|
-
file_import.
|
|
216
|
-
|
|
217
|
-
|
|
287
|
+
if async_mode:
|
|
288
|
+
file_import.add_submodule_import(
|
|
289
|
+
"azure.core.pipeline.transport",
|
|
290
|
+
"AsyncHttpResponse",
|
|
291
|
+
ImportType.AZURECORE,
|
|
292
|
+
)
|
|
293
|
+
else:
|
|
218
294
|
file_import.add_submodule_import(
|
|
219
|
-
|
|
295
|
+
"azure.core.pipeline.transport", "HttpResponse", ImportType.AZURECORE
|
|
220
296
|
)
|
|
221
|
-
if
|
|
222
|
-
self.
|
|
223
|
-
|
|
297
|
+
if (
|
|
298
|
+
self.code_model.options["builders_visibility"] == "embedded"
|
|
299
|
+
and not async_mode
|
|
224
300
|
):
|
|
225
|
-
file_import.
|
|
301
|
+
file_import.merge(self.request_builder.imports())
|
|
302
|
+
file_import.add_submodule_import(
|
|
303
|
+
"azure.core.pipeline", "PipelineResponse", ImportType.AZURECORE
|
|
304
|
+
)
|
|
305
|
+
file_import.add_submodule_import(
|
|
306
|
+
"azure.core.rest", "HttpRequest", ImportType.AZURECORE
|
|
307
|
+
)
|
|
308
|
+
file_import.add_submodule_import(
|
|
309
|
+
"typing", "Callable", ImportType.STDLIB, TypingSection.CONDITIONAL
|
|
310
|
+
)
|
|
311
|
+
file_import.add_submodule_import(
|
|
312
|
+
"typing", "Optional", ImportType.STDLIB, TypingSection.CONDITIONAL
|
|
313
|
+
)
|
|
314
|
+
file_import.add_submodule_import(
|
|
315
|
+
"typing", "Dict", ImportType.STDLIB, TypingSection.CONDITIONAL
|
|
316
|
+
)
|
|
317
|
+
file_import.add_submodule_import(
|
|
318
|
+
"typing", "TypeVar", ImportType.STDLIB, TypingSection.CONDITIONAL
|
|
319
|
+
)
|
|
226
320
|
if self.code_model.options["tracing"] and self.want_tracing:
|
|
227
321
|
file_import.add_submodule_import(
|
|
228
322
|
f"azure.core.tracing.decorator{'_async' if async_mode else ''}",
|
|
229
323
|
f"distributed_trace{'_async' if async_mode else ''}",
|
|
230
324
|
ImportType.AZURECORE,
|
|
231
325
|
)
|
|
326
|
+
|
|
232
327
|
return file_import
|
|
233
328
|
|
|
234
329
|
def _get_body_param_from_body_kwarg(self, body_kwarg: Parameter) -> Parameter:
|
|
235
330
|
# determine which of the body parameters returned from m4 corresponds to this body_kwarg
|
|
236
331
|
if not self.multiple_content_type_parameters.has_body:
|
|
237
332
|
return self.parameters.body[0]
|
|
238
|
-
if body_kwarg.serialized_name == "data":
|
|
239
|
-
return next(p for p in self.multiple_content_type_parameters.body if p.is_data_input)
|
|
240
|
-
if body_kwarg.serialized_name == "files":
|
|
241
|
-
return next(p for p in self.multiple_content_type_parameters.body if p.is_multipart)
|
|
242
333
|
if body_kwarg.serialized_name == "json":
|
|
243
334
|
# first check if there's any non-binary. In the case of multiple content types, there's
|
|
244
335
|
# usually one binary (for content), and one schema parameter (for json)
|
|
245
336
|
try:
|
|
246
337
|
return next(
|
|
247
|
-
p
|
|
338
|
+
p
|
|
339
|
+
for p in self.multiple_content_type_parameters.body
|
|
248
340
|
if not isinstance(p.schema, IOSchema)
|
|
249
341
|
)
|
|
250
342
|
except StopIteration:
|
|
251
|
-
return next(
|
|
343
|
+
return next(
|
|
344
|
+
p
|
|
345
|
+
for p in self.multiple_content_type_parameters.body
|
|
346
|
+
if p.is_json_parameter
|
|
347
|
+
)
|
|
252
348
|
return self.multiple_content_type_parameters.body[0]
|
|
253
349
|
|
|
254
350
|
def link_body_kwargs_to_body_params(self) -> None:
|
|
255
351
|
if not self.parameters.has_body:
|
|
256
352
|
return
|
|
257
353
|
body_kwargs = [
|
|
258
|
-
p for p in self.request_builder.parameters.body
|
|
259
|
-
if p.content_types
|
|
354
|
+
p for p in self.request_builder.parameters.body if p.content_types
|
|
260
355
|
]
|
|
261
356
|
if len(body_kwargs) == 1:
|
|
262
357
|
self.parameters.body[0].body_kwargs = [body_kwargs[0]]
|
|
@@ -266,64 +361,109 @@ class Operation(BaseBuilder): # pylint: disable=too-many-public-methods, too-ma
|
|
|
266
361
|
body_param.body_kwargs.append(body_kwarg)
|
|
267
362
|
|
|
268
363
|
def convert_multiple_content_type_parameters(self) -> None:
|
|
269
|
-
type_annot = ", ".join(
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
364
|
+
type_annot = ", ".join(
|
|
365
|
+
[
|
|
366
|
+
param.schema.type_annotation(is_operation_file=True)
|
|
367
|
+
for param in self.multiple_content_type_parameters
|
|
368
|
+
]
|
|
369
|
+
)
|
|
370
|
+
docstring_type = " or ".join(
|
|
371
|
+
[
|
|
372
|
+
param.schema.docstring_type
|
|
373
|
+
for param in self.multiple_content_type_parameters
|
|
374
|
+
]
|
|
375
|
+
)
|
|
276
376
|
try:
|
|
277
377
|
# get an optional param with object first. These params are the top choice
|
|
278
378
|
# bc they have more info about how to serialize the body
|
|
279
379
|
chosen_parameter = next(
|
|
280
|
-
p
|
|
380
|
+
p
|
|
381
|
+
for p in self.multiple_content_type_parameters
|
|
281
382
|
if not p.required and isinstance(p.schema, ObjectSchema)
|
|
282
383
|
)
|
|
283
384
|
except StopIteration: # pylint: disable=broad-except
|
|
284
385
|
# otherwise, we get the first optional param, if that exists. If not, we just grab the first one
|
|
285
|
-
optional_parameters = [
|
|
386
|
+
optional_parameters = [
|
|
387
|
+
p for p in self.multiple_content_type_parameters if not p.required
|
|
388
|
+
]
|
|
286
389
|
chosen_parameter = (
|
|
287
|
-
optional_parameters[0]
|
|
390
|
+
optional_parameters[0]
|
|
391
|
+
if optional_parameters
|
|
392
|
+
else self.multiple_content_type_parameters[0]
|
|
288
393
|
)
|
|
289
394
|
if not chosen_parameter:
|
|
290
|
-
raise ValueError(
|
|
395
|
+
raise ValueError(
|
|
396
|
+
"You are missing a parameter that has multiple media types"
|
|
397
|
+
)
|
|
291
398
|
chosen_parameter.multiple_content_types_type_annot = f"Union[{type_annot}]"
|
|
292
399
|
chosen_parameter.multiple_content_types_docstring_type = docstring_type
|
|
293
400
|
self.parameters.append(chosen_parameter)
|
|
294
401
|
|
|
295
402
|
@classmethod
|
|
296
|
-
def from_yaml(
|
|
403
|
+
def from_yaml(
|
|
404
|
+
cls, yaml_data: Dict[str, Any], code_model: "CodeModel"
|
|
405
|
+
) -> "Operation":
|
|
297
406
|
name = yaml_data["language"]["python"]["name"]
|
|
298
407
|
_LOGGER.debug("Parsing %s operation", name)
|
|
299
408
|
|
|
300
409
|
parameter_creator = get_parameter(code_model).from_yaml
|
|
301
|
-
|
|
302
|
-
|
|
410
|
+
schema_requests = [
|
|
411
|
+
SchemaRequest.from_yaml(yaml, code_model=code_model)
|
|
412
|
+
for yaml in yaml_data["requests"]
|
|
413
|
+
]
|
|
303
414
|
parameters, multiple_content_type_parameters = create_parameters(
|
|
304
415
|
yaml_data, code_model, parameter_creator
|
|
305
416
|
)
|
|
306
|
-
parameter_list =
|
|
307
|
-
multiple_content_type_parameter_list =
|
|
417
|
+
parameter_list = ParameterList(code_model, parameters, schema_requests)
|
|
418
|
+
multiple_content_type_parameter_list = ParameterList(
|
|
308
419
|
code_model, multiple_content_type_parameters, schema_requests
|
|
309
420
|
)
|
|
421
|
+
abstract = False
|
|
422
|
+
if code_model.options["version_tolerant"] and (
|
|
423
|
+
any(p for p in parameter_list if p.is_multipart or p.is_data_input)
|
|
424
|
+
or any(
|
|
425
|
+
p
|
|
426
|
+
for p in multiple_content_type_parameter_list
|
|
427
|
+
if p.is_multipart or p.is_data_input
|
|
428
|
+
)
|
|
429
|
+
):
|
|
430
|
+
_LOGGER.warning(
|
|
431
|
+
'Not going to generate operation "%s" because it has multipart / urlencoded body parameters. '
|
|
432
|
+
"Multipart / urlencoded body parameters are not supported for version tolerant generation right now. "
|
|
433
|
+
'Please write your own custom operation in the "_patch.py" file '
|
|
434
|
+
"following https://aka.ms/azsdk/python/dpcodegen/python/customize",
|
|
435
|
+
name,
|
|
436
|
+
)
|
|
437
|
+
abstract = True
|
|
310
438
|
|
|
311
439
|
if len(parameter_list.content_types) > 1:
|
|
312
440
|
for p in parameter_list.parameters:
|
|
313
441
|
if p.rest_api_name == "Content-Type":
|
|
314
|
-
p.
|
|
442
|
+
p.method_location = ParameterMethodLocation.KEYWORD_ONLY
|
|
443
|
+
request_builder = code_model.lookup_request_builder(id(yaml_data))
|
|
315
444
|
|
|
316
445
|
return cls(
|
|
317
446
|
code_model=code_model,
|
|
318
447
|
yaml_data=yaml_data,
|
|
448
|
+
request_builder=request_builder,
|
|
319
449
|
name=name,
|
|
320
450
|
description=yaml_data["language"]["python"]["description"],
|
|
321
|
-
api_versions=set(
|
|
451
|
+
api_versions=set(
|
|
452
|
+
value_dict["version"] for value_dict in yaml_data["apiVersions"]
|
|
453
|
+
),
|
|
322
454
|
parameters=parameter_list,
|
|
323
455
|
multiple_content_type_parameters=multiple_content_type_parameter_list,
|
|
324
456
|
schema_requests=schema_requests,
|
|
325
457
|
summary=yaml_data["language"]["python"].get("summary"),
|
|
326
|
-
responses=[
|
|
458
|
+
responses=[
|
|
459
|
+
SchemaResponse.from_yaml(yaml, code_model=code_model)
|
|
460
|
+
for yaml in yaml_data.get("responses", [])
|
|
461
|
+
],
|
|
327
462
|
# Exception with no schema means default exception, we don't store them
|
|
328
|
-
exceptions=[
|
|
463
|
+
exceptions=[
|
|
464
|
+
SchemaResponse.from_yaml(yaml, code_model=code_model)
|
|
465
|
+
for yaml in yaml_data.get("exceptions", [])
|
|
466
|
+
if "schema" in yaml
|
|
467
|
+
],
|
|
468
|
+
abstract=abstract,
|
|
329
469
|
)
|