@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
|
@@ -3,227 +3,302 @@
|
|
|
3
3
|
# Licensed under the MIT License. See License.txt in the project root for
|
|
4
4
|
# license information.
|
|
5
5
|
# --------------------------------------------------------------------------
|
|
6
|
-
from itertools import chain
|
|
7
6
|
import logging
|
|
8
|
-
from
|
|
7
|
+
from itertools import chain
|
|
8
|
+
from typing import (
|
|
9
|
+
Dict,
|
|
10
|
+
List,
|
|
11
|
+
Any,
|
|
12
|
+
Optional,
|
|
13
|
+
Union,
|
|
14
|
+
TYPE_CHECKING,
|
|
15
|
+
Generic,
|
|
16
|
+
TypeVar,
|
|
17
|
+
cast,
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
from .request_builder_parameter import RequestBuilderParameter
|
|
9
21
|
|
|
10
|
-
from .
|
|
22
|
+
from .utils import OrderedSet, add_to_pylint_disable
|
|
23
|
+
|
|
24
|
+
from .base_builder import BaseBuilder
|
|
11
25
|
from .imports import FileImport, ImportType, TypingSection
|
|
12
|
-
from .
|
|
26
|
+
from .response import (
|
|
27
|
+
Response,
|
|
28
|
+
PagingResponse,
|
|
29
|
+
LROResponse,
|
|
30
|
+
LROPagingResponse,
|
|
31
|
+
get_response,
|
|
32
|
+
)
|
|
13
33
|
from .parameter import (
|
|
34
|
+
BodyParameter,
|
|
35
|
+
MultipartBodyParameter,
|
|
14
36
|
Parameter,
|
|
15
|
-
ParameterMethodLocation,
|
|
16
|
-
get_parameter,
|
|
17
37
|
ParameterLocation,
|
|
18
38
|
)
|
|
19
39
|
from .parameter_list import ParameterList
|
|
20
|
-
from .
|
|
21
|
-
from .
|
|
22
|
-
from .request_builder import RequestBuilder
|
|
23
|
-
from .schema_request import SchemaRequest
|
|
24
|
-
from .primitive_schemas import IOSchema
|
|
40
|
+
from .model_type import ModelType
|
|
41
|
+
from .request_builder import OverloadedRequestBuilder, RequestBuilder
|
|
25
42
|
|
|
26
43
|
if TYPE_CHECKING:
|
|
27
44
|
from .code_model import CodeModel
|
|
28
45
|
|
|
29
46
|
_LOGGER = logging.getLogger(__name__)
|
|
30
47
|
|
|
48
|
+
ResponseType = TypeVar(
|
|
49
|
+
"ResponseType",
|
|
50
|
+
bound=Union[Response, PagingResponse, LROResponse, LROPagingResponse],
|
|
51
|
+
)
|
|
31
52
|
|
|
32
|
-
class Operation(
|
|
33
|
-
BaseBuilder
|
|
34
|
-
): # pylint: disable=too-many-public-methods, too-many-instance-attributes
|
|
35
|
-
"""Represent an self."""
|
|
36
53
|
|
|
54
|
+
class OperationBase( # pylint: disable=too-many-public-methods
|
|
55
|
+
Generic[ResponseType], BaseBuilder[ParameterList]
|
|
56
|
+
):
|
|
37
57
|
def __init__(
|
|
38
58
|
self,
|
|
39
59
|
yaml_data: Dict[str, Any],
|
|
40
60
|
code_model: "CodeModel",
|
|
41
|
-
request_builder: RequestBuilder,
|
|
42
61
|
name: str,
|
|
43
|
-
|
|
44
|
-
api_versions: Set[str],
|
|
62
|
+
request_builder: Union[RequestBuilder, OverloadedRequestBuilder],
|
|
45
63
|
parameters: ParameterList,
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
summary: Optional[str] = None,
|
|
49
|
-
responses: Optional[List[SchemaResponse]] = None,
|
|
50
|
-
exceptions: Optional[List[SchemaResponse]] = None,
|
|
51
|
-
want_description_docstring: bool = True,
|
|
52
|
-
want_tracing: bool = True,
|
|
64
|
+
responses: List[ResponseType],
|
|
65
|
+
exceptions: List[Response],
|
|
53
66
|
*,
|
|
67
|
+
overloads: Optional[List["Operation"]] = None,
|
|
68
|
+
public: bool = True,
|
|
69
|
+
want_tracing: bool = True,
|
|
54
70
|
abstract: bool = False,
|
|
55
71
|
) -> None:
|
|
56
72
|
super().__init__(
|
|
57
73
|
code_model=code_model,
|
|
58
74
|
yaml_data=yaml_data,
|
|
59
75
|
name=name,
|
|
60
|
-
description=description,
|
|
61
76
|
parameters=parameters,
|
|
62
|
-
|
|
63
|
-
schema_requests=schema_requests,
|
|
64
|
-
summary=summary,
|
|
77
|
+
overloads=overloads,
|
|
65
78
|
abstract=abstract,
|
|
66
79
|
want_tracing=want_tracing,
|
|
67
80
|
)
|
|
68
|
-
self.
|
|
69
|
-
self.
|
|
70
|
-
self.
|
|
71
|
-
self.exceptions = exceptions or []
|
|
72
|
-
self.want_description_docstring = want_description_docstring
|
|
81
|
+
self.overloads: List["Operation"] = overloads or []
|
|
82
|
+
self.responses = responses
|
|
83
|
+
self.public = public
|
|
73
84
|
self.request_builder = request_builder
|
|
74
85
|
self.deprecated = False
|
|
86
|
+
self.exceptions = exceptions
|
|
75
87
|
|
|
76
88
|
@property
|
|
77
|
-
def
|
|
78
|
-
return
|
|
79
|
-
|
|
80
|
-
@property
|
|
81
|
-
def is_stream_response(self) -> bool:
|
|
82
|
-
"""Is the response expected to be streamable, like a download."""
|
|
83
|
-
return any(response.is_stream_response for response in self.responses)
|
|
84
|
-
|
|
85
|
-
@property
|
|
86
|
-
def body_kwargs_to_pass_to_request_builder(self) -> List[str]:
|
|
87
|
-
return [p.serialized_name for p in self.request_builder.body_kwargs_to_get]
|
|
89
|
+
def operation_type(self) -> str:
|
|
90
|
+
return "operation"
|
|
88
91
|
|
|
89
92
|
@property
|
|
90
93
|
def has_optional_return_type(self) -> bool:
|
|
91
94
|
"""Has optional return type if there are multiple successful response types where some have
|
|
92
95
|
bodies and some are None
|
|
93
96
|
"""
|
|
97
|
+
# means if we have at least one successful response with a body and one without
|
|
98
|
+
successful_response_with_body = any(r for r in self.responses if r.type)
|
|
99
|
+
successful_response_without_body = any(r for r in self.responses if not r.type)
|
|
100
|
+
return successful_response_with_body and successful_response_without_body
|
|
94
101
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
response
|
|
102
|
+
def response_type_annotation(self, **kwargs) -> str:
|
|
103
|
+
if (
|
|
104
|
+
self.code_model.options["head_as_boolean"]
|
|
105
|
+
and self.request_builder.method.lower() == "head"
|
|
106
|
+
):
|
|
107
|
+
return "bool"
|
|
108
|
+
response_type_annotations: OrderedSet[str] = {
|
|
109
|
+
response.type_annotation(**kwargs): None
|
|
104
110
|
for response in self.responses
|
|
105
|
-
if
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
111
|
+
if response.type
|
|
112
|
+
}
|
|
113
|
+
response_str = ", ".join(response_type_annotations.keys())
|
|
114
|
+
if len(response_type_annotations) > 1:
|
|
115
|
+
return f"Union[{response_str}]"
|
|
116
|
+
if self.has_optional_return_type:
|
|
117
|
+
return f"Optional[{response_str}]"
|
|
118
|
+
if self.responses:
|
|
119
|
+
return self.responses[0].type_annotation(**kwargs)
|
|
120
|
+
return "None"
|
|
114
121
|
|
|
115
122
|
@property
|
|
116
|
-
def
|
|
117
|
-
|
|
118
|
-
|
|
123
|
+
def pylint_disable(self) -> str:
|
|
124
|
+
retval: str = ""
|
|
125
|
+
if self.response_type_annotation(async_mode=False) == "None":
|
|
126
|
+
# doesn't matter if it's async or not
|
|
127
|
+
retval = add_to_pylint_disable(retval, "inconsistent-return-statements")
|
|
128
|
+
return retval
|
|
129
|
+
|
|
130
|
+
def cls_type_annotation(self, *, async_mode: bool) -> str:
|
|
131
|
+
if (
|
|
132
|
+
self.request_builder.method.lower() == "head"
|
|
133
|
+
and self.code_model.options["head_as_boolean"]
|
|
134
|
+
):
|
|
135
|
+
return "ClsType[None]"
|
|
136
|
+
return f"ClsType[{self.response_type_annotation(async_mode=async_mode)}]"
|
|
137
|
+
|
|
138
|
+
def _response_docstring_helper(self, attr_name: str, **kwargs: Any) -> str:
|
|
139
|
+
responses_with_body = [r for r in self.responses if r.type]
|
|
140
|
+
if (
|
|
141
|
+
self.request_builder.method.lower() == "head"
|
|
142
|
+
and self.code_model.options["head_as_boolean"]
|
|
143
|
+
):
|
|
144
|
+
return "bool"
|
|
145
|
+
if responses_with_body:
|
|
146
|
+
response_docstring_values: OrderedSet[str] = {
|
|
147
|
+
getattr(response, attr_name)(**kwargs): None
|
|
148
|
+
for response in responses_with_body
|
|
149
|
+
}
|
|
150
|
+
retval = " or ".join(response_docstring_values.keys())
|
|
151
|
+
if self.has_optional_return_type:
|
|
152
|
+
retval += " or None"
|
|
153
|
+
return retval
|
|
154
|
+
if self.responses:
|
|
155
|
+
return getattr(self.responses[0], attr_name)(**kwargs)
|
|
156
|
+
return "None"
|
|
157
|
+
|
|
158
|
+
def response_docstring_text(self, **kwargs) -> str:
|
|
159
|
+
retval = self._response_docstring_helper("docstring_text", **kwargs)
|
|
160
|
+
if not self.code_model.options["version_tolerant"]:
|
|
161
|
+
retval += " or the result of cls(response)"
|
|
162
|
+
return retval
|
|
163
|
+
|
|
164
|
+
def response_docstring_type(self, **kwargs) -> str:
|
|
165
|
+
return self._response_docstring_helper("docstring_type", **kwargs)
|
|
119
166
|
|
|
120
167
|
@property
|
|
121
168
|
def has_response_body(self) -> bool:
|
|
122
169
|
"""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
|
-
)
|
|
170
|
+
return any(response.type for response in self.responses)
|
|
127
171
|
|
|
128
172
|
@property
|
|
129
173
|
def any_response_has_headers(self) -> bool:
|
|
130
|
-
return any(response.
|
|
174
|
+
return any(response.headers for response in self.responses)
|
|
131
175
|
|
|
132
176
|
@property
|
|
133
|
-
def
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
for excp in self.exceptions
|
|
137
|
-
for code in excp.status_codes
|
|
138
|
-
if code == "default"
|
|
177
|
+
def default_error_deserialization(self) -> Optional[str]:
|
|
178
|
+
default_exceptions = [
|
|
179
|
+
e for e in self.exceptions if "default" in e.status_codes and e.type
|
|
139
180
|
]
|
|
140
|
-
if not
|
|
181
|
+
if not default_exceptions:
|
|
141
182
|
return None
|
|
142
|
-
excep_schema =
|
|
143
|
-
if isinstance(excep_schema,
|
|
183
|
+
excep_schema = default_exceptions[0].type
|
|
184
|
+
if isinstance(excep_schema, ModelType):
|
|
144
185
|
return f"_models.{excep_schema.name}"
|
|
145
|
-
# in this case, it's just an
|
|
186
|
+
# in this case, it's just an AnyType
|
|
146
187
|
return "'object'"
|
|
147
188
|
|
|
148
189
|
@property
|
|
149
|
-
def
|
|
150
|
-
return [
|
|
151
|
-
excp for excp in self.exceptions if list(excp.status_codes) != ["default"]
|
|
152
|
-
]
|
|
190
|
+
def non_default_errors(self) -> List[Response]:
|
|
191
|
+
return [e for e in self.exceptions if "default" not in e.status_codes]
|
|
153
192
|
|
|
154
193
|
@property
|
|
155
|
-
def
|
|
194
|
+
def non_default_error_status_codes(self) -> List[Union[str, int]]:
|
|
156
195
|
"""Actually returns all of the status codes from exceptions (besides default)"""
|
|
157
196
|
return list(
|
|
158
197
|
chain.from_iterable(
|
|
159
|
-
[
|
|
198
|
+
[error.status_codes for error in self.non_default_errors]
|
|
160
199
|
)
|
|
161
200
|
)
|
|
162
201
|
|
|
163
|
-
def _imports_shared(
|
|
164
|
-
self, async_mode: bool # pylint: disable=unused-argument
|
|
165
|
-
) -> FileImport:
|
|
202
|
+
def _imports_shared(self, async_mode: bool, **kwargs: Any) -> FileImport:
|
|
166
203
|
file_import = FileImport()
|
|
167
204
|
file_import.add_submodule_import(
|
|
168
205
|
"typing", "Any", ImportType.STDLIB, TypingSection.CONDITIONAL
|
|
169
206
|
)
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
file_import.merge(param.imports())
|
|
174
|
-
|
|
175
|
-
for param in self.multiple_content_type_parameters:
|
|
176
|
-
file_import.merge(param.imports())
|
|
177
|
-
|
|
178
|
-
for response in self.responses:
|
|
179
|
-
file_import.merge(response.imports(self.code_model))
|
|
180
|
-
if response.has_body:
|
|
181
|
-
file_import.merge(cast(BaseSchema, response.schema).imports())
|
|
207
|
+
if not self.abstract:
|
|
208
|
+
for param in self.parameters.method:
|
|
209
|
+
file_import.merge(param.imports(async_mode, **kwargs))
|
|
182
210
|
|
|
183
211
|
response_types = [
|
|
184
|
-
r.type_annotation(
|
|
185
|
-
for r in self.responses
|
|
186
|
-
if r.has_body
|
|
212
|
+
r.type_annotation(async_mode=async_mode) for r in self.responses if r.type
|
|
187
213
|
]
|
|
188
214
|
if len(set(response_types)) > 1:
|
|
189
215
|
file_import.add_submodule_import(
|
|
190
216
|
"typing", "Union", ImportType.STDLIB, TypingSection.CONDITIONAL
|
|
191
217
|
)
|
|
192
|
-
|
|
193
|
-
if self.is_stream_response:
|
|
194
|
-
file_import.add_submodule_import(
|
|
195
|
-
"typing", "IO", ImportType.STDLIB, TypingSection.CONDITIONAL
|
|
196
|
-
)
|
|
197
218
|
return file_import
|
|
198
219
|
|
|
199
|
-
def imports_for_multiapi(
|
|
200
|
-
self,
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
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)
|
|
220
|
+
def imports_for_multiapi(self, async_mode: bool, **kwargs: Any) -> FileImport:
|
|
221
|
+
file_import = self._imports_shared(async_mode, **kwargs)
|
|
222
|
+
for response in self.responses:
|
|
223
|
+
file_import.merge(
|
|
224
|
+
response.imports_for_multiapi(async_mode=async_mode, **kwargs)
|
|
225
|
+
)
|
|
226
|
+
if self.code_model.options["models_mode"]:
|
|
227
|
+
for exception in self.exceptions:
|
|
228
|
+
file_import.merge(
|
|
229
|
+
exception.imports_for_multiapi(async_mode=async_mode, **kwargs)
|
|
230
|
+
)
|
|
214
231
|
return file_import
|
|
215
232
|
|
|
216
233
|
@staticmethod
|
|
217
234
|
def has_kwargs_to_pop_with_default(
|
|
218
|
-
kwargs_to_pop: List[
|
|
235
|
+
kwargs_to_pop: List[
|
|
236
|
+
Union[
|
|
237
|
+
Parameter,
|
|
238
|
+
RequestBuilderParameter,
|
|
239
|
+
BodyParameter,
|
|
240
|
+
MultipartBodyParameter,
|
|
241
|
+
]
|
|
242
|
+
],
|
|
243
|
+
location: ParameterLocation,
|
|
219
244
|
) -> bool:
|
|
220
245
|
return any(
|
|
221
|
-
kwarg.
|
|
246
|
+
(kwarg.client_default_value or kwarg.optional)
|
|
247
|
+
and kwarg.location == location
|
|
222
248
|
for kwarg in kwargs_to_pop
|
|
223
249
|
)
|
|
224
250
|
|
|
225
|
-
def
|
|
226
|
-
|
|
251
|
+
def get_request_builder_import(
|
|
252
|
+
self,
|
|
253
|
+
request_builder: Union[RequestBuilder, OverloadedRequestBuilder],
|
|
254
|
+
async_mode: bool,
|
|
255
|
+
) -> FileImport:
|
|
256
|
+
"""Helper method to get a request builder import."""
|
|
257
|
+
file_import = FileImport()
|
|
258
|
+
if self.code_model.options["builders_visibility"] != "embedded":
|
|
259
|
+
group_name = request_builder.group_name
|
|
260
|
+
rest_import_path = "..." if async_mode else ".."
|
|
261
|
+
if group_name:
|
|
262
|
+
file_import.add_submodule_import(
|
|
263
|
+
f"{rest_import_path}{self.code_model.rest_layer_name}",
|
|
264
|
+
group_name,
|
|
265
|
+
import_type=ImportType.LOCAL,
|
|
266
|
+
alias=f"rest_{group_name}",
|
|
267
|
+
)
|
|
268
|
+
else:
|
|
269
|
+
file_import.add_submodule_import(
|
|
270
|
+
rest_import_path,
|
|
271
|
+
self.code_model.rest_layer_name,
|
|
272
|
+
import_type=ImportType.LOCAL,
|
|
273
|
+
alias="rest",
|
|
274
|
+
)
|
|
275
|
+
if self.code_model.options["builders_visibility"] == "embedded" and async_mode:
|
|
276
|
+
suffix = (
|
|
277
|
+
"_py3"
|
|
278
|
+
if self.code_model.options["add_python3_operation_files"]
|
|
279
|
+
and not self.code_model.options["python3_only"]
|
|
280
|
+
else ""
|
|
281
|
+
)
|
|
282
|
+
file_import.add_submodule_import(
|
|
283
|
+
f"...{self.code_model.operations_folder_name}.{self.filename}{suffix}",
|
|
284
|
+
request_builder.name,
|
|
285
|
+
import_type=ImportType.LOCAL,
|
|
286
|
+
)
|
|
287
|
+
return file_import
|
|
288
|
+
|
|
289
|
+
def imports(
|
|
290
|
+
self, async_mode: bool, is_python3_file: bool, **kwargs: Any
|
|
291
|
+
) -> FileImport:
|
|
292
|
+
file_import = self._imports_shared(async_mode, **kwargs)
|
|
293
|
+
|
|
294
|
+
for response in self.responses:
|
|
295
|
+
file_import.merge(response.imports(async_mode=async_mode, **kwargs))
|
|
296
|
+
if self.code_model.options["models_mode"]:
|
|
297
|
+
for exception in self.exceptions:
|
|
298
|
+
file_import.merge(exception.imports(async_mode=async_mode, **kwargs))
|
|
299
|
+
|
|
300
|
+
if self.parameters.has_body and self.parameters.body_parameter.flattened:
|
|
301
|
+
file_import.merge(self.parameters.body_parameter.type.imports(**kwargs))
|
|
227
302
|
|
|
228
303
|
# Exceptions
|
|
229
304
|
if self.abstract:
|
|
@@ -253,32 +328,16 @@ class Operation(
|
|
|
253
328
|
|
|
254
329
|
kwargs_to_pop = self.parameters.kwargs_to_pop(is_python3_file)
|
|
255
330
|
if self.has_kwargs_to_pop_with_default(
|
|
256
|
-
kwargs_to_pop, ParameterLocation.
|
|
331
|
+
kwargs_to_pop, ParameterLocation.HEADER
|
|
257
332
|
) or self.has_kwargs_to_pop_with_default(
|
|
258
|
-
kwargs_to_pop, ParameterLocation.
|
|
333
|
+
kwargs_to_pop, ParameterLocation.QUERY
|
|
259
334
|
):
|
|
260
335
|
file_import.add_submodule_import(
|
|
261
336
|
"azure.core.utils", "case_insensitive_dict", ImportType.AZURECORE
|
|
262
337
|
)
|
|
263
338
|
if self.deprecated:
|
|
264
339
|
file_import.add_import("warnings", ImportType.STDLIB)
|
|
265
|
-
|
|
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
|
-
)
|
|
340
|
+
|
|
282
341
|
if self.code_model.need_request_converter:
|
|
283
342
|
relative_path = "..." if async_mode else ".."
|
|
284
343
|
file_import.add_submodule_import(
|
|
@@ -317,115 +376,74 @@ class Operation(
|
|
|
317
376
|
file_import.add_submodule_import(
|
|
318
377
|
"typing", "TypeVar", ImportType.STDLIB, TypingSection.CONDITIONAL
|
|
319
378
|
)
|
|
320
|
-
if self.code_model.options["tracing"] and self.want_tracing:
|
|
379
|
+
if self.code_model.options["tracing"] and self.want_tracing and not async_mode:
|
|
321
380
|
file_import.add_submodule_import(
|
|
322
|
-
f"azure.core.tracing.decorator
|
|
323
|
-
f"distributed_trace
|
|
381
|
+
f"azure.core.tracing.decorator",
|
|
382
|
+
f"distributed_trace",
|
|
324
383
|
ImportType.AZURECORE,
|
|
325
384
|
)
|
|
326
|
-
|
|
385
|
+
if not self.abstract:
|
|
386
|
+
file_import.merge(
|
|
387
|
+
self.get_request_builder_import(self.request_builder, async_mode)
|
|
388
|
+
)
|
|
389
|
+
if self.overloads:
|
|
390
|
+
file_import.add_submodule_import("typing", "overload", ImportType.STDLIB)
|
|
327
391
|
return file_import
|
|
328
392
|
|
|
329
|
-
def
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
return self.parameters.body[0]
|
|
333
|
-
if body_kwarg.serialized_name == "json":
|
|
334
|
-
# first check if there's any non-binary. In the case of multiple content types, there's
|
|
335
|
-
# usually one binary (for content), and one schema parameter (for json)
|
|
336
|
-
try:
|
|
337
|
-
return next(
|
|
338
|
-
p
|
|
339
|
-
for p in self.multiple_content_type_parameters.body
|
|
340
|
-
if not isinstance(p.schema, IOSchema)
|
|
341
|
-
)
|
|
342
|
-
except StopIteration:
|
|
343
|
-
return next(
|
|
344
|
-
p
|
|
345
|
-
for p in self.multiple_content_type_parameters.body
|
|
346
|
-
if p.is_json_parameter
|
|
347
|
-
)
|
|
348
|
-
return self.multiple_content_type_parameters.body[0]
|
|
349
|
-
|
|
350
|
-
def link_body_kwargs_to_body_params(self) -> None:
|
|
351
|
-
if not self.parameters.has_body:
|
|
352
|
-
return
|
|
353
|
-
body_kwargs = [
|
|
354
|
-
p for p in self.request_builder.parameters.body if p.content_types
|
|
355
|
-
]
|
|
356
|
-
if len(body_kwargs) == 1:
|
|
357
|
-
self.parameters.body[0].body_kwargs = [body_kwargs[0]]
|
|
358
|
-
return
|
|
359
|
-
for body_kwarg in body_kwargs:
|
|
360
|
-
body_param = self._get_body_param_from_body_kwarg(body_kwarg)
|
|
361
|
-
body_param.body_kwargs.append(body_kwarg)
|
|
362
|
-
|
|
363
|
-
def convert_multiple_content_type_parameters(self) -> None:
|
|
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
|
-
)
|
|
393
|
+
def get_response_from_status(
|
|
394
|
+
self, status_code: Optional[Union[str, int]]
|
|
395
|
+
) -> ResponseType:
|
|
376
396
|
try:
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
chosen_parameter = next(
|
|
380
|
-
p
|
|
381
|
-
for p in self.multiple_content_type_parameters
|
|
382
|
-
if not p.required and isinstance(p.schema, ObjectSchema)
|
|
383
|
-
)
|
|
384
|
-
except StopIteration: # pylint: disable=broad-except
|
|
385
|
-
# otherwise, we get the first optional param, if that exists. If not, we just grab the first one
|
|
386
|
-
optional_parameters = [
|
|
387
|
-
p for p in self.multiple_content_type_parameters if not p.required
|
|
388
|
-
]
|
|
389
|
-
chosen_parameter = (
|
|
390
|
-
optional_parameters[0]
|
|
391
|
-
if optional_parameters
|
|
392
|
-
else self.multiple_content_type_parameters[0]
|
|
393
|
-
)
|
|
394
|
-
if not chosen_parameter:
|
|
397
|
+
return next(r for r in self.responses if status_code in r.status_codes)
|
|
398
|
+
except StopIteration:
|
|
395
399
|
raise ValueError(
|
|
396
|
-
"
|
|
400
|
+
f"Incorrect status code {status_code}, operation {self.name}"
|
|
397
401
|
)
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
402
|
+
|
|
403
|
+
@property
|
|
404
|
+
def success_status_codes(self) -> List[Union[str, int]]:
|
|
405
|
+
"""The list of all successfull status code."""
|
|
406
|
+
return [code for response in self.responses for code in response.status_codes]
|
|
407
|
+
|
|
408
|
+
@property
|
|
409
|
+
def filename(self) -> str:
|
|
410
|
+
basename = self.group_name
|
|
411
|
+
if basename == "":
|
|
412
|
+
# in a mixin
|
|
413
|
+
basename = self.code_model.module_name
|
|
414
|
+
|
|
415
|
+
if (
|
|
416
|
+
basename == "operations"
|
|
417
|
+
or self.code_model.options["combine_operation_files"]
|
|
418
|
+
):
|
|
419
|
+
return f"_operations"
|
|
420
|
+
return f"_{basename}_operations"
|
|
421
|
+
|
|
422
|
+
@property
|
|
423
|
+
def has_stream_response(self) -> bool:
|
|
424
|
+
return any(r.is_stream_response for r in self.responses)
|
|
401
425
|
|
|
402
426
|
@classmethod
|
|
403
|
-
def from_yaml(
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
427
|
+
def from_yaml(cls, yaml_data: Dict[str, Any], code_model: "CodeModel"):
|
|
428
|
+
name = yaml_data["name"]
|
|
429
|
+
request_builder = code_model.lookup_request_builder(id(yaml_data))
|
|
430
|
+
responses = [
|
|
431
|
+
cast(ResponseType, get_response(r, code_model))
|
|
432
|
+
for r in yaml_data["responses"]
|
|
433
|
+
]
|
|
434
|
+
exceptions = [
|
|
435
|
+
Response.from_yaml(e, code_model) for e in yaml_data["exceptions"]
|
|
436
|
+
]
|
|
437
|
+
parameter_list = ParameterList.from_yaml(yaml_data, code_model)
|
|
438
|
+
overloads = [
|
|
439
|
+
cls.from_yaml(overload, code_model)
|
|
440
|
+
for overload in yaml_data.get("overloads", [])
|
|
413
441
|
]
|
|
414
|
-
parameters, multiple_content_type_parameters = create_parameters(
|
|
415
|
-
yaml_data, code_model, parameter_creator
|
|
416
|
-
)
|
|
417
|
-
parameter_list = ParameterList(code_model, parameters, schema_requests)
|
|
418
|
-
multiple_content_type_parameter_list = ParameterList(
|
|
419
|
-
code_model, multiple_content_type_parameters, schema_requests
|
|
420
|
-
)
|
|
421
442
|
abstract = False
|
|
422
|
-
if
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
for p in multiple_content_type_parameter_list
|
|
427
|
-
if p.is_multipart or p.is_data_input
|
|
428
|
-
)
|
|
443
|
+
if (
|
|
444
|
+
code_model.options["version_tolerant"]
|
|
445
|
+
and parameter_list.has_body
|
|
446
|
+
and isinstance(parameter_list.body_parameter, MultipartBodyParameter)
|
|
429
447
|
):
|
|
430
448
|
_LOGGER.warning(
|
|
431
449
|
'Not going to generate operation "%s" because it has multipart / urlencoded body parameters. '
|
|
@@ -436,34 +454,50 @@ class Operation(
|
|
|
436
454
|
)
|
|
437
455
|
abstract = True
|
|
438
456
|
|
|
439
|
-
if len(parameter_list.content_types) > 1:
|
|
440
|
-
for p in parameter_list.parameters:
|
|
441
|
-
if p.rest_api_name == "Content-Type":
|
|
442
|
-
p.method_location = ParameterMethodLocation.KEYWORD_ONLY
|
|
443
|
-
request_builder = code_model.lookup_request_builder(id(yaml_data))
|
|
444
|
-
|
|
445
457
|
return cls(
|
|
446
|
-
code_model=code_model,
|
|
447
458
|
yaml_data=yaml_data,
|
|
459
|
+
code_model=code_model,
|
|
448
460
|
request_builder=request_builder,
|
|
449
461
|
name=name,
|
|
450
|
-
description=yaml_data["language"]["python"]["description"],
|
|
451
|
-
api_versions=set(
|
|
452
|
-
value_dict["version"] for value_dict in yaml_data["apiVersions"]
|
|
453
|
-
),
|
|
454
462
|
parameters=parameter_list,
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
SchemaResponse.from_yaml(yaml, code_model=code_model)
|
|
460
|
-
for yaml in yaml_data.get("responses", [])
|
|
461
|
-
],
|
|
462
|
-
# Exception with no schema means default exception, we don't store them
|
|
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
|
-
],
|
|
463
|
+
overloads=overloads,
|
|
464
|
+
responses=responses,
|
|
465
|
+
exceptions=exceptions,
|
|
466
|
+
want_tracing=not yaml_data["isOverload"],
|
|
468
467
|
abstract=abstract,
|
|
469
468
|
)
|
|
469
|
+
|
|
470
|
+
|
|
471
|
+
class Operation(OperationBase[Response]):
|
|
472
|
+
def imports(
|
|
473
|
+
self, async_mode: bool, is_python3_file: bool, **kwargs: Any
|
|
474
|
+
) -> FileImport:
|
|
475
|
+
file_import = super().imports(async_mode, is_python3_file, **kwargs)
|
|
476
|
+
if async_mode:
|
|
477
|
+
file_import.add_submodule_import(
|
|
478
|
+
f"azure.core.tracing.decorator_async",
|
|
479
|
+
f"distributed_trace_async",
|
|
480
|
+
ImportType.AZURECORE,
|
|
481
|
+
)
|
|
482
|
+
if self.abstract:
|
|
483
|
+
return file_import
|
|
484
|
+
if (
|
|
485
|
+
self.has_response_body
|
|
486
|
+
and not self.has_optional_return_type
|
|
487
|
+
and not self.code_model.options["models_mode"]
|
|
488
|
+
):
|
|
489
|
+
file_import.add_submodule_import("typing", "cast", ImportType.STDLIB)
|
|
490
|
+
|
|
491
|
+
return file_import
|
|
492
|
+
|
|
493
|
+
|
|
494
|
+
def get_operation(yaml_data: Dict[str, Any], code_model: "CodeModel") -> OperationBase:
|
|
495
|
+
if yaml_data["discriminator"] == "lropaging":
|
|
496
|
+
from .lro_paging_operation import LROPagingOperation as OperationCls
|
|
497
|
+
elif yaml_data["discriminator"] == "lro":
|
|
498
|
+
from .lro_operation import LROOperation as OperationCls # type: ignore
|
|
499
|
+
elif yaml_data["discriminator"] == "paging":
|
|
500
|
+
from .paging_operation import PagingOperation as OperationCls # type: ignore
|
|
501
|
+
else:
|
|
502
|
+
from . import Operation as OperationCls # type: ignore
|
|
503
|
+
return OperationCls.from_yaml(yaml_data, code_model)
|