@autorest/python 5.15.0 → 5.18.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 +98 -4
- package/README.md +30 -4
- package/autorest/__init__.py +2 -3
- package/autorest/black/__init__.py +12 -5
- package/autorest/codegen/__init__.py +122 -211
- package/autorest/codegen/models/__init__.py +122 -78
- package/autorest/codegen/models/base_builder.py +70 -72
- package/autorest/codegen/models/base_model.py +7 -5
- package/autorest/codegen/models/{base_schema.py → base_type.py} +68 -45
- package/autorest/codegen/models/client.py +193 -40
- package/autorest/codegen/models/code_model.py +145 -245
- package/autorest/codegen/models/combined_type.py +107 -0
- package/autorest/codegen/models/constant_type.py +122 -0
- 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 +93 -41
- package/autorest/codegen/models/list_type.py +149 -0
- package/autorest/codegen/models/lro_operation.py +90 -133
- package/autorest/codegen/models/lro_paging_operation.py +28 -12
- package/autorest/codegen/models/model_type.py +262 -0
- package/autorest/codegen/models/operation.py +412 -259
- package/autorest/codegen/models/operation_group.py +80 -91
- package/autorest/codegen/models/paging_operation.py +101 -117
- package/autorest/codegen/models/parameter.py +302 -341
- package/autorest/codegen/models/parameter_list.py +373 -357
- package/autorest/codegen/models/primitive_types.py +544 -0
- package/autorest/codegen/models/property.py +136 -134
- package/autorest/codegen/models/request_builder.py +138 -86
- package/autorest/codegen/models/request_builder_parameter.py +122 -86
- package/autorest/codegen/models/response.py +325 -0
- package/autorest/codegen/models/utils.py +13 -17
- package/autorest/codegen/serializers/__init__.py +212 -112
- package/autorest/codegen/serializers/builder_serializer.py +931 -1040
- package/autorest/codegen/serializers/client_serializer.py +140 -84
- package/autorest/codegen/serializers/general_serializer.py +26 -50
- package/autorest/codegen/serializers/import_serializer.py +96 -31
- package/autorest/codegen/serializers/metadata_serializer.py +39 -79
- package/autorest/codegen/serializers/model_base_serializer.py +62 -34
- package/autorest/codegen/serializers/model_generic_serializer.py +9 -10
- package/autorest/codegen/serializers/model_init_serializer.py +4 -2
- package/autorest/codegen/serializers/model_python3_serializer.py +29 -22
- package/autorest/codegen/serializers/operation_groups_serializer.py +21 -19
- package/autorest/codegen/serializers/operations_init_serializer.py +23 -11
- package/autorest/codegen/serializers/parameter_serializer.py +174 -0
- package/autorest/codegen/serializers/patch_serializer.py +4 -1
- package/autorest/codegen/serializers/request_builders_serializer.py +57 -0
- package/autorest/codegen/serializers/utils.py +0 -126
- 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 +3 -3
- package/autorest/codegen/templates/lro_operation.py.jinja2 +6 -5
- package/autorest/codegen/templates/lro_paging_operation.py.jinja2 +6 -5
- package/autorest/codegen/templates/metadata.json.jinja2 +36 -35
- 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 +10 -14
- package/autorest/codegen/templates/operation_group.py.jinja2 +9 -15
- 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 +7 -8
- package/autorest/codegen/templates/request_builder.py.jinja2 +19 -10
- package/autorest/codegen/templates/setup.py.jinja2 +9 -3
- package/autorest/codegen/templates/vendor.py.jinja2 +1 -1
- package/autorest/jsonrpc/__init__.py +7 -12
- package/autorest/jsonrpc/localapi.py +4 -3
- package/autorest/jsonrpc/server.py +28 -9
- package/autorest/jsonrpc/stdstream.py +13 -6
- package/autorest/m2r/__init__.py +5 -8
- package/autorest/m4reformatter/__init__.py +1126 -0
- 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 +24 -17
- 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 +20 -25
- package/autorest/multiapi/serializers/import_serializer.py +47 -17
- package/autorest/multiapi/serializers/multiapi_serializer.py +17 -17
- 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/multiapi/utils.py +3 -3
- 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 +25 -32
- package/package.json +3 -3
- package/run-python3.js +2 -3
- package/venvtools.py +1 -1
- package/autorest/codegen/models/constant_schema.py +0 -101
- package/autorest/codegen/models/credential_model.py +0 -47
- package/autorest/codegen/models/credential_schema.py +0 -91
- package/autorest/codegen/models/credential_schema_policy.py +0 -77
- package/autorest/codegen/models/dictionary_schema.py +0 -103
- package/autorest/codegen/models/enum_schema.py +0 -215
- package/autorest/codegen/models/list_schema.py +0 -123
- package/autorest/codegen/models/object_schema.py +0 -253
- package/autorest/codegen/models/primitive_schemas.py +0 -466
- package/autorest/codegen/models/request_builder_parameter_list.py +0 -280
- package/autorest/codegen/models/rest.py +0 -42
- package/autorest/codegen/models/schema_request.py +0 -45
- package/autorest/codegen/models/schema_response.py +0 -136
- package/autorest/codegen/serializers/rest_serializer.py +0 -57
- package/autorest/namer/__init__.py +0 -25
- package/autorest/namer/name_converter.py +0 -412
|
@@ -3,348 +3,501 @@
|
|
|
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
|
|
9
|
-
|
|
10
|
-
|
|
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
|
|
21
|
+
|
|
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 .
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
from .
|
|
26
|
+
from .response import (
|
|
27
|
+
Response,
|
|
28
|
+
PagingResponse,
|
|
29
|
+
LROResponse,
|
|
30
|
+
LROPagingResponse,
|
|
31
|
+
get_response,
|
|
32
|
+
)
|
|
33
|
+
from .parameter import (
|
|
34
|
+
BodyParameter,
|
|
35
|
+
MultipartBodyParameter,
|
|
36
|
+
Parameter,
|
|
37
|
+
ParameterLocation,
|
|
38
|
+
)
|
|
39
|
+
from .parameter_list import ParameterList
|
|
40
|
+
from .model_type import ModelType
|
|
41
|
+
from .request_builder import OverloadedRequestBuilder, RequestBuilder
|
|
42
|
+
|
|
43
|
+
if TYPE_CHECKING:
|
|
44
|
+
from .code_model import CodeModel
|
|
20
45
|
|
|
21
46
|
_LOGGER = logging.getLogger(__name__)
|
|
22
47
|
|
|
23
|
-
|
|
24
|
-
""
|
|
25
|
-
|
|
48
|
+
ResponseType = TypeVar(
|
|
49
|
+
"ResponseType",
|
|
50
|
+
bound=Union[Response, PagingResponse, LROResponse, LROPagingResponse],
|
|
51
|
+
)
|
|
52
|
+
|
|
26
53
|
|
|
54
|
+
class OperationBase( # pylint: disable=too-many-public-methods
|
|
55
|
+
Generic[ResponseType], BaseBuilder[ParameterList]
|
|
56
|
+
):
|
|
27
57
|
def __init__(
|
|
28
58
|
self,
|
|
29
|
-
code_model,
|
|
30
59
|
yaml_data: Dict[str, Any],
|
|
60
|
+
code_model: "CodeModel",
|
|
31
61
|
name: str,
|
|
32
|
-
|
|
33
|
-
api_versions: Set[str],
|
|
62
|
+
request_builder: Union[RequestBuilder, OverloadedRequestBuilder],
|
|
34
63
|
parameters: ParameterList,
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
want_description_docstring: bool = True,
|
|
64
|
+
responses: List[ResponseType],
|
|
65
|
+
exceptions: List[Response],
|
|
66
|
+
*,
|
|
67
|
+
overloads: Optional[List["Operation"]] = None,
|
|
68
|
+
public: bool = True,
|
|
41
69
|
want_tracing: bool = True,
|
|
70
|
+
abstract: bool = False,
|
|
42
71
|
) -> None:
|
|
43
72
|
super().__init__(
|
|
44
73
|
code_model=code_model,
|
|
45
74
|
yaml_data=yaml_data,
|
|
46
75
|
name=name,
|
|
47
|
-
description=description,
|
|
48
76
|
parameters=parameters,
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
77
|
+
overloads=overloads,
|
|
78
|
+
abstract=abstract,
|
|
79
|
+
want_tracing=want_tracing,
|
|
52
80
|
)
|
|
53
|
-
self.
|
|
54
|
-
self.
|
|
55
|
-
self.
|
|
56
|
-
self.
|
|
57
|
-
self.want_description_docstring = want_description_docstring
|
|
58
|
-
self.want_tracing = want_tracing
|
|
59
|
-
self._request_builder: Optional[RequestBuilder] = None
|
|
81
|
+
self.overloads: List["Operation"] = overloads or []
|
|
82
|
+
self.responses = responses
|
|
83
|
+
self.public = public
|
|
84
|
+
self.request_builder = request_builder
|
|
60
85
|
self.deprecated = False
|
|
86
|
+
self.exceptions = exceptions
|
|
61
87
|
|
|
62
88
|
@property
|
|
63
|
-
def
|
|
64
|
-
return
|
|
65
|
-
|
|
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
|
-
@property
|
|
80
|
-
def is_stream_response(self) -> bool:
|
|
81
|
-
"""Is the response expected to be streamable, like a download."""
|
|
82
|
-
return any(response.is_stream_response for response in self.responses)
|
|
83
|
-
|
|
84
|
-
@property
|
|
85
|
-
def body_kwargs_to_pass_to_request_builder(self) -> List[str]:
|
|
86
|
-
return [p.serialized_name for p in self.request_builder.body_kwargs_to_get]
|
|
89
|
+
def operation_type(self) -> str:
|
|
90
|
+
return "operation"
|
|
87
91
|
|
|
88
92
|
@property
|
|
89
93
|
def has_optional_return_type(self) -> bool:
|
|
90
94
|
"""Has optional return type if there are multiple successful response types where some have
|
|
91
95
|
bodies and some are None
|
|
92
96
|
"""
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
self.
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
)
|
|
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
|
|
101
|
+
|
|
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
|
|
110
|
+
for response in self.responses
|
|
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"
|
|
110
121
|
|
|
111
122
|
@property
|
|
112
|
-
def
|
|
113
|
-
|
|
114
|
-
|
|
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)
|
|
115
166
|
|
|
116
167
|
@property
|
|
117
168
|
def has_response_body(self) -> bool:
|
|
118
|
-
"""Tell if at least one response has a body.
|
|
119
|
-
|
|
120
|
-
return any(response.has_body or response.is_stream_response for response in self.responses)
|
|
169
|
+
"""Tell if at least one response has a body."""
|
|
170
|
+
return any(response.type for response in self.responses)
|
|
121
171
|
|
|
122
172
|
@property
|
|
123
173
|
def any_response_has_headers(self) -> bool:
|
|
124
|
-
return any(response.
|
|
174
|
+
return any(response.headers for response in self.responses)
|
|
125
175
|
|
|
126
176
|
@property
|
|
127
|
-
def
|
|
128
|
-
|
|
129
|
-
|
|
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
|
|
180
|
+
]
|
|
181
|
+
if not default_exceptions:
|
|
130
182
|
return None
|
|
131
|
-
excep_schema =
|
|
132
|
-
if isinstance(excep_schema,
|
|
183
|
+
excep_schema = default_exceptions[0].type
|
|
184
|
+
if isinstance(excep_schema, ModelType):
|
|
133
185
|
return f"_models.{excep_schema.name}"
|
|
134
|
-
# in this case, it's just an
|
|
135
|
-
return "
|
|
186
|
+
# in this case, it's just an AnyType
|
|
187
|
+
return "'object'"
|
|
136
188
|
|
|
137
189
|
@property
|
|
138
|
-
def
|
|
139
|
-
return [
|
|
190
|
+
def non_default_errors(self) -> List[Response]:
|
|
191
|
+
return [e for e in self.exceptions if "default" not in e.status_codes]
|
|
140
192
|
|
|
141
193
|
@property
|
|
142
|
-
def
|
|
194
|
+
def non_default_error_status_codes(self) -> List[Union[str, int]]:
|
|
143
195
|
"""Actually returns all of the status codes from exceptions (besides default)"""
|
|
144
|
-
return list(
|
|
145
|
-
|
|
146
|
-
|
|
196
|
+
return list(
|
|
197
|
+
chain.from_iterable(
|
|
198
|
+
[error.status_codes for error in self.non_default_errors]
|
|
199
|
+
)
|
|
200
|
+
)
|
|
147
201
|
|
|
148
|
-
def _imports_shared(self, async_mode: bool) -> FileImport:
|
|
202
|
+
def _imports_shared(self, async_mode: bool, **kwargs: Any) -> FileImport:
|
|
149
203
|
file_import = FileImport()
|
|
150
|
-
file_import.add_submodule_import(
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
for response in self.responses:
|
|
158
|
-
file_import.merge(response.imports(self.code_model))
|
|
159
|
-
if response.has_body:
|
|
160
|
-
file_import.merge(cast(BaseSchema, response.schema).imports())
|
|
204
|
+
file_import.add_submodule_import(
|
|
205
|
+
"typing", "Any", ImportType.STDLIB, TypingSection.CONDITIONAL
|
|
206
|
+
)
|
|
207
|
+
if not self.abstract:
|
|
208
|
+
for param in self.parameters.method:
|
|
209
|
+
file_import.merge(param.imports(async_mode, **kwargs))
|
|
161
210
|
|
|
162
|
-
response_types = [
|
|
211
|
+
response_types = [
|
|
212
|
+
r.type_annotation(async_mode=async_mode) for r in self.responses if r.type
|
|
213
|
+
]
|
|
163
214
|
if len(set(response_types)) > 1:
|
|
164
|
-
file_import.add_submodule_import(
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
file_import.add_submodule_import("typing", "IO", ImportType.STDLIB, TypingSection.CONDITIONAL)
|
|
215
|
+
file_import.add_submodule_import(
|
|
216
|
+
"typing", "Union", ImportType.STDLIB, TypingSection.CONDITIONAL
|
|
217
|
+
)
|
|
168
218
|
return file_import
|
|
169
219
|
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
if self.
|
|
177
|
-
|
|
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
|
+
)
|
|
178
231
|
return file_import
|
|
179
232
|
|
|
180
233
|
@staticmethod
|
|
181
|
-
def has_kwargs_to_pop_with_default(
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
file_import.add_submodule_import("azure.core.pipeline", "PipelineResponse", ImportType.AZURECORE)
|
|
198
|
-
file_import.add_submodule_import("azure.core.rest", "HttpRequest", ImportType.AZURECORE)
|
|
199
|
-
kwargs_to_pop = self.parameters.kwargs_to_pop(is_python3_file)
|
|
200
|
-
if (self.has_kwargs_to_pop_with_default(kwargs_to_pop, ParameterLocation.Header) or
|
|
201
|
-
self.has_kwargs_to_pop_with_default(kwargs_to_pop, ParameterLocation.Query)):
|
|
202
|
-
file_import.add_submodule_import("azure.core.utils", "case_insensitive_dict", ImportType.AZURECORE)
|
|
203
|
-
if async_mode:
|
|
204
|
-
file_import.add_submodule_import("azure.core.pipeline.transport", "AsyncHttpResponse", ImportType.AZURECORE)
|
|
205
|
-
else:
|
|
206
|
-
file_import.add_submodule_import("azure.core.pipeline.transport", "HttpResponse", ImportType.AZURECORE)
|
|
207
|
-
|
|
208
|
-
if self.deprecated:
|
|
209
|
-
file_import.add_import("warnings", ImportType.STDLIB)
|
|
234
|
+
def has_kwargs_to_pop_with_default(
|
|
235
|
+
kwargs_to_pop: List[
|
|
236
|
+
Union[
|
|
237
|
+
Parameter,
|
|
238
|
+
RequestBuilderParameter,
|
|
239
|
+
BodyParameter,
|
|
240
|
+
MultipartBodyParameter,
|
|
241
|
+
]
|
|
242
|
+
],
|
|
243
|
+
location: ParameterLocation,
|
|
244
|
+
) -> bool:
|
|
245
|
+
return any(
|
|
246
|
+
(kwarg.client_default_value or kwarg.optional)
|
|
247
|
+
and kwarg.location == location
|
|
248
|
+
for kwarg in kwargs_to_pop
|
|
249
|
+
)
|
|
210
250
|
|
|
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()
|
|
211
258
|
if self.code_model.options["builders_visibility"] != "embedded":
|
|
212
|
-
|
|
259
|
+
group_name = request_builder.group_name
|
|
213
260
|
rest_import_path = "..." if async_mode else ".."
|
|
214
|
-
if
|
|
261
|
+
if group_name:
|
|
215
262
|
file_import.add_submodule_import(
|
|
216
263
|
f"{rest_import_path}{self.code_model.rest_layer_name}",
|
|
217
|
-
|
|
264
|
+
group_name,
|
|
218
265
|
import_type=ImportType.LOCAL,
|
|
219
|
-
alias=f"rest_{
|
|
266
|
+
alias=f"rest_{group_name}",
|
|
220
267
|
)
|
|
221
268
|
else:
|
|
222
269
|
file_import.add_submodule_import(
|
|
223
270
|
rest_import_path,
|
|
224
271
|
self.code_model.rest_layer_name,
|
|
225
272
|
import_type=ImportType.LOCAL,
|
|
226
|
-
alias="rest"
|
|
273
|
+
alias="rest",
|
|
227
274
|
)
|
|
228
|
-
if self.code_model.options["builders_visibility"] == "embedded" and
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
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
|
+
)
|
|
232
282
|
file_import.add_submodule_import(
|
|
233
|
-
f"{
|
|
283
|
+
f"...{self.code_model.operations_folder_name}.{self.filename}{suffix}",
|
|
284
|
+
request_builder.name,
|
|
285
|
+
import_type=ImportType.LOCAL,
|
|
234
286
|
)
|
|
287
|
+
return file_import
|
|
235
288
|
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
)
|
|
240
|
-
|
|
241
|
-
|
|
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))
|
|
302
|
+
|
|
303
|
+
# Exceptions
|
|
304
|
+
if self.abstract:
|
|
305
|
+
file_import.add_import("abc", ImportType.STDLIB)
|
|
306
|
+
else:
|
|
307
|
+
file_import.add_submodule_import(
|
|
308
|
+
"azure.core.exceptions", "map_error", ImportType.AZURECORE
|
|
309
|
+
)
|
|
310
|
+
if self.code_model.options["azure_arm"]:
|
|
311
|
+
file_import.add_submodule_import(
|
|
312
|
+
"azure.mgmt.core.exceptions", "ARMErrorFormat", ImportType.AZURECORE
|
|
313
|
+
)
|
|
242
314
|
file_import.add_submodule_import(
|
|
243
|
-
|
|
244
|
-
|
|
315
|
+
"azure.core.exceptions", "HttpResponseError", ImportType.AZURECORE
|
|
316
|
+
)
|
|
317
|
+
file_import.add_submodule_import(
|
|
318
|
+
"azure.core.exceptions",
|
|
319
|
+
"ClientAuthenticationError",
|
|
245
320
|
ImportType.AZURECORE,
|
|
246
321
|
)
|
|
247
|
-
|
|
322
|
+
file_import.add_submodule_import(
|
|
323
|
+
"azure.core.exceptions", "ResourceNotFoundError", ImportType.AZURECORE
|
|
324
|
+
)
|
|
325
|
+
file_import.add_submodule_import(
|
|
326
|
+
"azure.core.exceptions", "ResourceExistsError", ImportType.AZURECORE
|
|
327
|
+
)
|
|
328
|
+
|
|
329
|
+
kwargs_to_pop = self.parameters.kwargs_to_pop(is_python3_file)
|
|
330
|
+
if self.has_kwargs_to_pop_with_default(
|
|
331
|
+
kwargs_to_pop, ParameterLocation.HEADER
|
|
332
|
+
) or self.has_kwargs_to_pop_with_default(
|
|
333
|
+
kwargs_to_pop, ParameterLocation.QUERY
|
|
334
|
+
):
|
|
335
|
+
file_import.add_submodule_import(
|
|
336
|
+
"azure.core.utils", "case_insensitive_dict", ImportType.AZURECORE
|
|
337
|
+
)
|
|
338
|
+
if self.deprecated:
|
|
339
|
+
file_import.add_import("warnings", ImportType.STDLIB)
|
|
248
340
|
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
if body_kwarg.serialized_name == "data":
|
|
254
|
-
return next(p for p in self.multiple_content_type_parameters.body if p.is_data_input)
|
|
255
|
-
if body_kwarg.serialized_name == "files":
|
|
256
|
-
return next(p for p in self.multiple_content_type_parameters.body if p.is_multipart)
|
|
257
|
-
if body_kwarg.serialized_name == "json":
|
|
258
|
-
# first check if there's any non-binary. In the case of multiple content types, there's
|
|
259
|
-
# usually one binary (for content), and one schema parameter (for json)
|
|
260
|
-
try:
|
|
261
|
-
return next(
|
|
262
|
-
p for p in self.multiple_content_type_parameters.body
|
|
263
|
-
if not isinstance(p.schema, IOSchema)
|
|
341
|
+
if self.code_model.need_request_converter:
|
|
342
|
+
relative_path = "..." if async_mode else ".."
|
|
343
|
+
file_import.add_submodule_import(
|
|
344
|
+
f"{relative_path}_vendor", "_convert_request", ImportType.LOCAL
|
|
264
345
|
)
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
if not self.parameters.has_body:
|
|
271
|
-
return
|
|
272
|
-
body_kwargs = [
|
|
273
|
-
p for p in self.request_builder.parameters.body
|
|
274
|
-
if p.content_types
|
|
275
|
-
]
|
|
276
|
-
if len(body_kwargs) == 1:
|
|
277
|
-
self.parameters.body[0].body_kwargs = [body_kwargs[0]]
|
|
278
|
-
return
|
|
279
|
-
for body_kwarg in body_kwargs:
|
|
280
|
-
body_param = self._get_body_param_from_body_kwarg(body_kwarg)
|
|
281
|
-
body_param.body_kwargs.append(body_kwarg)
|
|
282
|
-
|
|
283
|
-
def convert_multiple_content_type_parameters(self) -> None:
|
|
284
|
-
type_annot = ", ".join([
|
|
285
|
-
param.schema.type_annotation(is_operation_file=True)
|
|
286
|
-
for param in self.multiple_content_type_parameters
|
|
287
|
-
])
|
|
288
|
-
docstring_type = " or ".join([
|
|
289
|
-
param.schema.docstring_type for param in self.multiple_content_type_parameters
|
|
290
|
-
])
|
|
291
|
-
try:
|
|
292
|
-
# get an optional param with object first. These params are the top choice
|
|
293
|
-
# bc they have more info about how to serialize the body
|
|
294
|
-
chosen_parameter = next(
|
|
295
|
-
p for p in self.multiple_content_type_parameters
|
|
296
|
-
if not p.required and isinstance(p.schema, ObjectSchema)
|
|
346
|
+
if async_mode:
|
|
347
|
+
file_import.add_submodule_import(
|
|
348
|
+
"azure.core.pipeline.transport",
|
|
349
|
+
"AsyncHttpResponse",
|
|
350
|
+
ImportType.AZURECORE,
|
|
297
351
|
)
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
chosen_parameter = (
|
|
302
|
-
optional_parameters[0] if optional_parameters else self.multiple_content_type_parameters[0]
|
|
352
|
+
else:
|
|
353
|
+
file_import.add_submodule_import(
|
|
354
|
+
"azure.core.pipeline.transport", "HttpResponse", ImportType.AZURECORE
|
|
303
355
|
)
|
|
304
|
-
if
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
schema_requests = [SchemaRequest.from_yaml(yaml, code_model=code_model) for yaml in yaml_data["requests"]]
|
|
318
|
-
parameters, multiple_content_type_parameters = create_parameters(
|
|
319
|
-
yaml_data, code_model, parameter_creator
|
|
356
|
+
if (
|
|
357
|
+
self.code_model.options["builders_visibility"] == "embedded"
|
|
358
|
+
and not async_mode
|
|
359
|
+
):
|
|
360
|
+
file_import.merge(self.request_builder.imports())
|
|
361
|
+
file_import.add_submodule_import(
|
|
362
|
+
"azure.core.pipeline", "PipelineResponse", ImportType.AZURECORE
|
|
363
|
+
)
|
|
364
|
+
file_import.add_submodule_import(
|
|
365
|
+
"azure.core.rest", "HttpRequest", ImportType.AZURECORE
|
|
366
|
+
)
|
|
367
|
+
file_import.add_submodule_import(
|
|
368
|
+
"typing", "Callable", ImportType.STDLIB, TypingSection.CONDITIONAL
|
|
320
369
|
)
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
code_model, multiple_content_type_parameters, schema_requests
|
|
370
|
+
file_import.add_submodule_import(
|
|
371
|
+
"typing", "Optional", ImportType.STDLIB, TypingSection.CONDITIONAL
|
|
324
372
|
)
|
|
373
|
+
file_import.add_submodule_import(
|
|
374
|
+
"typing", "Dict", ImportType.STDLIB, TypingSection.CONDITIONAL
|
|
375
|
+
)
|
|
376
|
+
file_import.add_submodule_import(
|
|
377
|
+
"typing", "TypeVar", ImportType.STDLIB, TypingSection.CONDITIONAL
|
|
378
|
+
)
|
|
379
|
+
if self.code_model.options["tracing"] and self.want_tracing and not async_mode:
|
|
380
|
+
file_import.add_submodule_import(
|
|
381
|
+
f"azure.core.tracing.decorator",
|
|
382
|
+
f"distributed_trace",
|
|
383
|
+
ImportType.AZURECORE,
|
|
384
|
+
)
|
|
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)
|
|
391
|
+
return file_import
|
|
325
392
|
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
393
|
+
def get_response_from_status(
|
|
394
|
+
self, status_code: Optional[Union[str, int]]
|
|
395
|
+
) -> ResponseType:
|
|
396
|
+
try:
|
|
397
|
+
return next(r for r in self.responses if status_code in r.status_codes)
|
|
398
|
+
except StopIteration:
|
|
399
|
+
raise ValueError(
|
|
400
|
+
f"Incorrect status code {status_code}, operation {self.name}"
|
|
401
|
+
)
|
|
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)
|
|
425
|
+
|
|
426
|
+
@classmethod
|
|
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", [])
|
|
441
|
+
]
|
|
442
|
+
abstract = False
|
|
443
|
+
if (
|
|
444
|
+
code_model.options["version_tolerant"]
|
|
445
|
+
and parameter_list.has_body
|
|
446
|
+
and isinstance(parameter_list.body_parameter, MultipartBodyParameter)
|
|
447
|
+
):
|
|
448
|
+
_LOGGER.warning(
|
|
449
|
+
'Not going to generate operation "%s" because it has multipart / urlencoded body parameters. '
|
|
450
|
+
"Multipart / urlencoded body parameters are not supported for version tolerant generation right now. "
|
|
451
|
+
'Please write your own custom operation in the "_patch.py" file '
|
|
452
|
+
"following https://aka.ms/azsdk/python/dpcodegen/python/customize",
|
|
453
|
+
name,
|
|
454
|
+
)
|
|
455
|
+
abstract = True
|
|
330
456
|
|
|
331
457
|
return cls(
|
|
332
|
-
code_model=code_model,
|
|
333
458
|
yaml_data=yaml_data,
|
|
459
|
+
code_model=code_model,
|
|
460
|
+
request_builder=request_builder,
|
|
334
461
|
name=name,
|
|
335
|
-
description=yaml_data["language"]["python"]["description"],
|
|
336
|
-
api_versions=set(value_dict["version"] for value_dict in yaml_data["apiVersions"]),
|
|
337
462
|
parameters=parameter_list,
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
for yaml in yaml_data.get("responses", [])
|
|
344
|
-
],
|
|
345
|
-
# Exception with no schema means default exception, we don't store them
|
|
346
|
-
exceptions=[
|
|
347
|
-
SchemaResponse.from_yaml(yaml, code_model=code_model)
|
|
348
|
-
for yaml in yaml_data.get("exceptions", []) if "schema" in yaml
|
|
349
|
-
],
|
|
463
|
+
overloads=overloads,
|
|
464
|
+
responses=responses,
|
|
465
|
+
exceptions=exceptions,
|
|
466
|
+
want_tracing=not yaml_data["isOverload"],
|
|
467
|
+
abstract=abstract,
|
|
350
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)
|