@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,154 +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
|
-
|
|
31
|
+
class ParameterLocation(str, Enum):
|
|
32
|
+
HEADER = "header"
|
|
33
|
+
PATH = "path"
|
|
34
|
+
ENDPOINT_PATH = "endpointPath"
|
|
35
|
+
QUERY = "query"
|
|
36
|
+
BODY = "body"
|
|
37
|
+
OTHER = "other"
|
|
27
38
|
|
|
28
39
|
|
|
29
|
-
class
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
Header = "header"
|
|
34
|
-
Uri = "uri"
|
|
35
|
-
Other = "other"
|
|
40
|
+
class ParameterMethodLocation(Enum):
|
|
41
|
+
POSITIONAL = auto()
|
|
42
|
+
KEYWORD_ONLY = auto()
|
|
43
|
+
KWARG = auto()
|
|
36
44
|
|
|
37
45
|
|
|
38
|
-
class
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
spaceDelimited = "spaceDelimited"
|
|
44
|
-
pipeDelimited = "pipeDelimited"
|
|
45
|
-
deepObject = "deepObject"
|
|
46
|
-
tabDelimited = "tabDelimited"
|
|
47
|
-
json = "json"
|
|
48
|
-
binary = "binary"
|
|
49
|
-
xml = "xml"
|
|
50
|
-
multipart = "multipart"
|
|
46
|
+
class ParameterDelimeter(str, Enum):
|
|
47
|
+
SPACE = "space"
|
|
48
|
+
PIPE = "pipe"
|
|
49
|
+
TAB = "tab"
|
|
50
|
+
COMMA = "comma"
|
|
51
51
|
|
|
52
52
|
|
|
53
|
+
class _ParameterBase(
|
|
54
|
+
BaseModel, abc.ABC
|
|
55
|
+
): # pylint: disable=too-many-instance-attributes
|
|
56
|
+
"""Base class for all parameters"""
|
|
53
57
|
|
|
54
|
-
def get_target_property_name(code_model: "CodeModel", target_property_id: int) -> str:
|
|
55
|
-
for obj in code_model.schemas.values():
|
|
56
|
-
for prop in obj.properties:
|
|
57
|
-
if prop.id == target_property_id:
|
|
58
|
-
return prop.name
|
|
59
|
-
raise KeyError("Didn't find the target property")
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
class Parameter(BaseModel): # pylint: disable=too-many-instance-attributes, too-many-public-methods
|
|
63
58
|
def __init__(
|
|
64
59
|
self,
|
|
65
|
-
code_model,
|
|
66
60
|
yaml_data: Dict[str, Any],
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
serialized_name: str,
|
|
70
|
-
description: str,
|
|
71
|
-
implementation: str,
|
|
72
|
-
required: bool,
|
|
73
|
-
location: ParameterLocation,
|
|
74
|
-
skip_url_encoding: bool,
|
|
75
|
-
constraints: List[Any],
|
|
76
|
-
target_property_name: Optional[Union[int, str]] = None, # first uses id as placeholder
|
|
77
|
-
style: Optional[ParameterStyle] = None,
|
|
78
|
-
explode: Optional[bool] = False,
|
|
79
|
-
*,
|
|
80
|
-
flattened: bool = False,
|
|
81
|
-
grouped_by: Optional["Parameter"] = None,
|
|
82
|
-
original_parameter: Optional["Parameter"] = None,
|
|
83
|
-
client_default_value: Optional[Any] = None,
|
|
84
|
-
keyword_only: Optional[bool] = None,
|
|
85
|
-
content_types: Optional[List[str]] = None,
|
|
61
|
+
code_model: "CodeModel",
|
|
62
|
+
type: BaseType,
|
|
86
63
|
) -> None:
|
|
87
|
-
super().__init__(yaml_data)
|
|
88
|
-
self.
|
|
89
|
-
self.
|
|
90
|
-
self.
|
|
91
|
-
self.
|
|
92
|
-
self.
|
|
93
|
-
self.
|
|
94
|
-
self.
|
|
95
|
-
self.
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
self.
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
self.
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
self.
|
|
105
|
-
self.
|
|
106
|
-
self.
|
|
107
|
-
self.
|
|
108
|
-
self._keyword_only = keyword_only
|
|
109
|
-
self.is_multipart = yaml_data.get("language", {}).get("python", {}).get("multipart", False)
|
|
110
|
-
self.is_data_input = yaml_data.get("isPartialBody", False) and not self.is_multipart
|
|
111
|
-
self.content_types = content_types or []
|
|
112
|
-
self.body_kwargs: List[Parameter] = []
|
|
113
|
-
self.is_body_kwarg = False
|
|
114
|
-
self.need_import = True
|
|
115
|
-
self.is_kwarg = (self.rest_api_name == "Content-Type" or (self.constant and self.inputtable_by_user))
|
|
116
|
-
|
|
117
|
-
def __hash__(self) -> int:
|
|
118
|
-
return hash(self.serialized_name)
|
|
119
|
-
|
|
120
|
-
@property
|
|
121
|
-
def description(self):
|
|
122
|
-
try:
|
|
123
|
-
description = self._description
|
|
124
|
-
if self.schema.extra_description_information:
|
|
125
|
-
if description:
|
|
126
|
-
description += " "
|
|
127
|
-
description += f"{self.schema.extra_description_information}"
|
|
128
|
-
if isinstance(self.schema, ConstantSchema) and not self.constant:
|
|
129
|
-
if description:
|
|
130
|
-
description += " "
|
|
131
|
-
description += f"Known values are {self.schema.get_declaration(self.schema.value)} or {None}."
|
|
132
|
-
if self.has_default_value and not any(
|
|
133
|
-
l for l in ["default value is", "default is"] if l in description.lower()
|
|
134
|
-
):
|
|
135
|
-
description += f" Default value is {self.default_value_declaration}."
|
|
136
|
-
if self.constant:
|
|
137
|
-
description += " Note that overriding this default value may result in unsupported behavior."
|
|
138
|
-
return description
|
|
139
|
-
except AttributeError:
|
|
140
|
-
pass
|
|
141
|
-
return self._description
|
|
142
|
-
|
|
143
|
-
@description.setter
|
|
144
|
-
def description(self, val: str):
|
|
145
|
-
self._description = val
|
|
146
|
-
|
|
147
|
-
@property
|
|
148
|
-
def is_json_parameter(self) -> bool:
|
|
149
|
-
if self.is_multipart or self.is_data_input:
|
|
150
|
-
return False
|
|
151
|
-
if self.style == ParameterStyle.xml:
|
|
152
|
-
return False
|
|
153
|
-
return True
|
|
64
|
+
super().__init__(yaml_data, code_model)
|
|
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"
|
|
80
|
+
)
|
|
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)
|
|
154
85
|
|
|
155
86
|
@property
|
|
156
87
|
def constant(self) -> bool:
|
|
@@ -158,271 +89,301 @@ class Parameter(BaseModel): # pylint: disable=too-many-instance-attributes, too
|
|
|
158
89
|
Checking to see if it's required, because if not, we don't consider it
|
|
159
90
|
a constant because it can have a value of None.
|
|
160
91
|
"""
|
|
161
|
-
|
|
162
|
-
if not self.schema.get("type") == "constant":
|
|
163
|
-
return False
|
|
164
|
-
else:
|
|
165
|
-
if not isinstance(self.schema, ConstantSchema):
|
|
166
|
-
return False
|
|
167
|
-
return self.required
|
|
92
|
+
return not self.optional and isinstance(self.type, ConstantType)
|
|
168
93
|
|
|
169
94
|
@property
|
|
170
|
-
def
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
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}.",
|
|
116
|
+
)
|
|
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
|
|
178
123
|
|
|
179
124
|
@property
|
|
180
|
-
def
|
|
181
|
-
|
|
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)
|
|
182
130
|
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
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
|
|
186
137
|
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
return self.location == ParameterLocation.Body
|
|
138
|
+
def docstring_text(self, **kwargs: Any) -> str:
|
|
139
|
+
return self.type.docstring_text(**kwargs)
|
|
190
140
|
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
return self.rest_api_name != "Accept"
|
|
141
|
+
def docstring_type(self, **kwargs: Any) -> str:
|
|
142
|
+
return self.type.docstring_type(**kwargs)
|
|
194
143
|
|
|
195
144
|
@property
|
|
196
|
-
def
|
|
197
|
-
|
|
198
|
-
I.e. ["text/plain; charset=UTF-8"] -> ["text/plain"]
|
|
199
|
-
"""
|
|
200
|
-
return [content_type.split(";")[0] for content_type in self.content_types]
|
|
145
|
+
def serialization_type(self) -> str:
|
|
146
|
+
return self.type.serialization_type
|
|
201
147
|
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
not self.inputtable_by_user
|
|
207
|
-
# If i'm not in the method code, no point in being in signature
|
|
208
|
-
or not self.in_method_code
|
|
209
|
-
# If I'm grouped, my grouper will be on signature, not me
|
|
210
|
-
or self.grouped_by
|
|
211
|
-
# If I'm body and it's flattened, I'm not either
|
|
212
|
-
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)
|
|
213
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
|
|
214
156
|
|
|
215
157
|
@property
|
|
216
|
-
def
|
|
217
|
-
|
|
218
|
-
raise ValueError("Should only be calling if your parameter is grouped")
|
|
219
|
-
try:
|
|
220
|
-
return next(
|
|
221
|
-
p for p in cast(ObjectSchema, self.grouped_by.schema).properties
|
|
222
|
-
if any(op for op in p.yaml_data['originalParameter'] if id(op) == self.id)
|
|
223
|
-
)
|
|
224
|
-
except StopIteration:
|
|
225
|
-
raise ValueError("There is not a corresponding grouped property for your parameter.")
|
|
158
|
+
def method_location(self) -> ParameterMethodLocation:
|
|
159
|
+
raise NotImplementedError("Please implement in children")
|
|
226
160
|
|
|
227
161
|
@property
|
|
228
|
-
def
|
|
229
|
-
return
|
|
162
|
+
def description_keyword(self) -> str:
|
|
163
|
+
return (
|
|
164
|
+
"param"
|
|
165
|
+
if self.method_location == ParameterMethodLocation.POSITIONAL
|
|
166
|
+
else "keyword"
|
|
167
|
+
)
|
|
230
168
|
|
|
231
169
|
@property
|
|
232
|
-
def
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
170
|
+
def docstring_type_keyword(self) -> str:
|
|
171
|
+
return (
|
|
172
|
+
"type"
|
|
173
|
+
if self.method_location == ParameterMethodLocation.POSITIONAL
|
|
174
|
+
else "paramtype"
|
|
175
|
+
)
|
|
237
176
|
|
|
238
177
|
@property
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
) and isinstance(self.schema, IOSchema)
|
|
243
|
-
|
|
244
|
-
def _default_value(self) -> Tuple[Optional[Any], str, str]:
|
|
245
|
-
type_annot = self.multiple_content_types_type_annot or self.schema.type_annotation(is_operation_file=True)
|
|
246
|
-
if self._is_io_json:
|
|
247
|
-
type_annot = f"Union[{type_annot}, JSONType]"
|
|
248
|
-
any_types = ["Any", "JSONType"]
|
|
249
|
-
if not self.required and type_annot not in any_types and not self._is_io_json:
|
|
250
|
-
type_annot = f"Optional[{type_annot}]"
|
|
178
|
+
@abc.abstractmethod
|
|
179
|
+
def in_method_signature(self) -> bool:
|
|
180
|
+
...
|
|
251
181
|
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
if (self.required or
|
|
262
|
-
self.is_content_type or
|
|
263
|
-
not self.code_model.options["default_optional_constants_to_none"]):
|
|
264
|
-
default_value = self.schema.get_declaration(self.schema.value)
|
|
265
|
-
else:
|
|
266
|
-
default_value = None
|
|
267
|
-
default_value_declaration = default_value
|
|
268
|
-
else:
|
|
269
|
-
default_value = self.schema.default_value
|
|
270
|
-
default_value_declaration = self.schema.default_value_declaration
|
|
271
|
-
if default_value is not None and self.required:
|
|
272
|
-
_LOGGER.warning(
|
|
273
|
-
"Parameter '%s' is required and has a default value, this combination is not recommended",
|
|
274
|
-
self.rest_api_name
|
|
275
|
-
)
|
|
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}"
|
|
276
191
|
|
|
277
|
-
return default_value, default_value_declaration, type_annot
|
|
278
192
|
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
return "keyword" if self.is_kwarg or self.is_keyword_only else "param"
|
|
193
|
+
class _BodyParameterBase(_ParameterBase):
|
|
194
|
+
"""Base class for body parameters"""
|
|
282
195
|
|
|
283
196
|
@property
|
|
284
|
-
def
|
|
285
|
-
|
|
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)
|
|
286
200
|
|
|
287
201
|
@property
|
|
288
|
-
def
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
202
|
+
def method_location(self) -> ParameterMethodLocation:
|
|
203
|
+
return (
|
|
204
|
+
ParameterMethodLocation.KWARG
|
|
205
|
+
if self.constant
|
|
206
|
+
else ParameterMethodLocation.POSITIONAL
|
|
207
|
+
)
|
|
292
208
|
|
|
293
209
|
@property
|
|
294
|
-
def
|
|
295
|
-
return self.
|
|
210
|
+
def in_method_signature(self) -> bool:
|
|
211
|
+
return not (self.flattened or self.grouped_by)
|
|
296
212
|
|
|
297
|
-
def type_annotation(self, *, is_operation_file: bool = False) -> str: # pylint: disable=unused-argument
|
|
298
|
-
return self._default_value()[2]
|
|
299
213
|
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
return self.schema.serialization_type
|
|
214
|
+
class BodyParameter(_BodyParameterBase):
|
|
215
|
+
"""Body parameter."""
|
|
303
216
|
|
|
304
217
|
@property
|
|
305
|
-
def
|
|
306
|
-
|
|
307
|
-
if self._is_io_json:
|
|
308
|
-
retval += " or JSONType"
|
|
309
|
-
return retval
|
|
218
|
+
def content_types(self) -> List[str]:
|
|
219
|
+
return self.yaml_data["contentTypes"]
|
|
310
220
|
|
|
311
221
|
@property
|
|
312
|
-
def
|
|
313
|
-
return self.
|
|
222
|
+
def default_content_type(self) -> str:
|
|
223
|
+
return self.yaml_data["defaultContentType"]
|
|
314
224
|
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
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"])),
|
|
233
|
+
)
|
|
324
234
|
|
|
325
|
-
@property
|
|
326
|
-
def full_serialized_name(self) -> str:
|
|
327
|
-
origin_name = self.serialized_name
|
|
328
|
-
if self.implementation == "Client":
|
|
329
|
-
origin_name = f"self._config.{self.serialized_name}"
|
|
330
|
-
return origin_name
|
|
331
235
|
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
return self._keyword_only or False
|
|
236
|
+
EntryBodyParameterType = TypeVar(
|
|
237
|
+
"EntryBodyParameterType", bound=Union[BodyParameter, "RequestBuilderBodyParameter"]
|
|
238
|
+
)
|
|
336
239
|
|
|
337
|
-
@is_keyword_only.setter
|
|
338
|
-
def is_keyword_only(self, val: bool) -> None:
|
|
339
|
-
self._keyword_only = val
|
|
340
|
-
self.is_kwarg = False
|
|
341
240
|
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
return self.serialized_name in _HIDDEN_KWARGS and self.is_kwarg or (
|
|
345
|
-
self.yaml_data["implementation"] == "Client" and self.constant
|
|
346
|
-
)
|
|
241
|
+
class _MultipartBodyParameter(Generic[EntryBodyParameterType], BodyParameter):
|
|
242
|
+
"""Base class for MultipartBodyParameter and RequestBuilderMultipartBodyParameter"""
|
|
347
243
|
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
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
|
|
351
253
|
|
|
352
254
|
@property
|
|
353
|
-
def
|
|
354
|
-
|
|
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
|
|
259
|
+
|
|
260
|
+
|
|
261
|
+
class MultipartBodyParameter(
|
|
262
|
+
_MultipartBodyParameter[BodyParameter] # pylint: disable=unsubscriptable-object
|
|
263
|
+
):
|
|
264
|
+
"""Multipart body parameter for Operation. Used for files and data input."""
|
|
355
265
|
|
|
356
266
|
@classmethod
|
|
357
267
|
def from_yaml(
|
|
358
|
-
cls,
|
|
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,
|
|
359
286
|
yaml_data: Dict[str, Any],
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
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")
|
|
298
|
+
|
|
299
|
+
@property
|
|
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:
|
|
305
|
+
if self.implementation == "Client":
|
|
306
|
+
return f"self._config.{self.client_name}"
|
|
307
|
+
return self.client_name
|
|
308
|
+
|
|
309
|
+
@property
|
|
310
|
+
def xml_serialization_ctxt(self) -> str:
|
|
311
|
+
return self.type.xml_serialization_ctxt or ""
|
|
312
|
+
|
|
313
|
+
@property
|
|
314
|
+
def method_location(self) -> ParameterMethodLocation:
|
|
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
|
|
324
|
+
return ParameterMethodLocation.KWARG
|
|
325
|
+
query_or_header = self.location in (
|
|
326
|
+
ParameterLocation.HEADER,
|
|
327
|
+
ParameterLocation.QUERY,
|
|
368
328
|
)
|
|
369
|
-
|
|
370
|
-
|
|
329
|
+
if (
|
|
330
|
+
self.code_model.options["only_path_and_body_params_positional"]
|
|
331
|
+
and query_or_header
|
|
332
|
+
):
|
|
333
|
+
return ParameterMethodLocation.KEYWORD_ONLY
|
|
334
|
+
return ParameterMethodLocation.POSITIONAL
|
|
371
335
|
|
|
336
|
+
@classmethod
|
|
337
|
+
def from_yaml(cls, yaml_data: Dict[str, Any], code_model: "CodeModel"):
|
|
372
338
|
return cls(
|
|
373
|
-
code_model=code_model,
|
|
374
339
|
yaml_data=yaml_data,
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
rest_api_name=yaml_data["language"]["default"].get(
|
|
378
|
-
"serializedName", yaml_data["language"]["default"]["name"]
|
|
379
|
-
),
|
|
380
|
-
serialized_name=serialized_name,
|
|
381
|
-
description=yaml_data["language"]["python"]["description"],
|
|
382
|
-
implementation=yaml_data["implementation"],
|
|
383
|
-
required=yaml_data.get("required", False),
|
|
384
|
-
location=ParameterLocation(http_protocol["in"]),
|
|
385
|
-
skip_url_encoding=yaml_data.get("extensions", {}).get("x-ms-skip-url-encoding", False),
|
|
386
|
-
constraints=[], # FIXME constraints
|
|
387
|
-
target_property_name=target_property_name,
|
|
388
|
-
style=ParameterStyle(http_protocol["style"]) if "style" in http_protocol else None,
|
|
389
|
-
explode=http_protocol.get("explode", False),
|
|
390
|
-
grouped_by=yaml_data.get("groupedBy", None),
|
|
391
|
-
original_parameter=yaml_data.get("originalParameter", None),
|
|
392
|
-
flattened=yaml_data.get("flattened", False),
|
|
393
|
-
client_default_value=yaml_data.get("clientDefaultValue"),
|
|
394
|
-
content_types=content_types
|
|
340
|
+
code_model=code_model,
|
|
341
|
+
type=code_model.lookup_type(id(yaml_data["type"])),
|
|
395
342
|
)
|
|
396
343
|
|
|
397
|
-
def imports(self) -> FileImport:
|
|
398
|
-
file_import = self.schema.imports()
|
|
399
|
-
if not self.required:
|
|
400
|
-
file_import.add_submodule_import("typing", "Optional", ImportType.STDLIB, TypingSection.CONDITIONAL)
|
|
401
|
-
if self.has_multiple_content_types or self._is_io_json:
|
|
402
|
-
file_import.add_submodule_import("typing", "Union", ImportType.STDLIB, TypingSection.CONDITIONAL)
|
|
403
344
|
|
|
404
|
-
|
|
345
|
+
class ClientParameter(Parameter):
|
|
346
|
+
"""Client parameter"""
|
|
405
347
|
|
|
406
|
-
|
|
348
|
+
@property
|
|
349
|
+
def is_host(self) -> bool:
|
|
350
|
+
return self.rest_api_name == "$host"
|
|
407
351
|
|
|
408
352
|
@property
|
|
409
|
-
def
|
|
410
|
-
if self.
|
|
411
|
-
return
|
|
412
|
-
|
|
413
|
-
self.
|
|
414
|
-
self.
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
353
|
+
def method_location(self) -> ParameterMethodLocation:
|
|
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"]
|
|
359
|
+
):
|
|
360
|
+
# this means i am the base url
|
|
361
|
+
return ParameterMethodLocation.KEYWORD_ONLY
|
|
362
|
+
return ParameterMethodLocation.POSITIONAL
|
|
363
|
+
|
|
419
364
|
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
self._keyword_only = val
|
|
423
|
-
self.is_kwarg = False
|
|
365
|
+
class ConfigParameter(Parameter):
|
|
366
|
+
"""Config Parameter"""
|
|
424
367
|
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
return
|
|
428
|
-
|
|
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"
|
|
375
|
+
|
|
376
|
+
@property
|
|
377
|
+
def method_location(self) -> ParameterMethodLocation:
|
|
378
|
+
if self.constant:
|
|
379
|
+
return ParameterMethodLocation.KWARG
|
|
380
|
+
return ParameterMethodLocation.POSITIONAL
|
|
381
|
+
|
|
382
|
+
|
|
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)
|