@autorest/python 5.14.0 → 5.15.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 +29 -0
- package/autorest/codegen/__init__.py +87 -47
- package/autorest/codegen/models/base_schema.py +2 -6
- package/autorest/codegen/models/client.py +6 -0
- package/autorest/codegen/models/code_model.py +40 -74
- package/autorest/codegen/models/constant_schema.py +7 -3
- package/autorest/codegen/models/credential_model.py +47 -0
- package/autorest/codegen/models/credential_schema.py +5 -4
- package/autorest/codegen/models/dictionary_schema.py +7 -7
- package/autorest/codegen/models/enum_schema.py +8 -39
- package/autorest/codegen/models/imports.py +3 -1
- package/autorest/codegen/models/list_schema.py +18 -8
- package/autorest/codegen/models/lro_operation.py +3 -3
- package/autorest/codegen/models/lro_paging_operation.py +3 -3
- package/autorest/codegen/models/object_schema.py +17 -13
- package/autorest/codegen/models/operation.py +27 -6
- package/autorest/codegen/models/operation_group.py +7 -2
- package/autorest/codegen/models/paging_operation.py +3 -3
- package/autorest/codegen/models/parameter.py +39 -15
- package/autorest/codegen/models/parameter_list.py +1 -1
- package/autorest/codegen/models/primitive_schemas.py +15 -25
- package/autorest/codegen/models/property.py +5 -5
- package/autorest/codegen/models/request_builder.py +4 -4
- package/autorest/codegen/models/request_builder_parameter.py +12 -5
- package/autorest/codegen/models/schema_response.py +23 -10
- package/autorest/codegen/models/utils.py +20 -0
- package/autorest/codegen/serializers/__init__.py +49 -25
- package/autorest/codegen/serializers/builder_serializer.py +79 -37
- package/autorest/codegen/serializers/client_serializer.py +16 -6
- package/autorest/codegen/serializers/general_serializer.py +24 -3
- package/autorest/codegen/serializers/import_serializer.py +1 -1
- package/autorest/codegen/serializers/metadata_serializer.py +1 -1
- package/autorest/codegen/serializers/model_base_serializer.py +8 -0
- package/autorest/codegen/serializers/model_python3_serializer.py +2 -2
- package/autorest/codegen/serializers/operation_groups_serializer.py +1 -0
- package/autorest/codegen/serializers/patch_serializer.py +12 -3
- package/autorest/codegen/serializers/utils.py +29 -4
- package/autorest/codegen/templates/config.py.jinja2 +4 -4
- package/autorest/codegen/templates/enum.py.jinja2 +1 -1
- package/autorest/codegen/templates/enum_container.py.jinja2 +0 -1
- package/autorest/codegen/templates/init.py.jinja2 +9 -6
- package/autorest/codegen/templates/keywords.jinja2 +14 -1
- package/autorest/codegen/templates/lro_operation.py.jinja2 +1 -1
- package/autorest/codegen/templates/lro_paging_operation.py.jinja2 +1 -1
- package/autorest/codegen/templates/metadata.json.jinja2 +3 -3
- package/autorest/codegen/templates/model.py.jinja2 +1 -6
- package/autorest/codegen/templates/model_init.py.jinja2 +7 -4
- package/autorest/codegen/templates/operation.py.jinja2 +2 -3
- package/autorest/codegen/templates/operation_group.py.jinja2 +12 -5
- package/autorest/codegen/templates/operation_groups_container.py.jinja2 +0 -1
- package/autorest/codegen/templates/operations_folder_init.py.jinja2 +4 -0
- package/autorest/codegen/templates/paging_operation.py.jinja2 +1 -1
- package/autorest/codegen/templates/patch.py.jinja2 +18 -29
- package/autorest/codegen/templates/request_builder.py.jinja2 +4 -6
- package/autorest/codegen/templates/vendor.py.jinja2 +12 -2
- package/autorest/multiapi/models/imports.py +21 -11
- package/autorest/multiapi/serializers/import_serializer.py +3 -1
- package/package.json +2 -2
|
@@ -59,13 +59,11 @@ class EnumSchema(BaseSchema):
|
|
|
59
59
|
name: str,
|
|
60
60
|
values: List["EnumValue"],
|
|
61
61
|
enum_type: PrimitiveSchema,
|
|
62
|
-
enum_file_name: str
|
|
63
62
|
) -> None:
|
|
64
63
|
super(EnumSchema, self).__init__(namespace=namespace, yaml_data=yaml_data)
|
|
65
64
|
self.description = description
|
|
66
65
|
self.name = name
|
|
67
66
|
self.values = values
|
|
68
|
-
self.enum_file_name = enum_file_name
|
|
69
67
|
self.enum_type = enum_type
|
|
70
68
|
|
|
71
69
|
def __lt__(self, other):
|
|
@@ -80,23 +78,13 @@ class EnumSchema(BaseSchema):
|
|
|
80
78
|
"""
|
|
81
79
|
return self.enum_type.serialization_type
|
|
82
80
|
|
|
83
|
-
|
|
84
|
-
def type_annotation(self) -> str:
|
|
81
|
+
def type_annotation(self, *, is_operation_file: bool = False) -> str:
|
|
85
82
|
"""The python type used for type annotation
|
|
86
83
|
|
|
87
84
|
:return: The type annotation for this schema
|
|
88
85
|
:rtype: str
|
|
89
86
|
"""
|
|
90
|
-
return f'Union[{self.enum_type.type_annotation}, "{self.name}"]'
|
|
91
|
-
|
|
92
|
-
@property
|
|
93
|
-
def operation_type_annotation(self) -> str:
|
|
94
|
-
"""The python type used for type annotation
|
|
95
|
-
|
|
96
|
-
:return: The type annotation for this schema
|
|
97
|
-
:rtype: str
|
|
98
|
-
"""
|
|
99
|
-
return f'Union[{self.enum_type.type_annotation}, "_models.{self.name}"]'
|
|
87
|
+
return f'Union[{self.enum_type.type_annotation(is_operation_file=is_operation_file)}, "_models.{self.name}"]'
|
|
100
88
|
|
|
101
89
|
def get_declaration(self, value: Any) -> str:
|
|
102
90
|
return self.enum_type.get_declaration(value)
|
|
@@ -109,7 +97,7 @@ class EnumSchema(BaseSchema):
|
|
|
109
97
|
def docstring_type(self) -> str:
|
|
110
98
|
"""The python type used for RST syntax input and type annotation.
|
|
111
99
|
"""
|
|
112
|
-
return f"{self.enum_type.type_annotation} or ~{self.namespace}.models.{self.name}"
|
|
100
|
+
return f"{self.enum_type.type_annotation()} or ~{self.namespace}.models.{self.name}"
|
|
113
101
|
|
|
114
102
|
@staticmethod
|
|
115
103
|
def _get_enum_values(yaml_data: List[Dict[str, Any]]) -> List["EnumValue"]:
|
|
@@ -164,8 +152,6 @@ class EnumSchema(BaseSchema):
|
|
|
164
152
|
else:
|
|
165
153
|
enum_type = StringSchema(namespace, {"type": "str"})
|
|
166
154
|
values = EnumSchema._get_enum_values(yaml_data["choices"])
|
|
167
|
-
code_model = kwargs.pop("code_model")
|
|
168
|
-
|
|
169
155
|
return cls(
|
|
170
156
|
namespace=namespace,
|
|
171
157
|
yaml_data=yaml_data,
|
|
@@ -173,7 +159,6 @@ class EnumSchema(BaseSchema):
|
|
|
173
159
|
name=name,
|
|
174
160
|
values=values,
|
|
175
161
|
enum_type=enum_type,
|
|
176
|
-
enum_file_name=f"_{code_model.module_name}_enums"
|
|
177
162
|
)
|
|
178
163
|
|
|
179
164
|
def imports(self) -> FileImport:
|
|
@@ -182,12 +167,6 @@ class EnumSchema(BaseSchema):
|
|
|
182
167
|
file_import.merge(self.enum_type.imports())
|
|
183
168
|
return file_import
|
|
184
169
|
|
|
185
|
-
def model_file_imports(self) -> FileImport:
|
|
186
|
-
imports = self.imports()
|
|
187
|
-
# we import every enum since we can get extremely long imports
|
|
188
|
-
# if we import my name
|
|
189
|
-
imports.add_submodule_import("." + self.enum_file_name, "*", ImportType.LOCAL)
|
|
190
|
-
return imports
|
|
191
170
|
|
|
192
171
|
class HiddenModelEnumSchema(EnumSchema):
|
|
193
172
|
|
|
@@ -196,27 +175,17 @@ class HiddenModelEnumSchema(EnumSchema):
|
|
|
196
175
|
file_import.merge(self.enum_type.imports())
|
|
197
176
|
return file_import
|
|
198
177
|
|
|
199
|
-
|
|
200
|
-
def type_annotation(self) -> str:
|
|
201
|
-
"""The python type used for type annotation
|
|
202
|
-
|
|
203
|
-
:return: The type annotation for this schema
|
|
204
|
-
:rtype: str
|
|
205
|
-
"""
|
|
206
|
-
return self.enum_type.type_annotation
|
|
207
|
-
|
|
208
|
-
@property
|
|
209
|
-
def operation_type_annotation(self) -> str:
|
|
178
|
+
def type_annotation(self, *, is_operation_file: bool = False) -> str:
|
|
210
179
|
"""The python type used for type annotation
|
|
211
180
|
|
|
212
181
|
:return: The type annotation for this schema
|
|
213
182
|
:rtype: str
|
|
214
183
|
"""
|
|
215
|
-
return self.enum_type.type_annotation
|
|
184
|
+
return self.enum_type.type_annotation(is_operation_file=is_operation_file)
|
|
216
185
|
|
|
217
186
|
@property
|
|
218
187
|
def docstring_text(self) -> str:
|
|
219
|
-
return f"{self.enum_type.type_annotation}. {self.extra_description_information}"
|
|
188
|
+
return f"{self.enum_type.type_annotation()}. {self.extra_description_information}"
|
|
220
189
|
|
|
221
190
|
@property
|
|
222
191
|
def extra_description_information(self):
|
|
@@ -232,13 +201,13 @@ class HiddenModelEnumSchema(EnumSchema):
|
|
|
232
201
|
possible_values[: len(possible_values) - 1]
|
|
233
202
|
) + f", and {possible_values[-1]}"
|
|
234
203
|
|
|
235
|
-
return "
|
|
204
|
+
return "Known values are: {}.".format(possible_values_str)
|
|
236
205
|
|
|
237
206
|
@property
|
|
238
207
|
def docstring_type(self) -> str:
|
|
239
208
|
"""The python type used for RST syntax input and type annotation.
|
|
240
209
|
"""
|
|
241
|
-
return self.enum_type.type_annotation
|
|
210
|
+
return self.enum_type.type_annotation()
|
|
242
211
|
|
|
243
212
|
def get_enum_schema(code_model) -> Type[EnumSchema]:
|
|
244
213
|
if code_model.options["models_mode"]:
|
|
@@ -97,13 +97,15 @@ class FileImport:
|
|
|
97
97
|
self,
|
|
98
98
|
module_name: str,
|
|
99
99
|
import_type: ImportType,
|
|
100
|
-
typing_section: TypingSection = TypingSection.REGULAR
|
|
100
|
+
typing_section: TypingSection = TypingSection.REGULAR,
|
|
101
|
+
alias: Optional[str] = None,
|
|
101
102
|
) -> None:
|
|
102
103
|
# Implementation detail: a regular import is just a "from" with no from
|
|
103
104
|
self._append_import(ImportModel(
|
|
104
105
|
typing_section=typing_section,
|
|
105
106
|
import_type=import_type,
|
|
106
107
|
module_name=module_name,
|
|
108
|
+
alias=alias,
|
|
107
109
|
))
|
|
108
110
|
|
|
109
111
|
def define_mypy_type(self, type_name: str, type_value: str, async_type_value: Optional[str] = None):
|
|
@@ -29,20 +29,24 @@ class ListSchema(BaseSchema):
|
|
|
29
29
|
def serialization_type(self) -> str:
|
|
30
30
|
return f"[{self.element_type.serialization_type}]"
|
|
31
31
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
def operation_type_annotation(self) -> str:
|
|
38
|
-
return f"List[{self.element_type.operation_type_annotation}]"
|
|
32
|
+
def type_annotation(self, *, is_operation_file: bool = False) -> str:
|
|
33
|
+
if self.element_type.type_annotation() == "ET.Element":
|
|
34
|
+
# this means we're version tolerant XML, we just return the XML element
|
|
35
|
+
return self.element_type.type_annotation(is_operation_file=is_operation_file)
|
|
36
|
+
return f"List[{self.element_type.type_annotation(is_operation_file=is_operation_file)}]"
|
|
39
37
|
|
|
40
38
|
@property
|
|
41
39
|
def docstring_type(self) -> str:
|
|
40
|
+
if self.element_type.docstring_type == "ET.Element":
|
|
41
|
+
# this means we're version tolerant XML, we just return the XML element
|
|
42
|
+
return self.element_type.docstring_type
|
|
42
43
|
return f"list[{self.element_type.docstring_type}]"
|
|
43
44
|
|
|
44
45
|
@property
|
|
45
46
|
def docstring_text(self) -> str:
|
|
47
|
+
if self.element_type.docstring_text == "XML Element":
|
|
48
|
+
# this means we're version tolerant XML, we just return the XML element
|
|
49
|
+
return self.element_type.docstring_text
|
|
46
50
|
return f"list of {self.element_type.docstring_text}"
|
|
47
51
|
|
|
48
52
|
@property
|
|
@@ -108,6 +112,12 @@ class ListSchema(BaseSchema):
|
|
|
108
112
|
|
|
109
113
|
def imports(self) -> FileImport:
|
|
110
114
|
file_import = FileImport()
|
|
111
|
-
|
|
115
|
+
if not self.element_type.type_annotation(is_operation_file=True) == "ET.Element":
|
|
116
|
+
file_import.add_submodule_import("typing", "List", ImportType.STDLIB, TypingSection.CONDITIONAL)
|
|
112
117
|
file_import.merge(self.element_type.imports())
|
|
113
118
|
return file_import
|
|
119
|
+
|
|
120
|
+
def model_file_imports(self) -> FileImport:
|
|
121
|
+
file_import = self.imports()
|
|
122
|
+
file_import.merge(self.element_type.model_file_imports())
|
|
123
|
+
return file_import
|
|
@@ -143,8 +143,8 @@ class LROOperation(Operation):
|
|
|
143
143
|
file_import.add_submodule_import(poller_import_path, poller, ImportType.AZURECORE, TypingSection.CONDITIONAL)
|
|
144
144
|
return file_import
|
|
145
145
|
|
|
146
|
-
def imports(self, async_mode: bool) -> FileImport:
|
|
147
|
-
file_import =
|
|
146
|
+
def imports(self, async_mode: bool, is_python3_file: bool) -> FileImport:
|
|
147
|
+
file_import = self._imports_base(async_mode, is_python3_file)
|
|
148
148
|
file_import.add_submodule_import("typing", "Union", ImportType.STDLIB, TypingSection.CONDITIONAL)
|
|
149
149
|
|
|
150
150
|
poller_import_path = ".".join(self.get_poller_path(async_mode).split(".")[:-1])
|
|
@@ -172,7 +172,7 @@ class LROOperation(Operation):
|
|
|
172
172
|
)
|
|
173
173
|
base_polling_method = self.get_base_polling_method(async_mode)
|
|
174
174
|
file_import.add_submodule_import(base_polling_method_import_path, base_polling_method, ImportType.AZURECORE)
|
|
175
|
-
|
|
175
|
+
file_import.add_submodule_import("typing", "cast", ImportType.STDLIB)
|
|
176
176
|
if async_mode:
|
|
177
177
|
file_import.add_submodule_import("typing", "Optional", ImportType.STDLIB, TypingSection.CONDITIONAL)
|
|
178
178
|
if self.code_model.options["tracing"] and self.want_tracing:
|
|
@@ -9,9 +9,9 @@ from .paging_operation import PagingOperation
|
|
|
9
9
|
|
|
10
10
|
class LROPagingOperation(PagingOperation, LROOperation):
|
|
11
11
|
|
|
12
|
-
def imports(self, async_mode: bool) -> FileImport:
|
|
13
|
-
lro_imports = LROOperation.imports(self, async_mode)
|
|
14
|
-
paging_imports = PagingOperation.imports(self, async_mode)
|
|
12
|
+
def imports(self, async_mode: bool, is_python3_file: bool) -> FileImport:
|
|
13
|
+
lro_imports = LROOperation.imports(self, async_mode, is_python3_file)
|
|
14
|
+
paging_imports = PagingOperation.imports(self, async_mode, is_python3_file)
|
|
15
15
|
|
|
16
16
|
file_import = lro_imports
|
|
17
17
|
file_import.merge(paging_imports)
|
|
@@ -39,13 +39,9 @@ class ObjectSchema(BaseSchema): # pylint: disable=too-many-instance-attributes
|
|
|
39
39
|
def serialization_type(self) -> str:
|
|
40
40
|
return self.name
|
|
41
41
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
return f'"{
|
|
45
|
-
|
|
46
|
-
@property
|
|
47
|
-
def operation_type_annotation(self) -> str:
|
|
48
|
-
return f'"_models.{self.name}"'
|
|
42
|
+
def type_annotation(self, *, is_operation_file: bool = False) -> str:
|
|
43
|
+
retval = f"_models.{self.name}"
|
|
44
|
+
return retval if is_operation_file else f'"{retval}"'
|
|
49
45
|
|
|
50
46
|
@property
|
|
51
47
|
def docstring_type(self) -> str:
|
|
@@ -216,31 +212,39 @@ class ObjectSchema(BaseSchema): # pylint: disable=too-many-instance-attributes
|
|
|
216
212
|
file_import.add_submodule_import("azure.core.exceptions", "HttpResponseError", ImportType.AZURECORE)
|
|
217
213
|
return file_import
|
|
218
214
|
|
|
215
|
+
def model_file_imports(self) -> FileImport:
|
|
216
|
+
file_import = self.imports()
|
|
217
|
+
file_import.add_import("__init__", ImportType.LOCAL, typing_section=TypingSection.TYPING, alias="_models")
|
|
218
|
+
return file_import
|
|
219
|
+
|
|
219
220
|
class HiddenModelObjectSchema(ObjectSchema):
|
|
220
221
|
|
|
221
222
|
@property
|
|
222
223
|
def serialization_type(self) -> str:
|
|
223
224
|
return "object"
|
|
224
225
|
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
@property
|
|
230
|
-
def operation_type_annotation(self) -> str:
|
|
226
|
+
def type_annotation(self, *, is_operation_file: bool = False) -> str: # pylint: disable=unused-argument
|
|
227
|
+
if self.xml_metadata:
|
|
228
|
+
return "ET.Element"
|
|
231
229
|
return "JSONType"
|
|
232
230
|
|
|
233
231
|
@property
|
|
234
232
|
def docstring_type(self) -> str:
|
|
233
|
+
if self.xml_metadata:
|
|
234
|
+
return "ET.Element"
|
|
235
235
|
return "JSONType"
|
|
236
236
|
|
|
237
237
|
@property
|
|
238
238
|
def docstring_text(self) -> str:
|
|
239
|
+
if self.xml_metadata:
|
|
240
|
+
return "XML Element"
|
|
239
241
|
return "JSON object"
|
|
240
242
|
|
|
241
243
|
def imports(self) -> FileImport:
|
|
242
244
|
file_import = FileImport()
|
|
243
245
|
file_import.add_submodule_import("typing", "Any", ImportType.STDLIB, TypingSection.CONDITIONAL)
|
|
246
|
+
if self.xml_metadata:
|
|
247
|
+
file_import.add_submodule_import("xml.etree", "ElementTree", ImportType.STDLIB, alias="ET")
|
|
244
248
|
return file_import
|
|
245
249
|
|
|
246
250
|
def get_object_schema(code_model) -> Type[ObjectSchema]:
|
|
@@ -10,7 +10,7 @@ from typing import cast, Dict, List, Any, Optional, Union, Set
|
|
|
10
10
|
from .base_builder import BaseBuilder, create_parameters
|
|
11
11
|
from .imports import FileImport, ImportType, TypingSection
|
|
12
12
|
from .schema_response import SchemaResponse
|
|
13
|
-
from .parameter import Parameter, get_parameter
|
|
13
|
+
from .parameter import Parameter, get_parameter, ParameterLocation
|
|
14
14
|
from .parameter_list import ParameterList, get_parameter_list
|
|
15
15
|
from .base_schema import BaseSchema
|
|
16
16
|
from .object_schema import ObjectSchema
|
|
@@ -159,7 +159,7 @@ class Operation(BaseBuilder): # pylint: disable=too-many-public-methods, too-ma
|
|
|
159
159
|
if response.has_body:
|
|
160
160
|
file_import.merge(cast(BaseSchema, response.schema).imports())
|
|
161
161
|
|
|
162
|
-
response_types = [r.
|
|
162
|
+
response_types = [r.type_annotation(is_operation_file=True) for r in self.responses if r.has_body]
|
|
163
163
|
if len(set(response_types)) > 1:
|
|
164
164
|
file_import.add_submodule_import("typing", "Union", ImportType.STDLIB, TypingSection.CONDITIONAL)
|
|
165
165
|
|
|
@@ -171,7 +171,17 @@ class Operation(BaseBuilder): # pylint: disable=too-many-public-methods, too-ma
|
|
|
171
171
|
def imports_for_multiapi(self, async_mode: bool) -> FileImport: # pylint: disable=unused-argument
|
|
172
172
|
return self._imports_shared(async_mode)
|
|
173
173
|
|
|
174
|
-
def imports(self, async_mode: bool) -> FileImport:
|
|
174
|
+
def imports(self, async_mode: bool, is_python3_file: bool) -> FileImport:
|
|
175
|
+
file_import = self._imports_base(async_mode, is_python3_file)
|
|
176
|
+
if self.has_response_body and not self.has_optional_return_type and not self.code_model.options["models_mode"]:
|
|
177
|
+
file_import.add_submodule_import("typing", "cast", ImportType.STDLIB)
|
|
178
|
+
return file_import
|
|
179
|
+
|
|
180
|
+
@staticmethod
|
|
181
|
+
def has_kwargs_to_pop_with_default(kwargs_to_pop: List[Parameter], location: ParameterLocation) -> bool:
|
|
182
|
+
return any(kwarg.has_default_value and kwarg.location == location for kwarg in kwargs_to_pop)
|
|
183
|
+
|
|
184
|
+
def _imports_base(self, async_mode: bool, is_python3_file: bool) -> FileImport:
|
|
175
185
|
file_import = self._imports_shared(async_mode)
|
|
176
186
|
|
|
177
187
|
# Exceptions
|
|
@@ -186,6 +196,10 @@ class Operation(BaseBuilder): # pylint: disable=too-many-public-methods, too-ma
|
|
|
186
196
|
file_import.add_submodule_import("typing", "TypeVar", ImportType.STDLIB, TypingSection.CONDITIONAL)
|
|
187
197
|
file_import.add_submodule_import("azure.core.pipeline", "PipelineResponse", ImportType.AZURECORE)
|
|
188
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)
|
|
189
203
|
if async_mode:
|
|
190
204
|
file_import.add_submodule_import("azure.core.pipeline.transport", "AsyncHttpResponse", ImportType.AZURECORE)
|
|
191
205
|
else:
|
|
@@ -218,6 +232,7 @@ class Operation(BaseBuilder): # pylint: disable=too-many-public-methods, too-ma
|
|
|
218
232
|
file_import.add_submodule_import(
|
|
219
233
|
f"{relative_path}_vendor", "_convert_request", ImportType.LOCAL
|
|
220
234
|
)
|
|
235
|
+
|
|
221
236
|
if self.code_model.options["version_tolerant"] and (
|
|
222
237
|
self.parameters.has_body or
|
|
223
238
|
any(r for r in self.responses if r.has_body)
|
|
@@ -267,7 +282,7 @@ class Operation(BaseBuilder): # pylint: disable=too-many-public-methods, too-ma
|
|
|
267
282
|
|
|
268
283
|
def convert_multiple_content_type_parameters(self) -> None:
|
|
269
284
|
type_annot = ", ".join([
|
|
270
|
-
param.schema.
|
|
285
|
+
param.schema.type_annotation(is_operation_file=True)
|
|
271
286
|
for param in self.multiple_content_type_parameters
|
|
272
287
|
])
|
|
273
288
|
docstring_type = " or ".join([
|
|
@@ -323,7 +338,13 @@ class Operation(BaseBuilder): # pylint: disable=too-many-public-methods, too-ma
|
|
|
323
338
|
multiple_content_type_parameters=multiple_content_type_parameter_list,
|
|
324
339
|
schema_requests=schema_requests,
|
|
325
340
|
summary=yaml_data["language"]["python"].get("summary"),
|
|
326
|
-
responses=[
|
|
341
|
+
responses=[
|
|
342
|
+
SchemaResponse.from_yaml(yaml, code_model=code_model)
|
|
343
|
+
for yaml in yaml_data.get("responses", [])
|
|
344
|
+
],
|
|
327
345
|
# Exception with no schema means default exception, we don't store them
|
|
328
|
-
exceptions=[
|
|
346
|
+
exceptions=[
|
|
347
|
+
SchemaResponse.from_yaml(yaml, code_model=code_model)
|
|
348
|
+
for yaml in yaml_data.get("exceptions", []) if "schema" in yaml
|
|
349
|
+
],
|
|
329
350
|
)
|
|
@@ -54,15 +54,16 @@ class OperationGroup(BaseModel):
|
|
|
54
54
|
file_import = FileImport()
|
|
55
55
|
for operation in self.operations:
|
|
56
56
|
file_import.merge(operation.imports_for_multiapi(async_mode))
|
|
57
|
+
file_import.add_submodule_import(".." if async_mode else ".", "models", ImportType.LOCAL, alias="_models")
|
|
57
58
|
return file_import
|
|
58
59
|
|
|
59
|
-
def imports(self, async_mode: bool) -> FileImport:
|
|
60
|
+
def imports(self, async_mode: bool, is_python3_file: bool) -> FileImport:
|
|
60
61
|
file_import = FileImport()
|
|
61
62
|
file_import.add_submodule_import("azure.core.exceptions", "ClientAuthenticationError", ImportType.AZURECORE)
|
|
62
63
|
file_import.add_submodule_import("azure.core.exceptions", "ResourceNotFoundError", ImportType.AZURECORE)
|
|
63
64
|
file_import.add_submodule_import("azure.core.exceptions", "ResourceExistsError", ImportType.AZURECORE)
|
|
64
65
|
for operation in self.operations:
|
|
65
|
-
file_import.merge(operation.imports(async_mode))
|
|
66
|
+
file_import.merge(operation.imports(async_mode, is_python3_file))
|
|
66
67
|
local_path = "..." if async_mode else ".."
|
|
67
68
|
if self.code_model.has_schemas and self.code_model.options["models_mode"]:
|
|
68
69
|
file_import.add_submodule_import(local_path, "models", ImportType.LOCAL, alias="_models")
|
|
@@ -84,6 +85,10 @@ class OperationGroup(BaseModel):
|
|
|
84
85
|
request_builder.name,
|
|
85
86
|
import_type=ImportType.LOCAL
|
|
86
87
|
)
|
|
88
|
+
if self.code_model.need_mixin_abc:
|
|
89
|
+
file_import.add_submodule_import(
|
|
90
|
+
".._vendor", "MixinABC", ImportType.LOCAL
|
|
91
|
+
)
|
|
87
92
|
type_value = "Optional[Callable[[PipelineResponse[HttpRequest, {}HttpResponse], T, Dict[str, Any]], Any]]"
|
|
88
93
|
file_import.define_mypy_type(
|
|
89
94
|
"ClsType",
|
|
@@ -66,7 +66,7 @@ class PagingOperation(Operation):
|
|
|
66
66
|
return response
|
|
67
67
|
|
|
68
68
|
def _find_python_name(self, rest_api_name: str, log_name: str) -> str:
|
|
69
|
-
response = self.
|
|
69
|
+
response = self.responses[0]
|
|
70
70
|
response_schema = cast(ObjectSchema, response.schema)
|
|
71
71
|
if response_schema:
|
|
72
72
|
for prop in response_schema.properties:
|
|
@@ -145,8 +145,8 @@ class PagingOperation(Operation):
|
|
|
145
145
|
|
|
146
146
|
return file_import
|
|
147
147
|
|
|
148
|
-
def imports(self, async_mode: bool) -> FileImport:
|
|
149
|
-
file_import =
|
|
148
|
+
def imports(self, async_mode: bool, is_python3_file: bool) -> FileImport:
|
|
149
|
+
file_import = self._imports_base(async_mode, is_python3_file)
|
|
150
150
|
# operation adds an import for distributed_trace_async, we don't want it
|
|
151
151
|
file_import.imports = [i for i in file_import.imports if not i.submodule_name == "distributed_trace_async"]
|
|
152
152
|
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
import logging
|
|
7
7
|
from enum import Enum
|
|
8
8
|
|
|
9
|
-
from typing import Dict, Optional, List, Any, Union, Tuple, cast
|
|
9
|
+
from typing import Dict, Optional, List, Any, Union, Tuple, cast, TYPE_CHECKING
|
|
10
10
|
|
|
11
11
|
from .imports import FileImport, ImportType, TypingSection
|
|
12
12
|
from .base_model import BaseModel
|
|
@@ -15,6 +15,10 @@ from .constant_schema import ConstantSchema
|
|
|
15
15
|
from .object_schema import ObjectSchema
|
|
16
16
|
from .property import Property
|
|
17
17
|
from .primitive_schemas import IOSchema
|
|
18
|
+
from .utils import get_schema
|
|
19
|
+
|
|
20
|
+
if TYPE_CHECKING:
|
|
21
|
+
from .code_model import CodeModel
|
|
18
22
|
|
|
19
23
|
|
|
20
24
|
_LOGGER = logging.getLogger(__name__)
|
|
@@ -46,6 +50,15 @@ class ParameterStyle(Enum):
|
|
|
46
50
|
multipart = "multipart"
|
|
47
51
|
|
|
48
52
|
|
|
53
|
+
|
|
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
|
+
|
|
49
62
|
class Parameter(BaseModel): # pylint: disable=too-many-instance-attributes, too-many-public-methods
|
|
50
63
|
def __init__(
|
|
51
64
|
self,
|
|
@@ -99,7 +112,7 @@ class Parameter(BaseModel): # pylint: disable=too-many-instance-attributes, too
|
|
|
99
112
|
self.body_kwargs: List[Parameter] = []
|
|
100
113
|
self.is_body_kwarg = False
|
|
101
114
|
self.need_import = True
|
|
102
|
-
self.is_kwarg = (self.rest_api_name == "Content-Type" or (self.constant and self.
|
|
115
|
+
self.is_kwarg = (self.rest_api_name == "Content-Type" or (self.constant and self.inputtable_by_user))
|
|
103
116
|
|
|
104
117
|
def __hash__(self) -> int:
|
|
105
118
|
return hash(self.serialized_name)
|
|
@@ -115,7 +128,7 @@ class Parameter(BaseModel): # pylint: disable=too-many-instance-attributes, too
|
|
|
115
128
|
if isinstance(self.schema, ConstantSchema) and not self.constant:
|
|
116
129
|
if description:
|
|
117
130
|
description += " "
|
|
118
|
-
description += f"
|
|
131
|
+
description += f"Known values are {self.schema.get_declaration(self.schema.value)} or {None}."
|
|
119
132
|
if self.has_default_value and not any(
|
|
120
133
|
l for l in ["default value is", "default is"] if l in description.lower()
|
|
121
134
|
):
|
|
@@ -175,6 +188,10 @@ class Parameter(BaseModel): # pylint: disable=too-many-instance-attributes, too
|
|
|
175
188
|
def is_body(self) -> bool:
|
|
176
189
|
return self.location == ParameterLocation.Body
|
|
177
190
|
|
|
191
|
+
@property
|
|
192
|
+
def inputtable_by_user(self) -> bool:
|
|
193
|
+
return self.rest_api_name != "Accept"
|
|
194
|
+
|
|
178
195
|
@property
|
|
179
196
|
def pre_semicolon_content_types(self) -> List[str]:
|
|
180
197
|
"""Splits on semicolon of media types and returns the first half.
|
|
@@ -185,8 +202,8 @@ class Parameter(BaseModel): # pylint: disable=too-many-instance-attributes, too
|
|
|
185
202
|
@property
|
|
186
203
|
def in_method_signature(self) -> bool:
|
|
187
204
|
return not(
|
|
188
|
-
# don't put
|
|
189
|
-
self.
|
|
205
|
+
# if not inputtable, don't put in signature
|
|
206
|
+
not self.inputtable_by_user
|
|
190
207
|
# If i'm not in the method code, no point in being in signature
|
|
191
208
|
or not self.in_method_code
|
|
192
209
|
# If I'm grouped, my grouper will be on signature, not me
|
|
@@ -225,7 +242,7 @@ class Parameter(BaseModel): # pylint: disable=too-many-instance-attributes, too
|
|
|
225
242
|
) and isinstance(self.schema, IOSchema)
|
|
226
243
|
|
|
227
244
|
def _default_value(self) -> Tuple[Optional[Any], str, str]:
|
|
228
|
-
type_annot = self.multiple_content_types_type_annot or self.schema.
|
|
245
|
+
type_annot = self.multiple_content_types_type_annot or self.schema.type_annotation(is_operation_file=True)
|
|
229
246
|
if self._is_io_json:
|
|
230
247
|
type_annot = f"Union[{type_annot}, JSONType]"
|
|
231
248
|
any_types = ["Any", "JSONType"]
|
|
@@ -277,8 +294,7 @@ class Parameter(BaseModel): # pylint: disable=too-many-instance-attributes, too
|
|
|
277
294
|
def default_value_declaration(self) -> Optional[Any]:
|
|
278
295
|
return self._default_value()[1]
|
|
279
296
|
|
|
280
|
-
|
|
281
|
-
def type_annotation(self) -> str:
|
|
297
|
+
def type_annotation(self, *, is_operation_file: bool = False) -> str: # pylint: disable=unused-argument
|
|
282
298
|
return self._default_value()[2]
|
|
283
299
|
|
|
284
300
|
@property
|
|
@@ -297,13 +313,14 @@ class Parameter(BaseModel): # pylint: disable=too-many-instance-attributes, too
|
|
|
297
313
|
return self.default_value is not None or not self.required
|
|
298
314
|
|
|
299
315
|
def method_signature(self, is_python3_file: bool) -> str:
|
|
316
|
+
type_annot = self.type_annotation(is_operation_file=True)
|
|
300
317
|
if is_python3_file:
|
|
301
318
|
if self.has_default_value:
|
|
302
|
-
return f"{self.serialized_name}: {
|
|
303
|
-
return f"{self.serialized_name}: {
|
|
319
|
+
return f"{self.serialized_name}: {type_annot} = {self.default_value_declaration},"
|
|
320
|
+
return f"{self.serialized_name}: {type_annot},"
|
|
304
321
|
if self.has_default_value:
|
|
305
|
-
return f"{self.serialized_name}={self.default_value_declaration}, # type: {
|
|
306
|
-
return f"{self.serialized_name}, # type: {
|
|
322
|
+
return f"{self.serialized_name}={self.default_value_declaration}, # type: {type_annot}"
|
|
323
|
+
return f"{self.serialized_name}, # type: {type_annot}"
|
|
307
324
|
|
|
308
325
|
@property
|
|
309
326
|
def full_serialized_name(self) -> str:
|
|
@@ -345,22 +362,29 @@ class Parameter(BaseModel): # pylint: disable=too-many-instance-attributes, too
|
|
|
345
362
|
content_types: Optional[List[str]] = None
|
|
346
363
|
) -> "Parameter":
|
|
347
364
|
http_protocol = yaml_data["protocol"].get("http", {"in": ParameterLocation.Other})
|
|
365
|
+
serialized_name = yaml_data["language"]["python"]["name"]
|
|
366
|
+
schema = get_schema(
|
|
367
|
+
code_model, yaml_data.get("schema"), serialized_name
|
|
368
|
+
)
|
|
369
|
+
target_property = yaml_data.get("targetProperty")
|
|
370
|
+
target_property_name = get_target_property_name(code_model, id(target_property)) if target_property else None
|
|
371
|
+
|
|
348
372
|
return cls(
|
|
349
373
|
code_model=code_model,
|
|
350
374
|
yaml_data=yaml_data,
|
|
351
|
-
schema=
|
|
375
|
+
schema=schema, # FIXME replace by operation model
|
|
352
376
|
# See also https://github.com/Azure/autorest.modelerfour/issues/80
|
|
353
377
|
rest_api_name=yaml_data["language"]["default"].get(
|
|
354
378
|
"serializedName", yaml_data["language"]["default"]["name"]
|
|
355
379
|
),
|
|
356
|
-
serialized_name=
|
|
380
|
+
serialized_name=serialized_name,
|
|
357
381
|
description=yaml_data["language"]["python"]["description"],
|
|
358
382
|
implementation=yaml_data["implementation"],
|
|
359
383
|
required=yaml_data.get("required", False),
|
|
360
384
|
location=ParameterLocation(http_protocol["in"]),
|
|
361
385
|
skip_url_encoding=yaml_data.get("extensions", {}).get("x-ms-skip-url-encoding", False),
|
|
362
386
|
constraints=[], # FIXME constraints
|
|
363
|
-
target_property_name=
|
|
387
|
+
target_property_name=target_property_name,
|
|
364
388
|
style=ParameterStyle(http_protocol["style"]) if "style" in http_protocol else None,
|
|
365
389
|
explode=http_protocol.get("explode", False),
|
|
366
390
|
grouped_by=yaml_data.get("groupedBy", None),
|
|
@@ -405,7 +405,7 @@ class GlobalParameterList(ParameterList):
|
|
|
405
405
|
credential_parameter = Parameter(
|
|
406
406
|
self.code_model,
|
|
407
407
|
yaml_data={},
|
|
408
|
-
schema=self.code_model.credential_schema_policy.credential,
|
|
408
|
+
schema=self.code_model.credential_model.credential_schema_policy.credential,
|
|
409
409
|
serialized_name="credential",
|
|
410
410
|
rest_api_name="credential",
|
|
411
411
|
implementation="Client",
|