@autorest/python 5.16.0 → 5.19.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/ChangeLog.md +79 -4
- package/README.md +30 -4
- package/autorest/__init__.py +1 -1
- package/autorest/codegen/__init__.py +55 -211
- package/autorest/codegen/models/__init__.py +116 -83
- package/autorest/codegen/models/base_builder.py +49 -88
- package/autorest/codegen/models/base_model.py +1 -1
- package/autorest/codegen/models/{base_schema.py → base_type.py} +61 -39
- package/autorest/codegen/models/client.py +165 -53
- package/autorest/codegen/models/code_model.py +122 -257
- package/autorest/codegen/models/combined_type.py +107 -0
- package/autorest/codegen/models/{constant_schema.py → constant_type.py} +49 -40
- package/autorest/codegen/models/credential_types.py +224 -0
- package/autorest/codegen/models/dictionary_type.py +131 -0
- package/autorest/codegen/models/enum_type.py +195 -0
- package/autorest/codegen/models/imports.py +80 -2
- package/autorest/codegen/models/list_type.py +149 -0
- package/autorest/codegen/models/lro_operation.py +79 -156
- package/autorest/codegen/models/lro_paging_operation.py +28 -11
- package/autorest/codegen/models/model_type.py +262 -0
- package/autorest/codegen/models/operation.py +331 -298
- package/autorest/codegen/models/operation_group.py +54 -91
- package/autorest/codegen/models/paging_operation.py +82 -123
- package/autorest/codegen/models/parameter.py +289 -396
- package/autorest/codegen/models/parameter_list.py +355 -360
- package/autorest/codegen/models/primitive_types.py +544 -0
- package/autorest/codegen/models/property.py +123 -139
- package/autorest/codegen/models/request_builder.py +130 -102
- package/autorest/codegen/models/request_builder_parameter.py +112 -100
- package/autorest/codegen/models/response.py +325 -0
- package/autorest/codegen/models/utils.py +12 -19
- package/autorest/codegen/serializers/__init__.py +55 -37
- package/autorest/codegen/serializers/builder_serializer.py +695 -1144
- package/autorest/codegen/serializers/client_serializer.py +92 -89
- package/autorest/codegen/serializers/general_serializer.py +15 -69
- package/autorest/codegen/serializers/import_serializer.py +7 -4
- package/autorest/codegen/serializers/metadata_serializer.py +15 -104
- package/autorest/codegen/serializers/model_base_serializer.py +49 -36
- package/autorest/codegen/serializers/model_generic_serializer.py +8 -6
- package/autorest/codegen/serializers/model_init_serializer.py +2 -4
- package/autorest/codegen/serializers/model_python3_serializer.py +22 -16
- package/autorest/codegen/serializers/operation_groups_serializer.py +7 -13
- package/autorest/codegen/serializers/parameter_serializer.py +174 -0
- package/autorest/codegen/serializers/request_builders_serializer.py +13 -30
- package/autorest/codegen/serializers/utils.py +0 -140
- package/autorest/codegen/templates/MANIFEST.in.jinja2 +1 -0
- package/autorest/codegen/templates/{service_client.py.jinja2 → client.py.jinja2} +10 -7
- package/autorest/codegen/templates/config.py.jinja2 +13 -13
- package/autorest/codegen/templates/enum.py.jinja2 +4 -4
- package/autorest/codegen/templates/enum_container.py.jinja2 +1 -1
- package/autorest/codegen/templates/init.py.jinja2 +2 -2
- package/autorest/codegen/templates/lro_operation.py.jinja2 +4 -1
- package/autorest/codegen/templates/lro_paging_operation.py.jinja2 +4 -1
- package/autorest/codegen/templates/metadata.json.jinja2 +33 -33
- package/autorest/codegen/templates/model.py.jinja2 +23 -24
- package/autorest/codegen/templates/model_container.py.jinja2 +2 -1
- package/autorest/codegen/templates/model_init.py.jinja2 +3 -5
- package/autorest/codegen/templates/operation.py.jinja2 +6 -8
- package/autorest/codegen/templates/operation_group.py.jinja2 +21 -8
- package/autorest/codegen/templates/operation_groups_container.py.jinja2 +2 -2
- package/autorest/codegen/templates/operation_tools.jinja2 +11 -3
- package/autorest/codegen/templates/paging_operation.py.jinja2 +2 -2
- package/autorest/codegen/templates/request_builder.py.jinja2 +10 -15
- package/autorest/codegen/templates/request_builders.py.jinja2 +1 -1
- package/autorest/codegen/templates/serialization.py.jinja2 +2006 -0
- package/autorest/codegen/templates/setup.py.jinja2 +13 -3
- package/autorest/codegen/templates/vendor.py.jinja2 +11 -1
- package/autorest/jsonrpc/server.py +15 -3
- package/autorest/m4reformatter/__init__.py +1126 -0
- package/autorest/multiapi/models/client.py +12 -2
- package/autorest/multiapi/models/code_model.py +1 -1
- package/autorest/multiapi/serializers/__init__.py +18 -4
- package/autorest/multiapi/templates/multiapi_config.py.jinja2 +3 -3
- package/autorest/multiapi/templates/multiapi_init.py.jinja2 +2 -2
- package/autorest/multiapi/templates/multiapi_operations_mixin.py.jinja2 +4 -4
- package/autorest/multiapi/templates/multiapi_service_client.py.jinja2 +9 -9
- package/autorest/postprocess/__init__.py +202 -0
- package/autorest/postprocess/get_all.py +19 -0
- package/autorest/postprocess/venvtools.py +73 -0
- package/autorest/preprocess/__init__.py +210 -0
- package/autorest/preprocess/helpers.py +54 -0
- package/autorest/{namer → preprocess}/python_mappings.py +21 -16
- package/package.json +2 -2
- package/autorest/codegen/models/credential_model.py +0 -55
- package/autorest/codegen/models/credential_schema.py +0 -95
- package/autorest/codegen/models/credential_schema_policy.py +0 -73
- package/autorest/codegen/models/dictionary_schema.py +0 -106
- package/autorest/codegen/models/enum_schema.py +0 -225
- package/autorest/codegen/models/list_schema.py +0 -135
- package/autorest/codegen/models/object_schema.py +0 -303
- package/autorest/codegen/models/primitive_schemas.py +0 -495
- package/autorest/codegen/models/request_builder_parameter_list.py +0 -249
- package/autorest/codegen/models/schema_request.py +0 -55
- package/autorest/codegen/models/schema_response.py +0 -141
- package/autorest/namer/__init__.py +0 -23
- package/autorest/namer/name_converter.py +0 -509
|
@@ -3,168 +3,85 @@
|
|
|
3
3
|
# Licensed under the MIT License. See License.txt in the project root for
|
|
4
4
|
# license information.
|
|
5
5
|
# --------------------------------------------------------------------------
|
|
6
|
-
import
|
|
7
|
-
from enum import Enum
|
|
8
|
-
|
|
9
|
-
from typing import
|
|
10
|
-
|
|
11
|
-
|
|
6
|
+
import abc
|
|
7
|
+
from enum import Enum, auto
|
|
8
|
+
|
|
9
|
+
from typing import (
|
|
10
|
+
Dict,
|
|
11
|
+
Any,
|
|
12
|
+
TYPE_CHECKING,
|
|
13
|
+
List,
|
|
14
|
+
Optional,
|
|
15
|
+
TypeVar,
|
|
16
|
+
Union,
|
|
17
|
+
Generic,
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
from .imports import FileImport, ImportType
|
|
12
21
|
from .base_model import BaseModel
|
|
13
|
-
from .
|
|
14
|
-
from .
|
|
15
|
-
from .
|
|
16
|
-
from .property import Property
|
|
17
|
-
from .primitive_schemas import IOSchema
|
|
18
|
-
from .utils import get_schema
|
|
22
|
+
from .base_type import BaseType
|
|
23
|
+
from .constant_type import ConstantType
|
|
24
|
+
from .utils import add_to_description
|
|
19
25
|
|
|
20
26
|
if TYPE_CHECKING:
|
|
21
27
|
from .code_model import CodeModel
|
|
28
|
+
from .request_builder_parameter import RequestBuilderBodyParameter
|
|
22
29
|
|
|
23
30
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
31
|
+
class ParameterLocation(str, Enum):
|
|
32
|
+
HEADER = "header"
|
|
33
|
+
PATH = "path"
|
|
34
|
+
ENDPOINT_PATH = "endpointPath"
|
|
35
|
+
QUERY = "query"
|
|
36
|
+
BODY = "body"
|
|
37
|
+
OTHER = "other"
|
|
28
38
|
|
|
29
|
-
class ParameterMethodLocation(str, Enum):
|
|
30
|
-
POSITIONAL = "positional"
|
|
31
|
-
KEYWORD_ONLY = "keyword_only"
|
|
32
|
-
KWARG = "kwarg"
|
|
33
|
-
HIDDEN_KWARG = "hidden_kwarg"
|
|
34
39
|
|
|
40
|
+
class ParameterMethodLocation(Enum):
|
|
41
|
+
POSITIONAL = auto()
|
|
42
|
+
KEYWORD_ONLY = auto()
|
|
43
|
+
KWARG = auto()
|
|
35
44
|
|
|
36
|
-
class ParameterLocation(Enum):
|
|
37
|
-
Path = "path"
|
|
38
|
-
Body = "body"
|
|
39
|
-
Query = "query"
|
|
40
|
-
Header = "header"
|
|
41
|
-
Uri = "uri"
|
|
42
|
-
Other = "other"
|
|
43
45
|
|
|
46
|
+
class ParameterDelimeter(str, Enum):
|
|
47
|
+
SPACE = "space"
|
|
48
|
+
PIPE = "pipe"
|
|
49
|
+
TAB = "tab"
|
|
50
|
+
COMMA = "comma"
|
|
44
51
|
|
|
45
|
-
class ParameterStyle(Enum):
|
|
46
|
-
simple = "simple"
|
|
47
|
-
label = "label"
|
|
48
|
-
matrix = "matrix"
|
|
49
|
-
form = "form"
|
|
50
|
-
spaceDelimited = "spaceDelimited"
|
|
51
|
-
pipeDelimited = "pipeDelimited"
|
|
52
|
-
deepObject = "deepObject"
|
|
53
|
-
tabDelimited = "tabDelimited"
|
|
54
|
-
json = "json"
|
|
55
|
-
binary = "binary"
|
|
56
|
-
xml = "xml"
|
|
57
|
-
multipart = "multipart"
|
|
58
52
|
|
|
53
|
+
class _ParameterBase(
|
|
54
|
+
BaseModel, abc.ABC
|
|
55
|
+
): # pylint: disable=too-many-instance-attributes
|
|
56
|
+
"""Base class for all parameters"""
|
|
59
57
|
|
|
60
|
-
def get_target_property_name(code_model: "CodeModel", target_property_id: int) -> str:
|
|
61
|
-
for obj in code_model.schemas.values():
|
|
62
|
-
for prop in obj.properties:
|
|
63
|
-
if prop.id == target_property_id:
|
|
64
|
-
return prop.name
|
|
65
|
-
raise KeyError("Didn't find the target property")
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
class Parameter(
|
|
69
|
-
BaseModel
|
|
70
|
-
): # pylint: disable=too-many-instance-attributes, too-many-public-methods
|
|
71
58
|
def __init__(
|
|
72
59
|
self,
|
|
73
60
|
yaml_data: Dict[str, Any],
|
|
74
61
|
code_model: "CodeModel",
|
|
75
|
-
|
|
76
|
-
rest_api_name: str,
|
|
77
|
-
serialized_name: str,
|
|
78
|
-
description: str,
|
|
79
|
-
implementation: str,
|
|
80
|
-
required: bool,
|
|
81
|
-
location: ParameterLocation,
|
|
82
|
-
skip_url_encoding: bool,
|
|
83
|
-
constraints: List[Any],
|
|
84
|
-
target_property_name: Optional[
|
|
85
|
-
Union[int, str]
|
|
86
|
-
] = None, # first uses id as placeholder
|
|
87
|
-
style: Optional[ParameterStyle] = None,
|
|
88
|
-
explode: Optional[bool] = False,
|
|
89
|
-
*,
|
|
90
|
-
flattened: bool = False,
|
|
91
|
-
grouped_by: Optional["Parameter"] = None,
|
|
92
|
-
original_parameter: Optional["Parameter"] = None,
|
|
93
|
-
client_default_value: Optional[Any] = None,
|
|
94
|
-
content_types: Optional[List[str]] = None,
|
|
62
|
+
type: BaseType,
|
|
95
63
|
) -> None:
|
|
96
64
|
super().__init__(yaml_data, code_model)
|
|
97
|
-
self.
|
|
98
|
-
self.
|
|
99
|
-
self.
|
|
100
|
-
self.
|
|
101
|
-
self.
|
|
102
|
-
self.
|
|
103
|
-
self.
|
|
104
|
-
self.
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
self.
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
self.
|
|
111
|
-
|
|
112
|
-
self.original_parameter = original_parameter
|
|
113
|
-
self.client_default_value = client_default_value
|
|
114
|
-
self.has_multiple_content_types: bool = False
|
|
115
|
-
self.multiple_content_types_type_annot: Optional[str] = None
|
|
116
|
-
self.multiple_content_types_docstring_type: Optional[str] = None
|
|
117
|
-
self.is_multipart = (
|
|
118
|
-
yaml_data.get("language", {}).get("python", {}).get("multipart", False)
|
|
65
|
+
self.rest_api_name: str = yaml_data["restApiName"]
|
|
66
|
+
self.client_name: str = self.yaml_data["clientName"]
|
|
67
|
+
self.optional: bool = self.yaml_data["optional"]
|
|
68
|
+
self.location: ParameterLocation = self.yaml_data["location"]
|
|
69
|
+
self.client_default_value = self.yaml_data.get("clientDefaultValue", None)
|
|
70
|
+
self.in_docstring = self.yaml_data.get("inDocstring", True)
|
|
71
|
+
self.type = type
|
|
72
|
+
if self.client_default_value is None:
|
|
73
|
+
self.client_default_value = self.type.client_default_value
|
|
74
|
+
# name of grouper if it is grouped by another parameter
|
|
75
|
+
self.grouped_by: Optional[str] = self.yaml_data.get("groupedBy")
|
|
76
|
+
# property matching property name to parameter name for grouping params
|
|
77
|
+
# and flattened body params
|
|
78
|
+
self.property_to_parameter_name: Optional[Dict[str, str]] = self.yaml_data.get(
|
|
79
|
+
"propertyToParameterName"
|
|
119
80
|
)
|
|
120
|
-
self.
|
|
121
|
-
|
|
122
|
-
)
|
|
123
|
-
self.
|
|
124
|
-
self.body_kwargs: List[Parameter] = []
|
|
125
|
-
self.is_body_kwarg = False
|
|
126
|
-
self.need_import = True
|
|
127
|
-
self._method_location: Optional[ParameterMethodLocation] = None
|
|
128
|
-
|
|
129
|
-
def __hash__(self) -> int:
|
|
130
|
-
return hash(self.serialized_name)
|
|
131
|
-
|
|
132
|
-
@property
|
|
133
|
-
def description(self):
|
|
134
|
-
try:
|
|
135
|
-
description = self._description
|
|
136
|
-
if self.schema.extra_description_information:
|
|
137
|
-
if description:
|
|
138
|
-
description += " "
|
|
139
|
-
description += f"{self.schema.extra_description_information}"
|
|
140
|
-
if isinstance(self.schema, ConstantSchema) and not self.constant:
|
|
141
|
-
if description:
|
|
142
|
-
description += " "
|
|
143
|
-
description += f"Known values are {self.schema.get_declaration(self.schema.value)} or {None}."
|
|
144
|
-
if self.has_default_value and not any(
|
|
145
|
-
l
|
|
146
|
-
for l in ["default value is", "default is"]
|
|
147
|
-
if l in description.lower()
|
|
148
|
-
):
|
|
149
|
-
description += f" Default value is {self.default_value_declaration}."
|
|
150
|
-
if self.constant:
|
|
151
|
-
description += " Note that overriding this default value may result in unsupported behavior."
|
|
152
|
-
return description
|
|
153
|
-
except AttributeError:
|
|
154
|
-
pass
|
|
155
|
-
return self._description
|
|
156
|
-
|
|
157
|
-
@description.setter
|
|
158
|
-
def description(self, val: str):
|
|
159
|
-
self._description = val
|
|
160
|
-
|
|
161
|
-
@property
|
|
162
|
-
def is_json_parameter(self) -> bool:
|
|
163
|
-
if self.is_multipart or self.is_data_input:
|
|
164
|
-
return False
|
|
165
|
-
if self.style == ParameterStyle.xml:
|
|
166
|
-
return False
|
|
167
|
-
return True
|
|
81
|
+
self.flattened: bool = self.yaml_data.get("flattened", False)
|
|
82
|
+
self.in_flattened_body: bool = self.yaml_data.get("inFlattenedBody", False)
|
|
83
|
+
self.grouper: bool = self.yaml_data.get("grouper", False)
|
|
84
|
+
self.check_client_input: bool = self.yaml_data.get("checkClientInput", False)
|
|
168
85
|
|
|
169
86
|
@property
|
|
170
87
|
def constant(self) -> bool:
|
|
@@ -172,325 +89,301 @@ class Parameter(
|
|
|
172
89
|
Checking to see if it's required, because if not, we don't consider it
|
|
173
90
|
a constant because it can have a value of None.
|
|
174
91
|
"""
|
|
175
|
-
|
|
176
|
-
if not self.schema.get("type") == "constant":
|
|
177
|
-
return False
|
|
178
|
-
else:
|
|
179
|
-
if not isinstance(self.schema, ConstantSchema):
|
|
180
|
-
return False
|
|
181
|
-
return self.required
|
|
92
|
+
return not self.optional and isinstance(self.type, ConstantType)
|
|
182
93
|
|
|
183
94
|
@property
|
|
184
|
-
def
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
95
|
+
def description(self) -> str:
|
|
96
|
+
base_description = self.yaml_data["description"]
|
|
97
|
+
type_description = self.type.description(is_operation_file=True)
|
|
98
|
+
if type_description:
|
|
99
|
+
base_description = add_to_description(base_description, type_description)
|
|
100
|
+
if self.optional and isinstance(self.type, ConstantType):
|
|
101
|
+
base_description = add_to_description(
|
|
102
|
+
base_description,
|
|
103
|
+
f"Known values are {self.type.get_declaration()} and None.",
|
|
104
|
+
)
|
|
105
|
+
if not (self.optional or self.client_default_value):
|
|
106
|
+
base_description = add_to_description(base_description, "Required.")
|
|
107
|
+
if self.client_default_value is not None:
|
|
108
|
+
base_description = add_to_description(
|
|
109
|
+
base_description,
|
|
110
|
+
f"Default value is {self.client_default_value_declaration}.",
|
|
111
|
+
)
|
|
112
|
+
if self.optional and self.client_default_value is None:
|
|
113
|
+
base_description = add_to_description(
|
|
114
|
+
base_description,
|
|
115
|
+
f"Default value is {self.client_default_value_declaration}.",
|
|
190
116
|
)
|
|
191
|
-
|
|
117
|
+
if self.constant:
|
|
118
|
+
base_description = add_to_description(
|
|
119
|
+
base_description,
|
|
120
|
+
"Note that overriding this default value may result in unsupported behavior.",
|
|
121
|
+
)
|
|
122
|
+
return base_description
|
|
192
123
|
|
|
193
124
|
@property
|
|
194
|
-
def
|
|
195
|
-
|
|
125
|
+
def client_default_value_declaration(self):
|
|
126
|
+
"""Declaration of parameter's client default value"""
|
|
127
|
+
if self.client_default_value is None:
|
|
128
|
+
return None
|
|
129
|
+
return self.type.get_declaration(self.client_default_value)
|
|
196
130
|
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
131
|
+
def type_annotation(self, **kwargs: Any) -> str:
|
|
132
|
+
kwargs["is_operation_file"] = True
|
|
133
|
+
type_annot = self.type.type_annotation(**kwargs)
|
|
134
|
+
if self.optional and self.client_default_value is None:
|
|
135
|
+
return f"Optional[{type_annot}]"
|
|
136
|
+
return type_annot
|
|
200
137
|
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
return self.location == ParameterLocation.Body
|
|
138
|
+
def docstring_text(self, **kwargs: Any) -> str:
|
|
139
|
+
return self.type.docstring_text(**kwargs)
|
|
204
140
|
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
return self.rest_api_name != "Accept"
|
|
141
|
+
def docstring_type(self, **kwargs: Any) -> str:
|
|
142
|
+
return self.type.docstring_type(**kwargs)
|
|
208
143
|
|
|
209
144
|
@property
|
|
210
|
-
def
|
|
211
|
-
|
|
212
|
-
I.e. ["text/plain; charset=UTF-8"] -> ["text/plain"]
|
|
213
|
-
"""
|
|
214
|
-
return [content_type.split(";")[0] for content_type in self.content_types]
|
|
145
|
+
def serialization_type(self) -> str:
|
|
146
|
+
return self.type.serialization_type
|
|
215
147
|
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
not self.inputtable_by_user
|
|
221
|
-
# If i'm not in the method code, no point in being in signature
|
|
222
|
-
or not self.in_method_code
|
|
223
|
-
# If I'm grouped, my grouper will be on signature, not me
|
|
224
|
-
or self.grouped_by
|
|
225
|
-
# If I'm body and it's flattened, I'm not either
|
|
226
|
-
or (self.is_body and self.flattened)
|
|
148
|
+
def imports(self, async_mode: bool, **kwargs: Any) -> FileImport:
|
|
149
|
+
file_import = FileImport()
|
|
150
|
+
file_import.merge(
|
|
151
|
+
self.type.imports(is_operation_file=True, async_mode=async_mode, **kwargs)
|
|
227
152
|
)
|
|
153
|
+
if self.optional and self.client_default_value is None:
|
|
154
|
+
file_import.add_submodule_import("typing", "Optional", ImportType.STDLIB)
|
|
155
|
+
return file_import
|
|
228
156
|
|
|
229
157
|
@property
|
|
230
|
-
def
|
|
231
|
-
|
|
232
|
-
raise ValueError("Should only be calling if your parameter is grouped")
|
|
233
|
-
try:
|
|
234
|
-
return next(
|
|
235
|
-
p
|
|
236
|
-
for p in cast(ObjectSchema, self.grouped_by.schema).properties
|
|
237
|
-
if any(
|
|
238
|
-
op for op in p.yaml_data["originalParameter"] if id(op) == self.id
|
|
239
|
-
)
|
|
240
|
-
)
|
|
241
|
-
except StopIteration:
|
|
242
|
-
raise ValueError(
|
|
243
|
-
"There is not a corresponding grouped property for your parameter."
|
|
244
|
-
)
|
|
158
|
+
def method_location(self) -> ParameterMethodLocation:
|
|
159
|
+
raise NotImplementedError("Please implement in children")
|
|
245
160
|
|
|
246
161
|
@property
|
|
247
|
-
def
|
|
248
|
-
return
|
|
162
|
+
def description_keyword(self) -> str:
|
|
163
|
+
return (
|
|
164
|
+
"param"
|
|
165
|
+
if self.method_location == ParameterMethodLocation.POSITIONAL
|
|
166
|
+
else "keyword"
|
|
167
|
+
)
|
|
249
168
|
|
|
250
169
|
@property
|
|
251
|
-
def
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
170
|
+
def docstring_type_keyword(self) -> str:
|
|
171
|
+
return (
|
|
172
|
+
"type"
|
|
173
|
+
if self.method_location == ParameterMethodLocation.POSITIONAL
|
|
174
|
+
else "paramtype"
|
|
175
|
+
)
|
|
256
176
|
|
|
257
177
|
@property
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
) and isinstance(self.schema, IOSchema)
|
|
262
|
-
|
|
263
|
-
def _default_value(self) -> Tuple[Optional[Any], str, str]:
|
|
264
|
-
type_annot = (
|
|
265
|
-
self.multiple_content_types_type_annot
|
|
266
|
-
or self.schema.type_annotation(is_operation_file=True)
|
|
267
|
-
)
|
|
268
|
-
if self._is_io_json:
|
|
269
|
-
type_annot = f"Union[{type_annot}, Any]"
|
|
270
|
-
if not self.required and type_annot != "Any" and not self._is_io_json:
|
|
271
|
-
type_annot = f"Optional[{type_annot}]"
|
|
178
|
+
@abc.abstractmethod
|
|
179
|
+
def in_method_signature(self) -> bool:
|
|
180
|
+
...
|
|
272
181
|
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
type_annot,
|
|
278
|
-
|
|
182
|
+
def method_signature(self, is_python3_file: bool, async_mode: bool) -> str:
|
|
183
|
+
type_annot = self.type_annotation(async_mode=async_mode)
|
|
184
|
+
if is_python3_file:
|
|
185
|
+
if self.client_default_value is not None or self.optional:
|
|
186
|
+
return f"{self.client_name}: {type_annot} = {self.client_default_value_declaration},"
|
|
187
|
+
return f"{self.client_name}: {type_annot},"
|
|
188
|
+
if self.client_default_value is not None or self.optional:
|
|
189
|
+
return f"{self.client_name}={self.client_default_value_declaration}, # type: {type_annot}"
|
|
190
|
+
return f"{self.client_name}, # type: {type_annot}"
|
|
279
191
|
|
|
280
|
-
if self.multiple_content_types_type_annot:
|
|
281
|
-
# means this parameter has multiple media types. We force default value to be None.
|
|
282
|
-
default_value = None
|
|
283
|
-
default_value_declaration = "None"
|
|
284
|
-
else:
|
|
285
|
-
if isinstance(self.schema, ConstantSchema):
|
|
286
|
-
if (
|
|
287
|
-
self.required
|
|
288
|
-
or self.is_content_type
|
|
289
|
-
or not self.code_model.options["default_optional_constants_to_none"]
|
|
290
|
-
):
|
|
291
|
-
default_value = self.schema.get_declaration(self.schema.value)
|
|
292
|
-
else:
|
|
293
|
-
default_value = None
|
|
294
|
-
default_value_declaration = default_value
|
|
295
|
-
else:
|
|
296
|
-
default_value = self.schema.default_value
|
|
297
|
-
default_value_declaration = self.schema.default_value_declaration
|
|
298
|
-
if default_value is not None and self.required:
|
|
299
|
-
_LOGGER.warning(
|
|
300
|
-
"Parameter '%s' is required and has a default value, this combination is not recommended",
|
|
301
|
-
self.rest_api_name,
|
|
302
|
-
)
|
|
303
192
|
|
|
304
|
-
|
|
193
|
+
class _BodyParameterBase(_ParameterBase):
|
|
194
|
+
"""Base class for body parameters"""
|
|
305
195
|
|
|
306
196
|
@property
|
|
307
|
-
def
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
if self.method_location
|
|
311
|
-
in (
|
|
312
|
-
ParameterMethodLocation.KWARG,
|
|
313
|
-
ParameterMethodLocation.HIDDEN_KWARG,
|
|
314
|
-
ParameterMethodLocation.KEYWORD_ONLY,
|
|
315
|
-
)
|
|
316
|
-
else "param"
|
|
317
|
-
)
|
|
197
|
+
def is_partial_body(self) -> bool:
|
|
198
|
+
"""Whether it's part of a bigger body parameter, i.e. a MultipartBodyParameter"""
|
|
199
|
+
return self.yaml_data.get("isPartialBody", False)
|
|
318
200
|
|
|
319
201
|
@property
|
|
320
|
-
def
|
|
202
|
+
def method_location(self) -> ParameterMethodLocation:
|
|
321
203
|
return (
|
|
322
|
-
|
|
323
|
-
if self.
|
|
324
|
-
|
|
325
|
-
ParameterMethodLocation.KWARG,
|
|
326
|
-
ParameterMethodLocation.HIDDEN_KWARG,
|
|
327
|
-
ParameterMethodLocation.KEYWORD_ONLY,
|
|
328
|
-
)
|
|
329
|
-
else "type"
|
|
204
|
+
ParameterMethodLocation.KWARG
|
|
205
|
+
if self.constant
|
|
206
|
+
else ParameterMethodLocation.POSITIONAL
|
|
330
207
|
)
|
|
331
208
|
|
|
332
209
|
@property
|
|
333
|
-
def
|
|
334
|
-
|
|
335
|
-
# default values we bubble up from the schema
|
|
336
|
-
return self._default_value()[0]
|
|
210
|
+
def in_method_signature(self) -> bool:
|
|
211
|
+
return not (self.flattened or self.grouped_by)
|
|
337
212
|
|
|
338
|
-
@property
|
|
339
|
-
def default_value_declaration(self) -> Optional[Any]:
|
|
340
|
-
return self._default_value()[1]
|
|
341
213
|
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
) -> str:
|
|
345
|
-
return self._default_value()[2]
|
|
214
|
+
class BodyParameter(_BodyParameterBase):
|
|
215
|
+
"""Body parameter."""
|
|
346
216
|
|
|
347
217
|
@property
|
|
348
|
-
def
|
|
349
|
-
return self.
|
|
218
|
+
def content_types(self) -> List[str]:
|
|
219
|
+
return self.yaml_data["contentTypes"]
|
|
350
220
|
|
|
351
221
|
@property
|
|
352
|
-
def
|
|
353
|
-
|
|
354
|
-
|
|
222
|
+
def default_content_type(self) -> str:
|
|
223
|
+
return self.yaml_data["defaultContentType"]
|
|
224
|
+
|
|
225
|
+
@classmethod
|
|
226
|
+
def from_yaml(
|
|
227
|
+
cls, yaml_data: Dict[str, Any], code_model: "CodeModel"
|
|
228
|
+
) -> "BodyParameter":
|
|
229
|
+
return cls(
|
|
230
|
+
yaml_data=yaml_data,
|
|
231
|
+
code_model=code_model,
|
|
232
|
+
type=code_model.lookup_type(id(yaml_data["type"])),
|
|
355
233
|
)
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
234
|
+
|
|
235
|
+
|
|
236
|
+
EntryBodyParameterType = TypeVar(
|
|
237
|
+
"EntryBodyParameterType", bound=Union[BodyParameter, "RequestBuilderBodyParameter"]
|
|
238
|
+
)
|
|
239
|
+
|
|
240
|
+
|
|
241
|
+
class _MultipartBodyParameter(Generic[EntryBodyParameterType], BodyParameter):
|
|
242
|
+
"""Base class for MultipartBodyParameter and RequestBuilderMultipartBodyParameter"""
|
|
243
|
+
|
|
244
|
+
def __init__(
|
|
245
|
+
self,
|
|
246
|
+
yaml_data: Dict[str, Any],
|
|
247
|
+
code_model: "CodeModel",
|
|
248
|
+
type: BaseType,
|
|
249
|
+
entries: List[EntryBodyParameterType],
|
|
250
|
+
) -> None:
|
|
251
|
+
super().__init__(yaml_data, code_model, type)
|
|
252
|
+
self.entries = entries
|
|
359
253
|
|
|
360
254
|
@property
|
|
361
|
-
def
|
|
362
|
-
|
|
255
|
+
def in_method_signature(self) -> bool:
|
|
256
|
+
# Right now, only legacy generates with multipart bodies
|
|
257
|
+
# and legacy generates with the multipart body arguments splatted out
|
|
258
|
+
return False
|
|
363
259
|
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
260
|
+
|
|
261
|
+
class MultipartBodyParameter(
|
|
262
|
+
_MultipartBodyParameter[BodyParameter] # pylint: disable=unsubscriptable-object
|
|
263
|
+
):
|
|
264
|
+
"""Multipart body parameter for Operation. Used for files and data input."""
|
|
265
|
+
|
|
266
|
+
@classmethod
|
|
267
|
+
def from_yaml(
|
|
268
|
+
cls, yaml_data: Dict[str, Any], code_model: "CodeModel"
|
|
269
|
+
) -> "MultipartBodyParameter":
|
|
270
|
+
return cls(
|
|
271
|
+
yaml_data=yaml_data,
|
|
272
|
+
code_model=code_model,
|
|
273
|
+
type=code_model.lookup_type(id(yaml_data["type"])),
|
|
274
|
+
entries=[
|
|
275
|
+
BodyParameter.from_yaml(entry, code_model)
|
|
276
|
+
for entry in yaml_data["entries"]
|
|
277
|
+
],
|
|
278
|
+
)
|
|
279
|
+
|
|
280
|
+
|
|
281
|
+
class Parameter(_ParameterBase):
|
|
282
|
+
"""Basic Parameter class"""
|
|
283
|
+
|
|
284
|
+
def __init__(
|
|
285
|
+
self,
|
|
286
|
+
yaml_data: Dict[str, Any],
|
|
287
|
+
code_model: "CodeModel",
|
|
288
|
+
type: BaseType,
|
|
289
|
+
) -> None:
|
|
290
|
+
super().__init__(yaml_data, code_model, type=type)
|
|
291
|
+
|
|
292
|
+
self.implementation: str = yaml_data["implementation"]
|
|
293
|
+
self.skip_url_encoding: bool = self.yaml_data.get("skipUrlEncoding", False)
|
|
294
|
+
self.explode: bool = self.yaml_data.get("explode", False)
|
|
295
|
+
self.in_overload: bool = self.yaml_data["inOverload"]
|
|
296
|
+
self.in_overriden: bool = self.yaml_data.get("inOverriden", False)
|
|
297
|
+
self.delimiter: Optional[ParameterDelimeter] = self.yaml_data.get("delimiter")
|
|
373
298
|
|
|
374
299
|
@property
|
|
375
|
-
def
|
|
376
|
-
|
|
300
|
+
def in_method_signature(self) -> bool:
|
|
301
|
+
return not (self.rest_api_name == "Accept" or self.grouped_by or self.flattened)
|
|
302
|
+
|
|
303
|
+
@property
|
|
304
|
+
def full_client_name(self) -> str:
|
|
377
305
|
if self.implementation == "Client":
|
|
378
|
-
|
|
379
|
-
return
|
|
306
|
+
return f"self._config.{self.client_name}"
|
|
307
|
+
return self.client_name
|
|
380
308
|
|
|
381
309
|
@property
|
|
382
|
-
def
|
|
383
|
-
return
|
|
384
|
-
self.rest_api_name == "Content-Type"
|
|
385
|
-
and self.location == ParameterLocation.Header
|
|
386
|
-
)
|
|
310
|
+
def xml_serialization_ctxt(self) -> str:
|
|
311
|
+
return self.type.xml_serialization_ctxt or ""
|
|
387
312
|
|
|
388
313
|
@property
|
|
389
314
|
def method_location(self) -> ParameterMethodLocation:
|
|
390
|
-
if self.
|
|
391
|
-
|
|
392
|
-
if self.
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
return ParameterMethodLocation.
|
|
396
|
-
if self.
|
|
315
|
+
if not self.in_method_signature:
|
|
316
|
+
raise ValueError(f"Parameter '{self.client_name}' is not in the method.")
|
|
317
|
+
if self.grouper:
|
|
318
|
+
return ParameterMethodLocation.POSITIONAL
|
|
319
|
+
if self.constant:
|
|
320
|
+
return ParameterMethodLocation.KWARG
|
|
321
|
+
if self.rest_api_name == "Content-Type":
|
|
322
|
+
if self.in_overload:
|
|
323
|
+
return ParameterMethodLocation.KEYWORD_ONLY
|
|
397
324
|
return ParameterMethodLocation.KWARG
|
|
325
|
+
query_or_header = self.location in (
|
|
326
|
+
ParameterLocation.HEADER,
|
|
327
|
+
ParameterLocation.QUERY,
|
|
328
|
+
)
|
|
329
|
+
if (
|
|
330
|
+
self.code_model.options["only_path_and_body_params_positional"]
|
|
331
|
+
and query_or_header
|
|
332
|
+
):
|
|
333
|
+
return ParameterMethodLocation.KEYWORD_ONLY
|
|
398
334
|
return ParameterMethodLocation.POSITIONAL
|
|
399
335
|
|
|
400
|
-
@method_location.setter
|
|
401
|
-
def method_location(self, val: ParameterMethodLocation) -> None:
|
|
402
|
-
self._method_location = val
|
|
403
|
-
|
|
404
336
|
@classmethod
|
|
405
|
-
def from_yaml(
|
|
406
|
-
cls,
|
|
407
|
-
yaml_data: Dict[str, Any],
|
|
408
|
-
code_model: "CodeModel",
|
|
409
|
-
*,
|
|
410
|
-
content_types: Optional[List[str]] = None,
|
|
411
|
-
) -> "Parameter":
|
|
412
|
-
http_protocol = yaml_data["protocol"].get(
|
|
413
|
-
"http", {"in": ParameterLocation.Other}
|
|
414
|
-
)
|
|
415
|
-
serialized_name = yaml_data["language"]["python"]["name"]
|
|
416
|
-
schema = get_schema(code_model, yaml_data.get("schema"), serialized_name)
|
|
417
|
-
target_property = yaml_data.get("targetProperty")
|
|
418
|
-
target_property_name = (
|
|
419
|
-
get_target_property_name(code_model, id(target_property))
|
|
420
|
-
if target_property
|
|
421
|
-
else None
|
|
422
|
-
)
|
|
423
|
-
|
|
337
|
+
def from_yaml(cls, yaml_data: Dict[str, Any], code_model: "CodeModel"):
|
|
424
338
|
return cls(
|
|
425
339
|
yaml_data=yaml_data,
|
|
426
340
|
code_model=code_model,
|
|
427
|
-
|
|
428
|
-
# See also https://github.com/Azure/autorest.modelerfour/issues/80
|
|
429
|
-
rest_api_name=yaml_data["language"]["default"].get(
|
|
430
|
-
"serializedName", yaml_data["language"]["default"]["name"]
|
|
431
|
-
),
|
|
432
|
-
serialized_name=serialized_name,
|
|
433
|
-
description=yaml_data["language"]["python"]["description"],
|
|
434
|
-
implementation=yaml_data["implementation"],
|
|
435
|
-
required=yaml_data.get("required", False),
|
|
436
|
-
location=ParameterLocation(http_protocol["in"]),
|
|
437
|
-
skip_url_encoding=yaml_data.get("extensions", {}).get(
|
|
438
|
-
"x-ms-skip-url-encoding", False
|
|
439
|
-
),
|
|
440
|
-
constraints=[], # FIXME constraints
|
|
441
|
-
target_property_name=target_property_name,
|
|
442
|
-
style=ParameterStyle(http_protocol["style"])
|
|
443
|
-
if "style" in http_protocol
|
|
444
|
-
else None,
|
|
445
|
-
explode=http_protocol.get("explode", False),
|
|
446
|
-
grouped_by=yaml_data.get("groupedBy", None),
|
|
447
|
-
original_parameter=yaml_data.get("originalParameter", None),
|
|
448
|
-
flattened=yaml_data.get("flattened", False),
|
|
449
|
-
client_default_value=yaml_data.get("clientDefaultValue"),
|
|
450
|
-
content_types=content_types,
|
|
341
|
+
type=code_model.lookup_type(id(yaml_data["type"])),
|
|
451
342
|
)
|
|
452
343
|
|
|
453
|
-
def imports(self) -> FileImport:
|
|
454
|
-
if self.need_import:
|
|
455
|
-
file_import = self.schema.imports()
|
|
456
|
-
if not self.required:
|
|
457
|
-
file_import.add_submodule_import(
|
|
458
|
-
"typing", "Optional", ImportType.STDLIB, TypingSection.CONDITIONAL
|
|
459
|
-
)
|
|
460
|
-
if self.has_multiple_content_types or self._is_io_json:
|
|
461
|
-
file_import.add_submodule_import(
|
|
462
|
-
"typing", "Union", ImportType.STDLIB, TypingSection.CONDITIONAL
|
|
463
|
-
)
|
|
464
344
|
|
|
465
|
-
|
|
466
|
-
|
|
345
|
+
class ClientParameter(Parameter):
|
|
346
|
+
"""Client parameter"""
|
|
467
347
|
|
|
348
|
+
@property
|
|
349
|
+
def is_host(self) -> bool:
|
|
350
|
+
return self.rest_api_name == "$host"
|
|
468
351
|
|
|
469
|
-
class ParameterOnlyPathAndBodyPositional(Parameter):
|
|
470
352
|
@property
|
|
471
353
|
def method_location(self) -> ParameterMethodLocation:
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
return super_method_location
|
|
478
|
-
if self._method_location:
|
|
479
|
-
return self._method_location
|
|
480
|
-
if self.location not in (
|
|
481
|
-
ParameterLocation.Path,
|
|
482
|
-
ParameterLocation.Uri,
|
|
483
|
-
ParameterLocation.Body,
|
|
354
|
+
if self.constant:
|
|
355
|
+
return ParameterMethodLocation.KWARG
|
|
356
|
+
if self.is_host and (
|
|
357
|
+
self.code_model.options["version_tolerant"]
|
|
358
|
+
or self.code_model.options["low_level_client"]
|
|
484
359
|
):
|
|
360
|
+
# this means i am the base url
|
|
485
361
|
return ParameterMethodLocation.KEYWORD_ONLY
|
|
486
|
-
return
|
|
362
|
+
return ParameterMethodLocation.POSITIONAL
|
|
363
|
+
|
|
364
|
+
|
|
365
|
+
class ConfigParameter(Parameter):
|
|
366
|
+
"""Config Parameter"""
|
|
367
|
+
|
|
368
|
+
@property
|
|
369
|
+
def in_method_signature(self) -> bool:
|
|
370
|
+
return not self.is_host
|
|
371
|
+
|
|
372
|
+
@property
|
|
373
|
+
def is_host(self) -> bool:
|
|
374
|
+
return self.rest_api_name == "$host"
|
|
487
375
|
|
|
488
|
-
@
|
|
489
|
-
def method_location(self
|
|
490
|
-
self.
|
|
376
|
+
@property
|
|
377
|
+
def method_location(self) -> ParameterMethodLocation:
|
|
378
|
+
if self.constant:
|
|
379
|
+
return ParameterMethodLocation.KWARG
|
|
380
|
+
return ParameterMethodLocation.POSITIONAL
|
|
491
381
|
|
|
492
382
|
|
|
493
|
-
def
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
383
|
+
def get_body_parameter(
|
|
384
|
+
yaml_data: Dict[str, Any], code_model: "CodeModel"
|
|
385
|
+
) -> Union[BodyParameter, MultipartBodyParameter]:
|
|
386
|
+
"""Creates a regular body parameter or Multipart body parameter"""
|
|
387
|
+
if yaml_data.get("entries"):
|
|
388
|
+
return MultipartBodyParameter.from_yaml(yaml_data, code_model)
|
|
389
|
+
return BodyParameter.from_yaml(yaml_data, code_model)
|